Update ASIO to 1.30.2

This commit is contained in:
aMannus
2025-05-08 19:48:40 +02:00
parent 85e9ce7ed1
commit c109e5c2da
625 changed files with 84940 additions and 18081 deletions

View File

@@ -278,7 +278,6 @@ endif()
# apclientpp + dependencies # apclientpp + dependencies
################################################################################ ################################################################################
add_compile_definitions(ASIO_STANDALONE) add_compile_definitions(ASIO_STANDALONE)
add_compile_definitions(ASIO_DISABLE_STD_INVOKE_RESULT)
# TEMPORARY # TEMPORARY
add_compile_definitions(WSWRAP_NO_SSL) add_compile_definitions(WSWRAP_NO_SSL)

View File

@@ -1,4 +1,4 @@
Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
Distributed under the Boost Software License, Version 1.0. (See accompanying 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) file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -0,0 +1,626 @@
# find . -name "*.*pp" | sed -e 's/^\.\///' | sed -e 's/^.*$/ & \\/' | sort
nobase_include_HEADERS = \
asio/any_completion_executor.hpp \
asio/any_completion_handler.hpp \
asio/any_io_executor.hpp \
asio/append.hpp \
asio/as_tuple.hpp \
asio/associated_allocator.hpp \
asio/associated_cancellation_slot.hpp \
asio/associated_executor.hpp \
asio/associated_immediate_executor.hpp \
asio/associator.hpp \
asio/async_result.hpp \
asio/awaitable.hpp \
asio/basic_datagram_socket.hpp \
asio/basic_deadline_timer.hpp \
asio/basic_file.hpp \
asio/basic_io_object.hpp \
asio/basic_random_access_file.hpp \
asio/basic_raw_socket.hpp \
asio/basic_readable_pipe.hpp \
asio/basic_seq_packet_socket.hpp \
asio/basic_serial_port.hpp \
asio/basic_signal_set.hpp \
asio/basic_socket_acceptor.hpp \
asio/basic_socket.hpp \
asio/basic_socket_iostream.hpp \
asio/basic_socket_streambuf.hpp \
asio/basic_streambuf_fwd.hpp \
asio/basic_streambuf.hpp \
asio/basic_stream_file.hpp \
asio/basic_stream_socket.hpp \
asio/basic_waitable_timer.hpp \
asio/basic_writable_pipe.hpp \
asio/bind_allocator.hpp \
asio/bind_cancellation_slot.hpp \
asio/bind_executor.hpp \
asio/bind_immediate_executor.hpp \
asio/buffered_read_stream_fwd.hpp \
asio/buffered_read_stream.hpp \
asio/buffered_stream_fwd.hpp \
asio/buffered_stream.hpp \
asio/buffered_write_stream_fwd.hpp \
asio/buffered_write_stream.hpp \
asio/buffer.hpp \
asio/buffer_registration.hpp \
asio/buffers_iterator.hpp \
asio/cancellation_signal.hpp \
asio/cancellation_state.hpp \
asio/cancellation_type.hpp \
asio/co_spawn.hpp \
asio/completion_condition.hpp \
asio/compose.hpp \
asio/connect.hpp \
asio/connect_pipe.hpp \
asio/consign.hpp \
asio/coroutine.hpp \
asio/deadline_timer.hpp \
asio/defer.hpp \
asio/deferred.hpp \
asio/detached.hpp \
asio/detail/array_fwd.hpp \
asio/detail/array.hpp \
asio/detail/assert.hpp \
asio/detail/atomic_count.hpp \
asio/detail/base_from_cancellation_state.hpp \
asio/detail/base_from_completion_cond.hpp \
asio/detail/bind_handler.hpp \
asio/detail/blocking_executor_op.hpp \
asio/detail/buffered_stream_storage.hpp \
asio/detail/buffer_resize_guard.hpp \
asio/detail/buffer_sequence_adapter.hpp \
asio/detail/call_stack.hpp \
asio/detail/chrono.hpp \
asio/detail/chrono_time_traits.hpp \
asio/detail/completion_handler.hpp \
asio/detail/composed_work.hpp \
asio/detail/concurrency_hint.hpp \
asio/detail/conditionally_enabled_event.hpp \
asio/detail/conditionally_enabled_mutex.hpp \
asio/detail/config.hpp \
asio/detail/consuming_buffers.hpp \
asio/detail/cstddef.hpp \
asio/detail/cstdint.hpp \
asio/detail/date_time_fwd.hpp \
asio/detail/deadline_timer_service.hpp \
asio/detail/dependent_type.hpp \
asio/detail/descriptor_ops.hpp \
asio/detail/descriptor_read_op.hpp \
asio/detail/descriptor_write_op.hpp \
asio/detail/dev_poll_reactor.hpp \
asio/detail/epoll_reactor.hpp \
asio/detail/eventfd_select_interrupter.hpp \
asio/detail/event.hpp \
asio/detail/exception.hpp \
asio/detail/executor_function.hpp \
asio/detail/executor_op.hpp \
asio/detail/fd_set_adapter.hpp \
asio/detail/fenced_block.hpp \
asio/detail/functional.hpp \
asio/detail/future.hpp \
asio/detail/global.hpp \
asio/detail/handler_alloc_helpers.hpp \
asio/detail/handler_cont_helpers.hpp \
asio/detail/handler_tracking.hpp \
asio/detail/handler_type_requirements.hpp \
asio/detail/handler_work.hpp \
asio/detail/hash_map.hpp \
asio/detail/impl/buffer_sequence_adapter.ipp \
asio/detail/impl/descriptor_ops.ipp \
asio/detail/impl/dev_poll_reactor.hpp \
asio/detail/impl/dev_poll_reactor.ipp \
asio/detail/impl/epoll_reactor.hpp \
asio/detail/impl/epoll_reactor.ipp \
asio/detail/impl/eventfd_select_interrupter.ipp \
asio/detail/impl/handler_tracking.ipp \
asio/detail/impl/io_uring_descriptor_service.ipp \
asio/detail/impl/io_uring_file_service.ipp \
asio/detail/impl/io_uring_service.hpp \
asio/detail/impl/io_uring_service.ipp \
asio/detail/impl/io_uring_socket_service_base.ipp \
asio/detail/impl/kqueue_reactor.hpp \
asio/detail/impl/kqueue_reactor.ipp \
asio/detail/impl/null_event.ipp \
asio/detail/impl/pipe_select_interrupter.ipp \
asio/detail/impl/posix_event.ipp \
asio/detail/impl/posix_mutex.ipp \
asio/detail/impl/posix_serial_port_service.ipp \
asio/detail/impl/posix_thread.ipp \
asio/detail/impl/posix_tss_ptr.ipp \
asio/detail/impl/reactive_descriptor_service.ipp \
asio/detail/impl/reactive_socket_service_base.ipp \
asio/detail/impl/resolver_service_base.ipp \
asio/detail/impl/scheduler.ipp \
asio/detail/impl/select_reactor.hpp \
asio/detail/impl/select_reactor.ipp \
asio/detail/impl/service_registry.hpp \
asio/detail/impl/service_registry.ipp \
asio/detail/impl/signal_set_service.ipp \
asio/detail/impl/socket_ops.ipp \
asio/detail/impl/socket_select_interrupter.ipp \
asio/detail/impl/strand_executor_service.hpp \
asio/detail/impl/strand_executor_service.ipp \
asio/detail/impl/strand_service.hpp \
asio/detail/impl/strand_service.ipp \
asio/detail/impl/thread_context.ipp \
asio/detail/impl/throw_error.ipp \
asio/detail/impl/timer_queue_ptime.ipp \
asio/detail/impl/timer_queue_set.ipp \
asio/detail/impl/win_event.ipp \
asio/detail/impl/win_iocp_file_service.ipp \
asio/detail/impl/win_iocp_handle_service.ipp \
asio/detail/impl/win_iocp_io_context.hpp \
asio/detail/impl/win_iocp_io_context.ipp \
asio/detail/impl/win_iocp_serial_port_service.ipp \
asio/detail/impl/win_iocp_socket_service_base.ipp \
asio/detail/impl/win_mutex.ipp \
asio/detail/impl/win_object_handle_service.ipp \
asio/detail/impl/winrt_ssocket_service_base.ipp \
asio/detail/impl/winrt_timer_scheduler.hpp \
asio/detail/impl/winrt_timer_scheduler.ipp \
asio/detail/impl/winsock_init.ipp \
asio/detail/impl/win_static_mutex.ipp \
asio/detail/impl/win_thread.ipp \
asio/detail/impl/win_tss_ptr.ipp \
asio/detail/initiate_defer.hpp \
asio/detail/initiate_dispatch.hpp \
asio/detail/initiate_post.hpp \
asio/detail/io_control.hpp \
asio/detail/io_object_impl.hpp \
asio/detail/io_uring_descriptor_read_at_op.hpp \
asio/detail/io_uring_descriptor_read_op.hpp \
asio/detail/io_uring_descriptor_service.hpp \
asio/detail/io_uring_descriptor_write_at_op.hpp \
asio/detail/io_uring_descriptor_write_op.hpp \
asio/detail/io_uring_file_service.hpp \
asio/detail/io_uring_null_buffers_op.hpp \
asio/detail/io_uring_operation.hpp \
asio/detail/io_uring_service.hpp \
asio/detail/io_uring_socket_accept_op.hpp \
asio/detail/io_uring_socket_connect_op.hpp \
asio/detail/io_uring_socket_recvfrom_op.hpp \
asio/detail/io_uring_socket_recvmsg_op.hpp \
asio/detail/io_uring_socket_recv_op.hpp \
asio/detail/io_uring_socket_send_op.hpp \
asio/detail/io_uring_socket_sendto_op.hpp \
asio/detail/io_uring_socket_service_base.hpp \
asio/detail/io_uring_socket_service.hpp \
asio/detail/io_uring_wait_op.hpp \
asio/detail/is_buffer_sequence.hpp \
asio/detail/is_executor.hpp \
asio/detail/keyword_tss_ptr.hpp \
asio/detail/kqueue_reactor.hpp \
asio/detail/limits.hpp \
asio/detail/local_free_on_block_exit.hpp \
asio/detail/memory.hpp \
asio/detail/mutex.hpp \
asio/detail/non_const_lvalue.hpp \
asio/detail/noncopyable.hpp \
asio/detail/null_event.hpp \
asio/detail/null_fenced_block.hpp \
asio/detail/null_global.hpp \
asio/detail/null_mutex.hpp \
asio/detail/null_reactor.hpp \
asio/detail/null_signal_blocker.hpp \
asio/detail/null_socket_service.hpp \
asio/detail/null_static_mutex.hpp \
asio/detail/null_thread.hpp \
asio/detail/null_tss_ptr.hpp \
asio/detail/object_pool.hpp \
asio/detail/old_win_sdk_compat.hpp \
asio/detail/operation.hpp \
asio/detail/op_queue.hpp \
asio/detail/pipe_select_interrupter.hpp \
asio/detail/pop_options.hpp \
asio/detail/posix_event.hpp \
asio/detail/posix_fd_set_adapter.hpp \
asio/detail/posix_global.hpp \
asio/detail/posix_mutex.hpp \
asio/detail/posix_serial_port_service.hpp \
asio/detail/posix_signal_blocker.hpp \
asio/detail/posix_static_mutex.hpp \
asio/detail/posix_thread.hpp \
asio/detail/posix_tss_ptr.hpp \
asio/detail/push_options.hpp \
asio/detail/reactive_descriptor_service.hpp \
asio/detail/reactive_null_buffers_op.hpp \
asio/detail/reactive_socket_accept_op.hpp \
asio/detail/reactive_socket_connect_op.hpp \
asio/detail/reactive_socket_recvfrom_op.hpp \
asio/detail/reactive_socket_recvmsg_op.hpp \
asio/detail/reactive_socket_recv_op.hpp \
asio/detail/reactive_socket_send_op.hpp \
asio/detail/reactive_socket_sendto_op.hpp \
asio/detail/reactive_socket_service_base.hpp \
asio/detail/reactive_socket_service.hpp \
asio/detail/reactive_wait_op.hpp \
asio/detail/reactor.hpp \
asio/detail/reactor_op.hpp \
asio/detail/reactor_op_queue.hpp \
asio/detail/recycling_allocator.hpp \
asio/detail/regex_fwd.hpp \
asio/detail/resolve_endpoint_op.hpp \
asio/detail/resolve_op.hpp \
asio/detail/resolve_query_op.hpp \
asio/detail/resolver_service_base.hpp \
asio/detail/resolver_service.hpp \
asio/detail/scheduler.hpp \
asio/detail/scheduler_operation.hpp \
asio/detail/scheduler_task.hpp \
asio/detail/scheduler_thread_info.hpp \
asio/detail/scoped_lock.hpp \
asio/detail/scoped_ptr.hpp \
asio/detail/select_interrupter.hpp \
asio/detail/select_reactor.hpp \
asio/detail/service_registry.hpp \
asio/detail/signal_blocker.hpp \
asio/detail/signal_handler.hpp \
asio/detail/signal_init.hpp \
asio/detail/signal_op.hpp \
asio/detail/signal_set_service.hpp \
asio/detail/socket_holder.hpp \
asio/detail/socket_ops.hpp \
asio/detail/socket_option.hpp \
asio/detail/socket_select_interrupter.hpp \
asio/detail/socket_types.hpp \
asio/detail/source_location.hpp \
asio/detail/static_mutex.hpp \
asio/detail/std_event.hpp \
asio/detail/std_fenced_block.hpp \
asio/detail/std_global.hpp \
asio/detail/std_mutex.hpp \
asio/detail/std_static_mutex.hpp \
asio/detail/std_thread.hpp \
asio/detail/strand_executor_service.hpp \
asio/detail/strand_service.hpp \
asio/detail/string_view.hpp \
asio/detail/thread_context.hpp \
asio/detail/thread_group.hpp \
asio/detail/thread.hpp \
asio/detail/thread_info_base.hpp \
asio/detail/throw_error.hpp \
asio/detail/throw_exception.hpp \
asio/detail/timer_queue_base.hpp \
asio/detail/timer_queue.hpp \
asio/detail/timer_queue_ptime.hpp \
asio/detail/timer_queue_set.hpp \
asio/detail/timer_scheduler_fwd.hpp \
asio/detail/timer_scheduler.hpp \
asio/detail/tss_ptr.hpp \
asio/detail/type_traits.hpp \
asio/detail/utility.hpp \
asio/detail/wait_handler.hpp \
asio/detail/wait_op.hpp \
asio/detail/winapp_thread.hpp \
asio/detail/wince_thread.hpp \
asio/detail/win_event.hpp \
asio/detail/win_fd_set_adapter.hpp \
asio/detail/win_global.hpp \
asio/detail/win_iocp_file_service.hpp \
asio/detail/win_iocp_handle_read_op.hpp \
asio/detail/win_iocp_handle_service.hpp \
asio/detail/win_iocp_handle_write_op.hpp \
asio/detail/win_iocp_io_context.hpp \
asio/detail/win_iocp_null_buffers_op.hpp \
asio/detail/win_iocp_operation.hpp \
asio/detail/win_iocp_overlapped_op.hpp \
asio/detail/win_iocp_overlapped_ptr.hpp \
asio/detail/win_iocp_serial_port_service.hpp \
asio/detail/win_iocp_socket_accept_op.hpp \
asio/detail/win_iocp_socket_connect_op.hpp \
asio/detail/win_iocp_socket_recvfrom_op.hpp \
asio/detail/win_iocp_socket_recvmsg_op.hpp \
asio/detail/win_iocp_socket_recv_op.hpp \
asio/detail/win_iocp_socket_send_op.hpp \
asio/detail/win_iocp_socket_service_base.hpp \
asio/detail/win_iocp_socket_service.hpp \
asio/detail/win_iocp_thread_info.hpp \
asio/detail/win_iocp_wait_op.hpp \
asio/detail/win_mutex.hpp \
asio/detail/win_object_handle_service.hpp \
asio/detail/winrt_async_manager.hpp \
asio/detail/winrt_async_op.hpp \
asio/detail/winrt_resolve_op.hpp \
asio/detail/winrt_resolver_service.hpp \
asio/detail/winrt_socket_connect_op.hpp \
asio/detail/winrt_socket_recv_op.hpp \
asio/detail/winrt_socket_send_op.hpp \
asio/detail/winrt_ssocket_service_base.hpp \
asio/detail/winrt_ssocket_service.hpp \
asio/detail/winrt_timer_scheduler.hpp \
asio/detail/winrt_utils.hpp \
asio/detail/winsock_init.hpp \
asio/detail/win_static_mutex.hpp \
asio/detail/win_thread.hpp \
asio/detail/win_tss_ptr.hpp \
asio/detail/work_dispatcher.hpp \
asio/detail/wrapped_handler.hpp \
asio/dispatch.hpp \
asio/error_code.hpp \
asio/error.hpp \
asio/execution.hpp \
asio/execution_context.hpp \
asio/execution/allocator.hpp \
asio/execution/any_executor.hpp \
asio/execution/bad_executor.hpp \
asio/execution/blocking.hpp \
asio/execution/blocking_adaptation.hpp \
asio/execution/context.hpp \
asio/execution/context_as.hpp \
asio/execution/executor.hpp \
asio/execution/impl/bad_executor.ipp \
asio/execution/invocable_archetype.hpp \
asio/execution/mapping.hpp \
asio/execution/occupancy.hpp \
asio/execution/outstanding_work.hpp \
asio/execution/prefer_only.hpp \
asio/execution/relationship.hpp \
asio/executor.hpp \
asio/executor_work_guard.hpp \
asio/experimental/append.hpp \
asio/experimental/as_single.hpp \
asio/experimental/as_tuple.hpp \
asio/experimental/awaitable_operators.hpp \
asio/experimental/basic_channel.hpp \
asio/experimental/basic_concurrent_channel.hpp \
asio/experimental/cancellation_condition.hpp \
asio/experimental/channel.hpp \
asio/experimental/channel_error.hpp \
asio/experimental/channel_traits.hpp \
asio/experimental/co_composed.hpp \
asio/experimental/co_spawn.hpp \
asio/experimental/concurrent_channel.hpp \
asio/experimental/coro.hpp \
asio/experimental/coro_traits.hpp \
asio/experimental/deferred.hpp \
asio/experimental/detail/channel_handler.hpp \
asio/experimental/detail/channel_message.hpp \
asio/experimental/detail/channel_operation.hpp \
asio/experimental/detail/channel_payload.hpp \
asio/experimental/detail/channel_receive_op.hpp \
asio/experimental/detail/channel_send_functions.hpp \
asio/experimental/detail/channel_send_op.hpp \
asio/experimental/detail/channel_service.hpp \
asio/experimental/detail/coro_completion_handler.hpp \
asio/experimental/detail/coro_promise_allocator.hpp \
asio/experimental/detail/has_signature.hpp \
asio/experimental/detail/impl/channel_service.hpp \
asio/experimental/detail/partial_promise.hpp \
asio/experimental/impl/as_single.hpp \
asio/experimental/impl/channel_error.ipp \
asio/experimental/impl/co_composed.hpp \
asio/experimental/impl/coro.hpp \
asio/experimental/impl/parallel_group.hpp \
asio/experimental/impl/promise.hpp \
asio/experimental/impl/use_coro.hpp \
asio/experimental/impl/use_promise.hpp \
asio/experimental/parallel_group.hpp \
asio/experimental/prepend.hpp \
asio/experimental/promise.hpp \
asio/experimental/use_coro.hpp \
asio/experimental/use_promise.hpp \
asio/file_base.hpp \
asio/generic/basic_endpoint.hpp \
asio/generic/datagram_protocol.hpp \
asio/generic/detail/endpoint.hpp \
asio/generic/detail/impl/endpoint.ipp \
asio/generic/raw_protocol.hpp \
asio/generic/seq_packet_protocol.hpp \
asio/generic/stream_protocol.hpp \
asio/handler_continuation_hook.hpp \
asio/high_resolution_timer.hpp \
asio.hpp \
asio/impl/any_completion_executor.ipp \
asio/impl/any_io_executor.ipp \
asio/impl/append.hpp \
asio/impl/as_tuple.hpp \
asio/impl/awaitable.hpp \
asio/impl/buffered_read_stream.hpp \
asio/impl/buffered_write_stream.hpp \
asio/impl/cancellation_signal.ipp \
asio/impl/co_spawn.hpp \
asio/impl/connect.hpp \
asio/impl/connect_pipe.hpp \
asio/impl/connect_pipe.ipp \
asio/impl/consign.hpp \
asio/impl/deferred.hpp \
asio/impl/detached.hpp \
asio/impl/error_code.ipp \
asio/impl/error.ipp \
asio/impl/execution_context.hpp \
asio/impl/execution_context.ipp \
asio/impl/executor.hpp \
asio/impl/executor.ipp \
asio/impl/io_context.hpp \
asio/impl/io_context.ipp \
asio/impl/multiple_exceptions.ipp \
asio/impl/prepend.hpp \
asio/impl/read_at.hpp \
asio/impl/read.hpp \
asio/impl/read_until.hpp \
asio/impl/redirect_error.hpp \
asio/impl/serial_port_base.hpp \
asio/impl/serial_port_base.ipp \
asio/impl/spawn.hpp \
asio/impl/src.hpp \
asio/impl/system_context.hpp \
asio/impl/system_context.ipp \
asio/impl/system_executor.hpp \
asio/impl/thread_pool.hpp \
asio/impl/thread_pool.ipp \
asio/impl/use_awaitable.hpp \
asio/impl/use_future.hpp \
asio/impl/write_at.hpp \
asio/impl/write.hpp \
asio/io_context.hpp \
asio/io_context_strand.hpp \
asio/io_service.hpp \
asio/io_service_strand.hpp \
asio/ip/address.hpp \
asio/ip/address_v4.hpp \
asio/ip/address_v4_iterator.hpp \
asio/ip/address_v4_range.hpp \
asio/ip/address_v6.hpp \
asio/ip/address_v6_iterator.hpp \
asio/ip/address_v6_range.hpp \
asio/ip/bad_address_cast.hpp \
asio/ip/basic_endpoint.hpp \
asio/ip/basic_resolver_entry.hpp \
asio/ip/basic_resolver.hpp \
asio/ip/basic_resolver_iterator.hpp \
asio/ip/basic_resolver_query.hpp \
asio/ip/basic_resolver_results.hpp \
asio/ip/detail/endpoint.hpp \
asio/ip/detail/impl/endpoint.ipp \
asio/ip/detail/socket_option.hpp \
asio/ip/host_name.hpp \
asio/ip/icmp.hpp \
asio/ip/impl/address.hpp \
asio/ip/impl/address.ipp \
asio/ip/impl/address_v4.hpp \
asio/ip/impl/address_v4.ipp \
asio/ip/impl/address_v6.hpp \
asio/ip/impl/address_v6.ipp \
asio/ip/impl/basic_endpoint.hpp \
asio/ip/impl/host_name.ipp \
asio/ip/impl/network_v4.hpp \
asio/ip/impl/network_v4.ipp \
asio/ip/impl/network_v6.hpp \
asio/ip/impl/network_v6.ipp \
asio/ip/multicast.hpp \
asio/ip/network_v4.hpp \
asio/ip/network_v6.hpp \
asio/ip/resolver_base.hpp \
asio/ip/resolver_query_base.hpp \
asio/ip/tcp.hpp \
asio/ip/udp.hpp \
asio/ip/unicast.hpp \
asio/ip/v6_only.hpp \
asio/is_applicable_property.hpp \
asio/is_contiguous_iterator.hpp \
asio/is_executor.hpp \
asio/is_read_buffered.hpp \
asio/is_write_buffered.hpp \
asio/local/basic_endpoint.hpp \
asio/local/connect_pair.hpp \
asio/local/datagram_protocol.hpp \
asio/local/detail/endpoint.hpp \
asio/local/detail/impl/endpoint.ipp \
asio/local/seq_packet_protocol.hpp \
asio/local/stream_protocol.hpp \
asio/multiple_exceptions.hpp \
asio/packaged_task.hpp \
asio/placeholders.hpp \
asio/posix/basic_descriptor.hpp \
asio/posix/basic_stream_descriptor.hpp \
asio/posix/descriptor_base.hpp \
asio/posix/descriptor.hpp \
asio/posix/stream_descriptor.hpp \
asio/post.hpp \
asio/prefer.hpp \
asio/prepend.hpp \
asio/query.hpp \
asio/random_access_file.hpp \
asio/read_at.hpp \
asio/read.hpp \
asio/read_until.hpp \
asio/readable_pipe.hpp \
asio/recycling_allocator.hpp \
asio/redirect_error.hpp \
asio/registered_buffer.hpp \
asio/require.hpp \
asio/require_concept.hpp \
asio/serial_port_base.hpp \
asio/serial_port.hpp \
asio/signal_set_base.hpp \
asio/signal_set.hpp \
asio/socket_base.hpp \
asio/spawn.hpp \
asio/ssl/context_base.hpp \
asio/ssl/context.hpp \
asio/ssl/detail/buffered_handshake_op.hpp \
asio/ssl/detail/engine.hpp \
asio/ssl/detail/handshake_op.hpp \
asio/ssl/detail/impl/engine.ipp \
asio/ssl/detail/impl/openssl_init.ipp \
asio/ssl/detail/io.hpp \
asio/ssl/detail/openssl_init.hpp \
asio/ssl/detail/openssl_types.hpp \
asio/ssl/detail/password_callback.hpp \
asio/ssl/detail/read_op.hpp \
asio/ssl/detail/shutdown_op.hpp \
asio/ssl/detail/stream_core.hpp \
asio/ssl/detail/verify_callback.hpp \
asio/ssl/detail/write_op.hpp \
asio/ssl/error.hpp \
asio/ssl.hpp \
asio/ssl/host_name_verification.hpp \
asio/ssl/impl/context.hpp \
asio/ssl/impl/context.ipp \
asio/ssl/impl/error.ipp \
asio/ssl/impl/host_name_verification.ipp \
asio/ssl/impl/rfc2818_verification.ipp \
asio/ssl/impl/src.hpp \
asio/ssl/rfc2818_verification.hpp \
asio/ssl/stream_base.hpp \
asio/ssl/stream.hpp \
asio/ssl/verify_context.hpp \
asio/ssl/verify_mode.hpp \
asio/static_thread_pool.hpp \
asio/steady_timer.hpp \
asio/strand.hpp \
asio/streambuf.hpp \
asio/stream_file.hpp \
asio/system_context.hpp \
asio/system_error.hpp \
asio/system_executor.hpp \
asio/system_timer.hpp \
asio/this_coro.hpp \
asio/thread.hpp \
asio/thread_pool.hpp \
asio/time_traits.hpp \
asio/traits/equality_comparable.hpp \
asio/traits/execute_member.hpp \
asio/traits/prefer_free.hpp \
asio/traits/prefer_member.hpp \
asio/traits/query_free.hpp \
asio/traits/query_member.hpp \
asio/traits/query_static_constexpr_member.hpp \
asio/traits/require_concept_free.hpp \
asio/traits/require_concept_member.hpp \
asio/traits/require_free.hpp \
asio/traits/require_member.hpp \
asio/traits/static_query.hpp \
asio/traits/static_require.hpp \
asio/traits/static_require_concept.hpp \
asio/ts/buffer.hpp \
asio/ts/executor.hpp \
asio/ts/internet.hpp \
asio/ts/io_context.hpp \
asio/ts/netfwd.hpp \
asio/ts/net.hpp \
asio/ts/socket.hpp \
asio/ts/timer.hpp \
asio/unyield.hpp \
asio/use_awaitable.hpp \
asio/use_future.hpp \
asio/uses_executor.hpp \
asio/version.hpp \
asio/wait_traits.hpp \
asio/windows/basic_object_handle.hpp \
asio/windows/basic_overlapped_handle.hpp \
asio/windows/basic_random_access_handle.hpp \
asio/windows/basic_stream_handle.hpp \
asio/windows/object_handle.hpp \
asio/windows/overlapped_handle.hpp \
asio/windows/overlapped_ptr.hpp \
asio/windows/random_access_handle.hpp \
asio/windows/stream_handle.hpp \
asio/writable_pipe.hpp \
asio/write_at.hpp \
asio/write.hpp \
asio/yield.hpp
MAINTAINERCLEANFILES = \
$(srcdir)/Makefile.in

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// asio.hpp // asio.hpp
// ~~~~~~~~ // ~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,24 +15,43 @@
# pragma once # pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/any_completion_executor.hpp"
#include "asio/any_completion_handler.hpp"
#include "asio/any_io_executor.hpp"
#include "asio/append.hpp"
#include "asio/as_tuple.hpp"
#include "asio/associated_allocator.hpp" #include "asio/associated_allocator.hpp"
#include "asio/associated_cancellation_slot.hpp"
#include "asio/associated_executor.hpp" #include "asio/associated_executor.hpp"
#include "asio/associated_immediate_executor.hpp"
#include "asio/associator.hpp"
#include "asio/async_result.hpp" #include "asio/async_result.hpp"
#include "asio/awaitable.hpp"
#include "asio/basic_datagram_socket.hpp" #include "asio/basic_datagram_socket.hpp"
#include "asio/basic_deadline_timer.hpp" #include "asio/basic_deadline_timer.hpp"
#include "asio/basic_file.hpp"
#include "asio/basic_io_object.hpp" #include "asio/basic_io_object.hpp"
#include "asio/basic_random_access_file.hpp"
#include "asio/basic_raw_socket.hpp" #include "asio/basic_raw_socket.hpp"
#include "asio/basic_readable_pipe.hpp"
#include "asio/basic_seq_packet_socket.hpp" #include "asio/basic_seq_packet_socket.hpp"
#include "asio/basic_serial_port.hpp" #include "asio/basic_serial_port.hpp"
#include "asio/basic_signal_set.hpp" #include "asio/basic_signal_set.hpp"
#include "asio/basic_socket.hpp"
#include "asio/basic_socket_acceptor.hpp" #include "asio/basic_socket_acceptor.hpp"
#include "asio/basic_socket_iostream.hpp" #include "asio/basic_socket_iostream.hpp"
#include "asio/basic_socket_streambuf.hpp" #include "asio/basic_socket_streambuf.hpp"
#include "asio/basic_stream_file.hpp"
#include "asio/basic_stream_socket.hpp" #include "asio/basic_stream_socket.hpp"
#include "asio/basic_streambuf.hpp" #include "asio/basic_streambuf.hpp"
#include "asio/basic_waitable_timer.hpp" #include "asio/basic_waitable_timer.hpp"
#include "asio/basic_writable_pipe.hpp"
#include "asio/bind_allocator.hpp"
#include "asio/bind_cancellation_slot.hpp"
#include "asio/bind_executor.hpp" #include "asio/bind_executor.hpp"
#include "asio/bind_immediate_executor.hpp"
#include "asio/buffer.hpp" #include "asio/buffer.hpp"
#include "asio/buffer_registration.hpp"
#include "asio/buffered_read_stream_fwd.hpp" #include "asio/buffered_read_stream_fwd.hpp"
#include "asio/buffered_read_stream.hpp" #include "asio/buffered_read_stream.hpp"
#include "asio/buffered_stream_fwd.hpp" #include "asio/buffered_stream_fwd.hpp"
@@ -40,28 +59,46 @@
#include "asio/buffered_write_stream_fwd.hpp" #include "asio/buffered_write_stream_fwd.hpp"
#include "asio/buffered_write_stream.hpp" #include "asio/buffered_write_stream.hpp"
#include "asio/buffers_iterator.hpp" #include "asio/buffers_iterator.hpp"
#include "asio/cancellation_signal.hpp"
#include "asio/cancellation_state.hpp"
#include "asio/cancellation_type.hpp"
#include "asio/co_spawn.hpp"
#include "asio/completion_condition.hpp" #include "asio/completion_condition.hpp"
#include "asio/compose.hpp"
#include "asio/connect.hpp" #include "asio/connect.hpp"
#include "asio/connect_pipe.hpp"
#include "asio/consign.hpp"
#include "asio/coroutine.hpp" #include "asio/coroutine.hpp"
#include "asio/datagram_socket_service.hpp"
#include "asio/deadline_timer_service.hpp"
#include "asio/deadline_timer.hpp" #include "asio/deadline_timer.hpp"
#include "asio/defer.hpp" #include "asio/defer.hpp"
#include "asio/deferred.hpp"
#include "asio/detached.hpp"
#include "asio/dispatch.hpp" #include "asio/dispatch.hpp"
#include "asio/error.hpp" #include "asio/error.hpp"
#include "asio/error_code.hpp" #include "asio/error_code.hpp"
#include "asio/execution_context.hpp" #include "asio/execution.hpp"
#include "asio/execution/allocator.hpp"
#include "asio/execution/any_executor.hpp"
#include "asio/execution/blocking.hpp"
#include "asio/execution/blocking_adaptation.hpp"
#include "asio/execution/context.hpp"
#include "asio/execution/context_as.hpp"
#include "asio/execution/executor.hpp"
#include "asio/execution/invocable_archetype.hpp"
#include "asio/execution/mapping.hpp"
#include "asio/execution/occupancy.hpp"
#include "asio/execution/outstanding_work.hpp"
#include "asio/execution/prefer_only.hpp"
#include "asio/execution/relationship.hpp"
#include "asio/executor.hpp" #include "asio/executor.hpp"
#include "asio/executor_work_guard.hpp" #include "asio/executor_work_guard.hpp"
#include "asio/file_base.hpp"
#include "asio/generic/basic_endpoint.hpp" #include "asio/generic/basic_endpoint.hpp"
#include "asio/generic/datagram_protocol.hpp" #include "asio/generic/datagram_protocol.hpp"
#include "asio/generic/raw_protocol.hpp" #include "asio/generic/raw_protocol.hpp"
#include "asio/generic/seq_packet_protocol.hpp" #include "asio/generic/seq_packet_protocol.hpp"
#include "asio/generic/stream_protocol.hpp" #include "asio/generic/stream_protocol.hpp"
#include "asio/handler_alloc_hook.hpp"
#include "asio/handler_continuation_hook.hpp" #include "asio/handler_continuation_hook.hpp"
#include "asio/handler_invoke_hook.hpp"
#include "asio/handler_type.hpp"
#include "asio/high_resolution_timer.hpp" #include "asio/high_resolution_timer.hpp"
#include "asio/io_context.hpp" #include "asio/io_context.hpp"
#include "asio/io_context_strand.hpp" #include "asio/io_context_strand.hpp"
@@ -74,6 +111,8 @@
#include "asio/ip/address_v6.hpp" #include "asio/ip/address_v6.hpp"
#include "asio/ip/address_v6_iterator.hpp" #include "asio/ip/address_v6_iterator.hpp"
#include "asio/ip/address_v6_range.hpp" #include "asio/ip/address_v6_range.hpp"
#include "asio/ip/network_v4.hpp"
#include "asio/ip/network_v6.hpp"
#include "asio/ip/bad_address_cast.hpp" #include "asio/ip/bad_address_cast.hpp"
#include "asio/ip/basic_endpoint.hpp" #include "asio/ip/basic_endpoint.hpp"
#include "asio/ip/basic_resolver.hpp" #include "asio/ip/basic_resolver.hpp"
@@ -85,18 +124,21 @@
#include "asio/ip/multicast.hpp" #include "asio/ip/multicast.hpp"
#include "asio/ip/resolver_base.hpp" #include "asio/ip/resolver_base.hpp"
#include "asio/ip/resolver_query_base.hpp" #include "asio/ip/resolver_query_base.hpp"
#include "asio/ip/resolver_service.hpp"
#include "asio/ip/tcp.hpp" #include "asio/ip/tcp.hpp"
#include "asio/ip/udp.hpp" #include "asio/ip/udp.hpp"
#include "asio/ip/unicast.hpp" #include "asio/ip/unicast.hpp"
#include "asio/ip/v6_only.hpp" #include "asio/ip/v6_only.hpp"
#include "asio/is_applicable_property.hpp"
#include "asio/is_contiguous_iterator.hpp"
#include "asio/is_executor.hpp" #include "asio/is_executor.hpp"
#include "asio/is_read_buffered.hpp" #include "asio/is_read_buffered.hpp"
#include "asio/is_write_buffered.hpp" #include "asio/is_write_buffered.hpp"
#include "asio/local/basic_endpoint.hpp" #include "asio/local/basic_endpoint.hpp"
#include "asio/local/connect_pair.hpp" #include "asio/local/connect_pair.hpp"
#include "asio/local/datagram_protocol.hpp" #include "asio/local/datagram_protocol.hpp"
#include "asio/local/seq_packet_protocol.hpp"
#include "asio/local/stream_protocol.hpp" #include "asio/local/stream_protocol.hpp"
#include "asio/multiple_exceptions.hpp"
#include "asio/packaged_task.hpp" #include "asio/packaged_task.hpp"
#include "asio/placeholders.hpp" #include "asio/placeholders.hpp"
#include "asio/posix/basic_descriptor.hpp" #include "asio/posix/basic_descriptor.hpp"
@@ -104,48 +146,53 @@
#include "asio/posix/descriptor.hpp" #include "asio/posix/descriptor.hpp"
#include "asio/posix/descriptor_base.hpp" #include "asio/posix/descriptor_base.hpp"
#include "asio/posix/stream_descriptor.hpp" #include "asio/posix/stream_descriptor.hpp"
#include "asio/posix/stream_descriptor_service.hpp"
#include "asio/post.hpp" #include "asio/post.hpp"
#include "asio/raw_socket_service.hpp" #include "asio/prefer.hpp"
#include "asio/prepend.hpp"
#include "asio/query.hpp"
#include "asio/random_access_file.hpp"
#include "asio/read.hpp" #include "asio/read.hpp"
#include "asio/read_at.hpp" #include "asio/read_at.hpp"
#include "asio/read_until.hpp" #include "asio/read_until.hpp"
#include "asio/seq_packet_socket_service.hpp" #include "asio/readable_pipe.hpp"
#include "asio/recycling_allocator.hpp"
#include "asio/redirect_error.hpp"
#include "asio/registered_buffer.hpp"
#include "asio/require.hpp"
#include "asio/require_concept.hpp"
#include "asio/serial_port.hpp" #include "asio/serial_port.hpp"
#include "asio/serial_port_base.hpp" #include "asio/serial_port_base.hpp"
#include "asio/serial_port_service.hpp"
#include "asio/signal_set.hpp" #include "asio/signal_set.hpp"
#include "asio/signal_set_service.hpp" #include "asio/signal_set_base.hpp"
#include "asio/socket_acceptor_service.hpp"
#include "asio/socket_base.hpp" #include "asio/socket_base.hpp"
#include "asio/static_thread_pool.hpp"
#include "asio/steady_timer.hpp" #include "asio/steady_timer.hpp"
#include "asio/strand.hpp" #include "asio/strand.hpp"
#include "asio/stream_socket_service.hpp" #include "asio/stream_file.hpp"
#include "asio/streambuf.hpp" #include "asio/streambuf.hpp"
#include "asio/system_context.hpp" #include "asio/system_context.hpp"
#include "asio/system_error.hpp" #include "asio/system_error.hpp"
#include "asio/system_executor.hpp" #include "asio/system_executor.hpp"
#include "asio/system_timer.hpp" #include "asio/system_timer.hpp"
#include "asio/this_coro.hpp"
#include "asio/thread.hpp" #include "asio/thread.hpp"
#include "asio/thread_pool.hpp" #include "asio/thread_pool.hpp"
#include "asio/time_traits.hpp" #include "asio/time_traits.hpp"
#include "asio/use_awaitable.hpp"
#include "asio/use_future.hpp" #include "asio/use_future.hpp"
#include "asio/uses_executor.hpp" #include "asio/uses_executor.hpp"
#include "asio/version.hpp" #include "asio/version.hpp"
#include "asio/wait_traits.hpp" #include "asio/wait_traits.hpp"
#include "asio/waitable_timer_service.hpp"
#include "asio/windows/basic_handle.hpp"
#include "asio/windows/basic_object_handle.hpp" #include "asio/windows/basic_object_handle.hpp"
#include "asio/windows/basic_overlapped_handle.hpp"
#include "asio/windows/basic_random_access_handle.hpp" #include "asio/windows/basic_random_access_handle.hpp"
#include "asio/windows/basic_stream_handle.hpp" #include "asio/windows/basic_stream_handle.hpp"
#include "asio/windows/object_handle.hpp" #include "asio/windows/object_handle.hpp"
#include "asio/windows/object_handle_service.hpp"
#include "asio/windows/overlapped_handle.hpp" #include "asio/windows/overlapped_handle.hpp"
#include "asio/windows/overlapped_ptr.hpp" #include "asio/windows/overlapped_ptr.hpp"
#include "asio/windows/random_access_handle.hpp" #include "asio/windows/random_access_handle.hpp"
#include "asio/windows/random_access_handle_service.hpp"
#include "asio/windows/stream_handle.hpp" #include "asio/windows/stream_handle.hpp"
#include "asio/windows/stream_handle_service.hpp" #include "asio/writable_pipe.hpp"
#include "asio/write.hpp" #include "asio/write.hpp"
#include "asio/write_at.hpp" #include "asio/write_at.hpp"

View File

@@ -0,0 +1,336 @@
//
// any_completion_executor.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 ASIO_ANY_COMPLETION_EXECUTOR_HPP
#define ASIO_ANY_COMPLETION_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include "asio/executor.hpp"
#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include "asio/execution.hpp"
#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
#include "asio/detail/push_options.hpp"
namespace asio {
#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
typedef executor any_completion_executor;
#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
/// Polymorphic executor type for use with I/O objects.
/**
* The @c any_completion_executor type is a polymorphic executor that supports
* the set of properties required for the execution of completion handlers. It
* is defined as the execution::any_executor class template parameterised as
* follows:
* @code execution::any_executor<
* execution::prefer_only<execution::outstanding_work_t::tracked_t>,
* execution::prefer_only<execution::outstanding_work_t::untracked_t>
* execution::prefer_only<execution::relationship_t::fork_t>,
* execution::prefer_only<execution::relationship_t::continuation_t>
* > @endcode
*/
class any_completion_executor :
#if defined(GENERATING_DOCUMENTATION)
public execution::any_executor<...>
#else // defined(GENERATING_DOCUMENTATION)
public execution::any_executor<
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
>
#endif // defined(GENERATING_DOCUMENTATION)
{
public:
#if !defined(GENERATING_DOCUMENTATION)
typedef execution::any_executor<
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
> base_type;
typedef void supportable_properties_type(
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
);
#endif // !defined(GENERATING_DOCUMENTATION)
/// Default constructor.
ASIO_DECL any_completion_executor() noexcept;
/// Construct in an empty state. Equivalent effects to default constructor.
ASIO_DECL any_completion_executor(nullptr_t) noexcept;
/// Copy constructor.
ASIO_DECL any_completion_executor(
const any_completion_executor& e) noexcept;
/// Move constructor.
ASIO_DECL any_completion_executor(
any_completion_executor&& e) noexcept;
/// Construct to point to the same target as another any_executor.
#if defined(GENERATING_DOCUMENTATION)
template <class... OtherSupportableProperties>
any_completion_executor(
execution::any_executor<OtherSupportableProperties...> e);
#else // defined(GENERATING_DOCUMENTATION)
template <typename OtherAnyExecutor>
any_completion_executor(OtherAnyExecutor e,
constraint_t<
conditional<
!is_same<OtherAnyExecutor, any_completion_executor>::value
&& is_base_of<execution::detail::any_executor_base,
OtherAnyExecutor>::value,
typename execution::detail::supportable_properties<
0, supportable_properties_type>::template
is_valid_target<OtherAnyExecutor>,
false_type
>::type::value
> = 0)
: base_type(static_cast<OtherAnyExecutor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct to point to the same target as another any_executor.
#if defined(GENERATING_DOCUMENTATION)
template <class... OtherSupportableProperties>
any_completion_executor(std::nothrow_t,
execution::any_executor<OtherSupportableProperties...> e);
#else // defined(GENERATING_DOCUMENTATION)
template <typename OtherAnyExecutor>
any_completion_executor(std::nothrow_t, OtherAnyExecutor e,
constraint_t<
conditional<
!is_same<OtherAnyExecutor, any_completion_executor>::value
&& is_base_of<execution::detail::any_executor_base,
OtherAnyExecutor>::value,
typename execution::detail::supportable_properties<
0, supportable_properties_type>::template
is_valid_target<OtherAnyExecutor>,
false_type
>::type::value
> = 0) noexcept
: base_type(std::nothrow, static_cast<OtherAnyExecutor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct to point to the same target as another any_executor.
ASIO_DECL any_completion_executor(std::nothrow_t,
const any_completion_executor& e) noexcept;
/// Construct to point to the same target as another any_executor.
ASIO_DECL any_completion_executor(std::nothrow_t,
any_completion_executor&& e) noexcept;
/// Construct a polymorphic wrapper for the specified executor.
#if defined(GENERATING_DOCUMENTATION)
template <ASIO_EXECUTION_EXECUTOR Executor>
any_completion_executor(Executor e);
#else // defined(GENERATING_DOCUMENTATION)
template <ASIO_EXECUTION_EXECUTOR Executor>
any_completion_executor(Executor e,
constraint_t<
conditional<
!is_same<Executor, any_completion_executor>::value
&& !is_base_of<execution::detail::any_executor_base,
Executor>::value,
execution::detail::is_valid_target_executor<
Executor, supportable_properties_type>,
false_type
>::type::value
> = 0)
: base_type(static_cast<Executor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct a polymorphic wrapper for the specified executor.
#if defined(GENERATING_DOCUMENTATION)
template <ASIO_EXECUTION_EXECUTOR Executor>
any_completion_executor(std::nothrow_t, Executor e);
#else // defined(GENERATING_DOCUMENTATION)
template <ASIO_EXECUTION_EXECUTOR Executor>
any_completion_executor(std::nothrow_t, Executor e,
constraint_t<
conditional<
!is_same<Executor, any_completion_executor>::value
&& !is_base_of<execution::detail::any_executor_base,
Executor>::value,
execution::detail::is_valid_target_executor<
Executor, supportable_properties_type>,
false_type
>::type::value
> = 0) noexcept
: base_type(std::nothrow, static_cast<Executor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Assignment operator.
ASIO_DECL any_completion_executor& operator=(
const any_completion_executor& e) noexcept;
/// Move assignment operator.
ASIO_DECL any_completion_executor& operator=(
any_completion_executor&& e) noexcept;
/// Assignment operator that sets the polymorphic wrapper to the empty state.
ASIO_DECL any_completion_executor& operator=(nullptr_t);
/// Destructor.
ASIO_DECL ~any_completion_executor();
/// Swap targets with another polymorphic wrapper.
ASIO_DECL void swap(any_completion_executor& other) noexcept;
/// Obtain a polymorphic wrapper with the specified property.
/**
* Do not call this function directly. It is intended for use with the
* asio::require and asio::prefer customisation points.
*
* For example:
* @code any_completion_executor ex = ...;
* auto ex2 = asio::require(ex, execution::relationship.fork); @endcode
*/
template <typename Property>
any_completion_executor require(const Property& p,
constraint_t<
traits::require_member<const base_type&, const Property&>::is_valid
> = 0) const
{
return static_cast<const base_type&>(*this).require(p);
}
/// Obtain a polymorphic wrapper with the specified property.
/**
* Do not call this function directly. It is intended for use with the
* asio::prefer customisation point.
*
* For example:
* @code any_completion_executor ex = ...;
* auto ex2 = asio::prefer(ex, execution::relationship.fork); @endcode
*/
template <typename Property>
any_completion_executor prefer(const Property& p,
constraint_t<
traits::prefer_member<const base_type&, const Property&>::is_valid
> = 0) const
{
return static_cast<const base_type&>(*this).prefer(p);
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <>
ASIO_DECL any_completion_executor any_completion_executor::prefer(
const execution::outstanding_work_t::tracked_t&, int) const;
template <>
ASIO_DECL any_completion_executor any_completion_executor::prefer(
const execution::outstanding_work_t::untracked_t&, int) const;
template <>
ASIO_DECL any_completion_executor any_completion_executor::prefer(
const execution::relationship_t::fork_t&, int) const;
template <>
ASIO_DECL any_completion_executor any_completion_executor::prefer(
const execution::relationship_t::continuation_t&, int) const;
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <>
struct equality_comparable<any_completion_executor>
{
static const bool is_valid = true;
static const bool is_noexcept = true;
};
#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
template <typename F>
struct execute_member<any_completion_executor, F>
{
static const bool is_valid = true;
static const bool is_noexcept = false;
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
template <typename Prop>
struct query_member<any_completion_executor, Prop> :
query_member<any_completion_executor::base_type, Prop>
{
};
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
template <typename Prop>
struct require_member<any_completion_executor, Prop> :
require_member<any_completion_executor::base_type, Prop>
{
typedef any_completion_executor result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
template <typename Prop>
struct prefer_member<any_completion_executor, Prop> :
prefer_member<any_completion_executor::base_type, Prop>
{
typedef any_completion_executor result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
} // namespace traits
#endif // !defined(GENERATING_DOCUMENTATION)
#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#if defined(ASIO_HEADER_ONLY) \
&& !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include "asio/impl/any_completion_executor.ipp"
#endif // defined(ASIO_HEADER_ONLY)
// && !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
#endif // ASIO_ANY_COMPLETION_EXECUTOR_HPP

View File

@@ -0,0 +1,822 @@
//
// any_completion_handler.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 ASIO_ANY_COMPLETION_HANDLER_HPP
#define ASIO_ANY_COMPLETION_HANDLER_HPP
#include "asio/detail/config.hpp"
#include <cstring>
#include <functional>
#include <memory>
#include <utility>
#include "asio/any_completion_executor.hpp"
#include "asio/any_io_executor.hpp"
#include "asio/associated_allocator.hpp"
#include "asio/associated_cancellation_slot.hpp"
#include "asio/associated_executor.hpp"
#include "asio/associated_immediate_executor.hpp"
#include "asio/cancellation_state.hpp"
#include "asio/recycling_allocator.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class any_completion_handler_impl_base
{
public:
template <typename S>
explicit any_completion_handler_impl_base(S&& slot)
: cancel_state_(static_cast<S&&>(slot), enable_total_cancellation())
{
}
cancellation_slot get_cancellation_slot() const noexcept
{
return cancel_state_.slot();
}
private:
cancellation_state cancel_state_;
};
template <typename Handler>
class any_completion_handler_impl :
public any_completion_handler_impl_base
{
public:
template <typename S, typename H>
any_completion_handler_impl(S&& slot, H&& h)
: any_completion_handler_impl_base(static_cast<S&&>(slot)),
handler_(static_cast<H&&>(h))
{
}
struct uninit_deleter
{
typename std::allocator_traits<
associated_allocator_t<Handler,
asio::recycling_allocator<void>>>::template
rebind_alloc<any_completion_handler_impl> alloc;
void operator()(any_completion_handler_impl* ptr)
{
std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1);
}
};
struct deleter
{
typename std::allocator_traits<
associated_allocator_t<Handler,
asio::recycling_allocator<void>>>::template
rebind_alloc<any_completion_handler_impl> alloc;
void operator()(any_completion_handler_impl* ptr)
{
std::allocator_traits<decltype(alloc)>::destroy(alloc, ptr);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1);
}
};
template <typename S, typename H>
static any_completion_handler_impl* create(S&& slot, H&& h)
{
uninit_deleter d{
(get_associated_allocator)(h,
asio::recycling_allocator<void>())};
std::unique_ptr<any_completion_handler_impl, uninit_deleter> uninit_ptr(
std::allocator_traits<decltype(d.alloc)>::allocate(d.alloc, 1), d);
any_completion_handler_impl* ptr =
new (uninit_ptr.get()) any_completion_handler_impl(
static_cast<S&&>(slot), static_cast<H&&>(h));
uninit_ptr.release();
return ptr;
}
void destroy()
{
deleter d{
(get_associated_allocator)(handler_,
asio::recycling_allocator<void>())};
d(this);
}
any_completion_executor executor(
const any_completion_executor& candidate) const noexcept
{
return any_completion_executor(std::nothrow,
(get_associated_executor)(handler_, candidate));
}
any_completion_executor immediate_executor(
const any_io_executor& candidate) const noexcept
{
return any_completion_executor(std::nothrow,
(get_associated_immediate_executor)(handler_, candidate));
}
void* allocate(std::size_t size, std::size_t align) const
{
typename std::allocator_traits<
associated_allocator_t<Handler,
asio::recycling_allocator<void>>>::template
rebind_alloc<unsigned char> alloc(
(get_associated_allocator)(handler_,
asio::recycling_allocator<void>()));
std::size_t space = size + align - 1;
unsigned char* base =
std::allocator_traits<decltype(alloc)>::allocate(
alloc, space + sizeof(std::ptrdiff_t));
void* p = base;
if (detail::align(align, size, p, space))
{
std::ptrdiff_t off = static_cast<unsigned char*>(p) - base;
std::memcpy(static_cast<unsigned char*>(p) + size, &off, sizeof(off));
return p;
}
std::bad_alloc ex;
asio::detail::throw_exception(ex);
return nullptr;
}
void deallocate(void* p, std::size_t size, std::size_t align) const
{
if (p)
{
typename std::allocator_traits<
associated_allocator_t<Handler,
asio::recycling_allocator<void>>>::template
rebind_alloc<unsigned char> alloc(
(get_associated_allocator)(handler_,
asio::recycling_allocator<void>()));
std::ptrdiff_t off;
std::memcpy(&off, static_cast<unsigned char*>(p) + size, sizeof(off));
unsigned char* base = static_cast<unsigned char*>(p) - off;
std::allocator_traits<decltype(alloc)>::deallocate(
alloc, base, size + align -1 + sizeof(std::ptrdiff_t));
}
}
template <typename... Args>
void call(Args&&... args)
{
deleter d{
(get_associated_allocator)(handler_,
asio::recycling_allocator<void>())};
std::unique_ptr<any_completion_handler_impl, deleter> ptr(this, d);
Handler handler(static_cast<Handler&&>(handler_));
ptr.reset();
static_cast<Handler&&>(handler)(
static_cast<Args&&>(args)...);
}
private:
Handler handler_;
};
template <typename Signature>
class any_completion_handler_call_fn;
template <typename R, typename... Args>
class any_completion_handler_call_fn<R(Args...)>
{
public:
using type = void(*)(any_completion_handler_impl_base*, Args...);
constexpr any_completion_handler_call_fn(type fn)
: call_fn_(fn)
{
}
void call(any_completion_handler_impl_base* impl, Args... args) const
{
call_fn_(impl, static_cast<Args&&>(args)...);
}
template <typename Handler>
static void impl(any_completion_handler_impl_base* impl, Args... args)
{
static_cast<any_completion_handler_impl<Handler>*>(impl)->call(
static_cast<Args&&>(args)...);
}
private:
type call_fn_;
};
template <typename... Signatures>
class any_completion_handler_call_fns;
template <typename Signature>
class any_completion_handler_call_fns<Signature> :
public any_completion_handler_call_fn<Signature>
{
public:
using any_completion_handler_call_fn<
Signature>::any_completion_handler_call_fn;
using any_completion_handler_call_fn<Signature>::call;
};
template <typename Signature, typename... Signatures>
class any_completion_handler_call_fns<Signature, Signatures...> :
public any_completion_handler_call_fn<Signature>,
public any_completion_handler_call_fns<Signatures...>
{
public:
template <typename CallFn, typename... CallFns>
constexpr any_completion_handler_call_fns(CallFn fn, CallFns... fns)
: any_completion_handler_call_fn<Signature>(fn),
any_completion_handler_call_fns<Signatures...>(fns...)
{
}
using any_completion_handler_call_fn<Signature>::call;
using any_completion_handler_call_fns<Signatures...>::call;
};
class any_completion_handler_destroy_fn
{
public:
using type = void(*)(any_completion_handler_impl_base*);
constexpr any_completion_handler_destroy_fn(type fn)
: destroy_fn_(fn)
{
}
void destroy(any_completion_handler_impl_base* impl) const
{
destroy_fn_(impl);
}
template <typename Handler>
static void impl(any_completion_handler_impl_base* impl)
{
static_cast<any_completion_handler_impl<Handler>*>(impl)->destroy();
}
private:
type destroy_fn_;
};
class any_completion_handler_executor_fn
{
public:
using type = any_completion_executor(*)(
any_completion_handler_impl_base*, const any_completion_executor&);
constexpr any_completion_handler_executor_fn(type fn)
: executor_fn_(fn)
{
}
any_completion_executor executor(any_completion_handler_impl_base* impl,
const any_completion_executor& candidate) const
{
return executor_fn_(impl, candidate);
}
template <typename Handler>
static any_completion_executor impl(any_completion_handler_impl_base* impl,
const any_completion_executor& candidate)
{
return static_cast<any_completion_handler_impl<Handler>*>(impl)->executor(
candidate);
}
private:
type executor_fn_;
};
class any_completion_handler_immediate_executor_fn
{
public:
using type = any_completion_executor(*)(
any_completion_handler_impl_base*, const any_io_executor&);
constexpr any_completion_handler_immediate_executor_fn(type fn)
: immediate_executor_fn_(fn)
{
}
any_completion_executor immediate_executor(
any_completion_handler_impl_base* impl,
const any_io_executor& candidate) const
{
return immediate_executor_fn_(impl, candidate);
}
template <typename Handler>
static any_completion_executor impl(any_completion_handler_impl_base* impl,
const any_io_executor& candidate)
{
return static_cast<any_completion_handler_impl<Handler>*>(
impl)->immediate_executor(candidate);
}
private:
type immediate_executor_fn_;
};
class any_completion_handler_allocate_fn
{
public:
using type = void*(*)(any_completion_handler_impl_base*,
std::size_t, std::size_t);
constexpr any_completion_handler_allocate_fn(type fn)
: allocate_fn_(fn)
{
}
void* allocate(any_completion_handler_impl_base* impl,
std::size_t size, std::size_t align) const
{
return allocate_fn_(impl, size, align);
}
template <typename Handler>
static void* impl(any_completion_handler_impl_base* impl,
std::size_t size, std::size_t align)
{
return static_cast<any_completion_handler_impl<Handler>*>(impl)->allocate(
size, align);
}
private:
type allocate_fn_;
};
class any_completion_handler_deallocate_fn
{
public:
using type = void(*)(any_completion_handler_impl_base*,
void*, std::size_t, std::size_t);
constexpr any_completion_handler_deallocate_fn(type fn)
: deallocate_fn_(fn)
{
}
void deallocate(any_completion_handler_impl_base* impl,
void* p, std::size_t size, std::size_t align) const
{
deallocate_fn_(impl, p, size, align);
}
template <typename Handler>
static void impl(any_completion_handler_impl_base* impl,
void* p, std::size_t size, std::size_t align)
{
static_cast<any_completion_handler_impl<Handler>*>(impl)->deallocate(
p, size, align);
}
private:
type deallocate_fn_;
};
template <typename... Signatures>
class any_completion_handler_fn_table
: private any_completion_handler_destroy_fn,
private any_completion_handler_executor_fn,
private any_completion_handler_immediate_executor_fn,
private any_completion_handler_allocate_fn,
private any_completion_handler_deallocate_fn,
private any_completion_handler_call_fns<Signatures...>
{
public:
template <typename... CallFns>
constexpr any_completion_handler_fn_table(
any_completion_handler_destroy_fn::type destroy_fn,
any_completion_handler_executor_fn::type executor_fn,
any_completion_handler_immediate_executor_fn::type immediate_executor_fn,
any_completion_handler_allocate_fn::type allocate_fn,
any_completion_handler_deallocate_fn::type deallocate_fn,
CallFns... call_fns)
: any_completion_handler_destroy_fn(destroy_fn),
any_completion_handler_executor_fn(executor_fn),
any_completion_handler_immediate_executor_fn(immediate_executor_fn),
any_completion_handler_allocate_fn(allocate_fn),
any_completion_handler_deallocate_fn(deallocate_fn),
any_completion_handler_call_fns<Signatures...>(call_fns...)
{
}
using any_completion_handler_destroy_fn::destroy;
using any_completion_handler_executor_fn::executor;
using any_completion_handler_immediate_executor_fn::immediate_executor;
using any_completion_handler_allocate_fn::allocate;
using any_completion_handler_deallocate_fn::deallocate;
using any_completion_handler_call_fns<Signatures...>::call;
};
template <typename Handler, typename... Signatures>
struct any_completion_handler_fn_table_instance
{
static constexpr any_completion_handler_fn_table<Signatures...>
value = any_completion_handler_fn_table<Signatures...>(
&any_completion_handler_destroy_fn::impl<Handler>,
&any_completion_handler_executor_fn::impl<Handler>,
&any_completion_handler_immediate_executor_fn::impl<Handler>,
&any_completion_handler_allocate_fn::impl<Handler>,
&any_completion_handler_deallocate_fn::impl<Handler>,
&any_completion_handler_call_fn<Signatures>::template impl<Handler>...);
};
template <typename Handler, typename... Signatures>
constexpr any_completion_handler_fn_table<Signatures...>
any_completion_handler_fn_table_instance<Handler, Signatures...>::value;
} // namespace detail
template <typename... Signatures>
class any_completion_handler;
/// An allocator type that forwards memory allocation operations through an
/// instance of @c any_completion_handler.
template <typename T, typename... Signatures>
class any_completion_handler_allocator
{
private:
template <typename...>
friend class any_completion_handler;
template <typename, typename...>
friend class any_completion_handler_allocator;
const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
detail::any_completion_handler_impl_base* impl_;
constexpr any_completion_handler_allocator(int,
const any_completion_handler<Signatures...>& h) noexcept
: fn_table_(h.fn_table_),
impl_(h.impl_)
{
}
public:
/// The type of objects that may be allocated by the allocator.
typedef T value_type;
/// Rebinds an allocator to another value type.
template <typename U>
struct rebind
{
/// Specifies the type of the rebound allocator.
typedef any_completion_handler_allocator<U, Signatures...> other;
};
/// Construct from another @c any_completion_handler_allocator.
template <typename U>
constexpr any_completion_handler_allocator(
const any_completion_handler_allocator<U, Signatures...>& a)
noexcept
: fn_table_(a.fn_table_),
impl_(a.impl_)
{
}
/// Equality operator.
constexpr bool operator==(
const any_completion_handler_allocator& other) const noexcept
{
return fn_table_ == other.fn_table_ && impl_ == other.impl_;
}
/// Inequality operator.
constexpr bool operator!=(
const any_completion_handler_allocator& other) const noexcept
{
return fn_table_ != other.fn_table_ || impl_ != other.impl_;
}
/// Allocate space for @c n objects of the allocator's value type.
T* allocate(std::size_t n) const
{
if (fn_table_)
{
return static_cast<T*>(
fn_table_->allocate(
impl_, sizeof(T) * n, alignof(T)));
}
std::bad_alloc ex;
asio::detail::throw_exception(ex);
return nullptr;
}
/// Deallocate space for @c n objects of the allocator's value type.
void deallocate(T* p, std::size_t n) const
{
fn_table_->deallocate(impl_, p, sizeof(T) * n, alignof(T));
}
};
/// A protoco-allocator type that may be rebound to obtain an allocator that
/// forwards memory allocation operations through an instance of
/// @c any_completion_handler.
template <typename... Signatures>
class any_completion_handler_allocator<void, Signatures...>
{
private:
template <typename...>
friend class any_completion_handler;
template <typename, typename...>
friend class any_completion_handler_allocator;
const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
detail::any_completion_handler_impl_base* impl_;
constexpr any_completion_handler_allocator(int,
const any_completion_handler<Signatures...>& h) noexcept
: fn_table_(h.fn_table_),
impl_(h.impl_)
{
}
public:
/// @c void as no objects can be allocated through a proto-allocator.
typedef void value_type;
/// Rebinds an allocator to another value type.
template <typename U>
struct rebind
{
/// Specifies the type of the rebound allocator.
typedef any_completion_handler_allocator<U, Signatures...> other;
};
/// Construct from another @c any_completion_handler_allocator.
template <typename U>
constexpr any_completion_handler_allocator(
const any_completion_handler_allocator<U, Signatures...>& a)
noexcept
: fn_table_(a.fn_table_),
impl_(a.impl_)
{
}
/// Equality operator.
constexpr bool operator==(
const any_completion_handler_allocator& other) const noexcept
{
return fn_table_ == other.fn_table_ && impl_ == other.impl_;
}
/// Inequality operator.
constexpr bool operator!=(
const any_completion_handler_allocator& other) const noexcept
{
return fn_table_ != other.fn_table_ || impl_ != other.impl_;
}
};
/// Polymorphic wrapper for completion handlers.
/**
* The @c any_completion_handler class template is a polymorphic wrapper for
* completion handlers that propagates the associated executor, associated
* allocator, and associated cancellation slot through a type-erasing interface.
*
* When using @c any_completion_handler, specify one or more completion
* signatures as template parameters. These will dictate the arguments that may
* be passed to the handler through the polymorphic interface.
*
* Typical uses for @c any_completion_handler include:
*
* @li Separate compilation of asynchronous operation implementations.
*
* @li Enabling interoperability between asynchronous operations and virtual
* functions.
*/
template <typename... Signatures>
class any_completion_handler
{
#if !defined(GENERATING_DOCUMENTATION)
private:
template <typename, typename...>
friend class any_completion_handler_allocator;
template <typename, typename>
friend struct associated_executor;
template <typename, typename>
friend struct associated_immediate_executor;
const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
detail::any_completion_handler_impl_base* impl_;
#endif // !defined(GENERATING_DOCUMENTATION)
public:
/// The associated allocator type.
using allocator_type = any_completion_handler_allocator<void, Signatures...>;
/// The associated cancellation slot type.
using cancellation_slot_type = cancellation_slot;
/// Construct an @c any_completion_handler in an empty state, without a target
/// object.
constexpr any_completion_handler()
: fn_table_(nullptr),
impl_(nullptr)
{
}
/// Construct an @c any_completion_handler in an empty state, without a target
/// object.
constexpr any_completion_handler(nullptr_t)
: fn_table_(nullptr),
impl_(nullptr)
{
}
/// Construct an @c any_completion_handler to contain the specified target.
template <typename H, typename Handler = decay_t<H>>
any_completion_handler(H&& h,
constraint_t<
!is_same<decay_t<H>, any_completion_handler>::value
> = 0)
: fn_table_(
&detail::any_completion_handler_fn_table_instance<
Handler, Signatures...>::value),
impl_(detail::any_completion_handler_impl<Handler>::create(
(get_associated_cancellation_slot)(h), static_cast<H&&>(h)))
{
}
/// Move-construct an @c any_completion_handler from another.
/**
* After the operation, the moved-from object @c other has no target.
*/
any_completion_handler(any_completion_handler&& other) noexcept
: fn_table_(other.fn_table_),
impl_(other.impl_)
{
other.fn_table_ = nullptr;
other.impl_ = nullptr;
}
/// Move-assign an @c any_completion_handler from another.
/**
* After the operation, the moved-from object @c other has no target.
*/
any_completion_handler& operator=(
any_completion_handler&& other) noexcept
{
any_completion_handler(
static_cast<any_completion_handler&&>(other)).swap(*this);
return *this;
}
/// Assignment operator that sets the polymorphic wrapper to the empty state.
any_completion_handler& operator=(nullptr_t) noexcept
{
any_completion_handler().swap(*this);
return *this;
}
/// Destructor.
~any_completion_handler()
{
if (impl_)
fn_table_->destroy(impl_);
}
/// Test if the polymorphic wrapper is empty.
constexpr explicit operator bool() const noexcept
{
return impl_ != nullptr;
}
/// Test if the polymorphic wrapper is non-empty.
constexpr bool operator!() const noexcept
{
return impl_ == nullptr;
}
/// Swap the content of an @c any_completion_handler with another.
void swap(any_completion_handler& other) noexcept
{
std::swap(fn_table_, other.fn_table_);
std::swap(impl_, other.impl_);
}
/// Get the associated allocator.
allocator_type get_allocator() const noexcept
{
return allocator_type(0, *this);
}
/// Get the associated cancellation slot.
cancellation_slot_type get_cancellation_slot() const noexcept
{
return impl_ ? impl_->get_cancellation_slot() : cancellation_slot_type();
}
/// Function call operator.
/**
* Invokes target completion handler with the supplied arguments.
*
* This function may only be called once, as the target handler is moved from.
* The polymorphic wrapper is left in an empty state.
*
* Throws @c std::bad_function_call if the polymorphic wrapper is empty.
*/
template <typename... Args>
auto operator()(Args&&... args)
-> decltype(fn_table_->call(impl_, static_cast<Args&&>(args)...))
{
if (detail::any_completion_handler_impl_base* impl = impl_)
{
impl_ = nullptr;
return fn_table_->call(impl, static_cast<Args&&>(args)...);
}
std::bad_function_call ex;
asio::detail::throw_exception(ex);
}
/// Equality operator.
friend constexpr bool operator==(
const any_completion_handler& a, nullptr_t) noexcept
{
return a.impl_ == nullptr;
}
/// Equality operator.
friend constexpr bool operator==(
nullptr_t, const any_completion_handler& b) noexcept
{
return nullptr == b.impl_;
}
/// Inequality operator.
friend constexpr bool operator!=(
const any_completion_handler& a, nullptr_t) noexcept
{
return a.impl_ != nullptr;
}
/// Inequality operator.
friend constexpr bool operator!=(
nullptr_t, const any_completion_handler& b) noexcept
{
return nullptr != b.impl_;
}
};
template <typename... Signatures, typename Candidate>
struct associated_executor<any_completion_handler<Signatures...>, Candidate>
{
using type = any_completion_executor;
static type get(const any_completion_handler<Signatures...>& handler,
const Candidate& candidate = Candidate()) noexcept
{
any_completion_executor any_candidate(std::nothrow, candidate);
return handler.fn_table_
? handler.fn_table_->executor(handler.impl_, any_candidate)
: any_candidate;
}
};
template <typename... Signatures, typename Candidate>
struct associated_immediate_executor<
any_completion_handler<Signatures...>, Candidate>
{
using type = any_completion_executor;
static type get(const any_completion_handler<Signatures...>& handler,
const Candidate& candidate = Candidate()) noexcept
{
any_io_executor any_candidate(std::nothrow, candidate);
return handler.fn_table_
? handler.fn_table_->immediate_executor(handler.impl_, any_candidate)
: any_candidate;
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_ANY_COMPLETION_HANDLER_HPP

View File

@@ -0,0 +1,351 @@
//
// any_io_executor.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 ASIO_ANY_IO_EXECUTOR_HPP
#define ASIO_ANY_IO_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include "asio/executor.hpp"
#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include "asio/execution.hpp"
# include "asio/execution_context.hpp"
#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
#include "asio/detail/push_options.hpp"
namespace asio {
#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
typedef executor any_io_executor;
#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
/// Polymorphic executor type for use with I/O objects.
/**
* The @c any_io_executor type is a polymorphic executor that supports the set
* of properties required by I/O objects. It is defined as the
* execution::any_executor class template parameterised as follows:
* @code execution::any_executor<
* execution::context_as_t<execution_context&>,
* execution::blocking_t::never_t,
* execution::prefer_only<execution::blocking_t::possibly_t>,
* execution::prefer_only<execution::outstanding_work_t::tracked_t>,
* execution::prefer_only<execution::outstanding_work_t::untracked_t>,
* execution::prefer_only<execution::relationship_t::fork_t>,
* execution::prefer_only<execution::relationship_t::continuation_t>
* > @endcode
*/
class any_io_executor :
#if defined(GENERATING_DOCUMENTATION)
public execution::any_executor<...>
#else // defined(GENERATING_DOCUMENTATION)
public execution::any_executor<
execution::context_as_t<execution_context&>,
execution::blocking_t::never_t,
execution::prefer_only<execution::blocking_t::possibly_t>,
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
>
#endif // defined(GENERATING_DOCUMENTATION)
{
public:
#if !defined(GENERATING_DOCUMENTATION)
typedef execution::any_executor<
execution::context_as_t<execution_context&>,
execution::blocking_t::never_t,
execution::prefer_only<execution::blocking_t::possibly_t>,
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
> base_type;
typedef void supportable_properties_type(
execution::context_as_t<execution_context&>,
execution::blocking_t::never_t,
execution::prefer_only<execution::blocking_t::possibly_t>,
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
);
#endif // !defined(GENERATING_DOCUMENTATION)
/// Default constructor.
ASIO_DECL any_io_executor() noexcept;
/// Construct in an empty state. Equivalent effects to default constructor.
ASIO_DECL any_io_executor(nullptr_t) noexcept;
/// Copy constructor.
ASIO_DECL any_io_executor(const any_io_executor& e) noexcept;
/// Move constructor.
ASIO_DECL any_io_executor(any_io_executor&& e) noexcept;
/// Construct to point to the same target as another any_executor.
#if defined(GENERATING_DOCUMENTATION)
template <class... OtherSupportableProperties>
any_io_executor(execution::any_executor<OtherSupportableProperties...> e);
#else // defined(GENERATING_DOCUMENTATION)
template <typename OtherAnyExecutor>
any_io_executor(OtherAnyExecutor e,
constraint_t<
conditional_t<
!is_same<OtherAnyExecutor, any_io_executor>::value
&& is_base_of<execution::detail::any_executor_base,
OtherAnyExecutor>::value,
typename execution::detail::supportable_properties<
0, supportable_properties_type>::template
is_valid_target<OtherAnyExecutor>,
false_type
>::value
> = 0)
: base_type(static_cast<OtherAnyExecutor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct to point to the same target as another any_executor.
#if defined(GENERATING_DOCUMENTATION)
template <class... OtherSupportableProperties>
any_io_executor(std::nothrow_t,
execution::any_executor<OtherSupportableProperties...> e);
#else // defined(GENERATING_DOCUMENTATION)
template <typename OtherAnyExecutor>
any_io_executor(std::nothrow_t, OtherAnyExecutor e,
constraint_t<
conditional_t<
!is_same<OtherAnyExecutor, any_io_executor>::value
&& is_base_of<execution::detail::any_executor_base,
OtherAnyExecutor>::value,
typename execution::detail::supportable_properties<
0, supportable_properties_type>::template
is_valid_target<OtherAnyExecutor>,
false_type
>::value
> = 0) noexcept
: base_type(std::nothrow, static_cast<OtherAnyExecutor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct to point to the same target as another any_executor.
ASIO_DECL any_io_executor(std::nothrow_t,
const any_io_executor& e) noexcept;
/// Construct to point to the same target as another any_executor.
ASIO_DECL any_io_executor(std::nothrow_t, any_io_executor&& e) noexcept;
/// Construct a polymorphic wrapper for the specified executor.
#if defined(GENERATING_DOCUMENTATION)
template <ASIO_EXECUTION_EXECUTOR Executor>
any_io_executor(Executor e);
#else // defined(GENERATING_DOCUMENTATION)
template <ASIO_EXECUTION_EXECUTOR Executor>
any_io_executor(Executor e,
constraint_t<
conditional_t<
!is_same<Executor, any_io_executor>::value
&& !is_base_of<execution::detail::any_executor_base,
Executor>::value,
execution::detail::is_valid_target_executor<
Executor, supportable_properties_type>,
false_type
>::value
> = 0)
: base_type(static_cast<Executor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct a polymorphic wrapper for the specified executor.
#if defined(GENERATING_DOCUMENTATION)
template <ASIO_EXECUTION_EXECUTOR Executor>
any_io_executor(std::nothrow_t, Executor e);
#else // defined(GENERATING_DOCUMENTATION)
template <ASIO_EXECUTION_EXECUTOR Executor>
any_io_executor(std::nothrow_t, Executor e,
constraint_t<
conditional_t<
!is_same<Executor, any_io_executor>::value
&& !is_base_of<execution::detail::any_executor_base,
Executor>::value,
execution::detail::is_valid_target_executor<
Executor, supportable_properties_type>,
false_type
>::value
> = 0) noexcept
: base_type(std::nothrow, static_cast<Executor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Assignment operator.
ASIO_DECL any_io_executor& operator=(
const any_io_executor& e) noexcept;
/// Move assignment operator.
ASIO_DECL any_io_executor& operator=(any_io_executor&& e) noexcept;
/// Assignment operator that sets the polymorphic wrapper to the empty state.
ASIO_DECL any_io_executor& operator=(nullptr_t);
/// Destructor.
ASIO_DECL ~any_io_executor();
/// Swap targets with another polymorphic wrapper.
ASIO_DECL void swap(any_io_executor& other) noexcept;
/// Obtain a polymorphic wrapper with the specified property.
/**
* Do not call this function directly. It is intended for use with the
* asio::require and asio::prefer customisation points.
*
* For example:
* @code any_io_executor ex = ...;
* auto ex2 = asio::require(ex, execution::blocking.possibly); @endcode
*/
template <typename Property>
any_io_executor require(const Property& p,
constraint_t<
traits::require_member<const base_type&, const Property&>::is_valid
> = 0) const
{
return static_cast<const base_type&>(*this).require(p);
}
/// Obtain a polymorphic wrapper with the specified property.
/**
* Do not call this function directly. It is intended for use with the
* asio::prefer customisation point.
*
* For example:
* @code any_io_executor ex = ...;
* auto ex2 = asio::prefer(ex, execution::blocking.possibly); @endcode
*/
template <typename Property>
any_io_executor prefer(const Property& p,
constraint_t<
traits::prefer_member<const base_type&, const Property&>::is_valid
> = 0) const
{
return static_cast<const base_type&>(*this).prefer(p);
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <>
ASIO_DECL any_io_executor any_io_executor::require(
const execution::blocking_t::never_t&, int) const;
template <>
ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::blocking_t::possibly_t&, int) const;
template <>
ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::outstanding_work_t::tracked_t&, int) const;
template <>
ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::outstanding_work_t::untracked_t&, int) const;
template <>
ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::relationship_t::fork_t&, int) const;
template <>
ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::relationship_t::continuation_t&, int) const;
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <>
struct equality_comparable<any_io_executor>
{
static const bool is_valid = true;
static const bool is_noexcept = true;
};
#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
template <typename F>
struct execute_member<any_io_executor, F>
{
static const bool is_valid = true;
static const bool is_noexcept = false;
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
template <typename Prop>
struct query_member<any_io_executor, Prop> :
query_member<any_io_executor::base_type, Prop>
{
};
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
template <typename Prop>
struct require_member<any_io_executor, Prop> :
require_member<any_io_executor::base_type, Prop>
{
typedef any_io_executor result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
template <typename Prop>
struct prefer_member<any_io_executor, Prop> :
prefer_member<any_io_executor::base_type, Prop>
{
typedef any_io_executor result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
} // namespace traits
#endif // !defined(GENERATING_DOCUMENTATION)
#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#if defined(ASIO_HEADER_ONLY) \
&& !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include "asio/impl/any_io_executor.ipp"
#endif // defined(ASIO_HEADER_ONLY)
// && !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
#endif // ASIO_ANY_IO_EXECUTOR_HPP

View File

@@ -0,0 +1,65 @@
//
// append.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 ASIO_APPEND_HPP
#define ASIO_APPEND_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <tuple>
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Completion token type used to specify that the completion handler
/// arguments should be passed additional values after the results of the
/// operation.
template <typename CompletionToken, typename... Values>
class append_t
{
public:
/// Constructor.
template <typename T, typename... V>
constexpr explicit append_t(T&& completion_token, V&&... values)
: token_(static_cast<T&&>(completion_token)),
values_(static_cast<V&&>(values)...)
{
}
//private:
CompletionToken token_;
std::tuple<Values...> values_;
};
/// Completion token type used to specify that the completion handler
/// arguments should be passed additional values after the results of the
/// operation.
template <typename CompletionToken, typename... Values>
ASIO_NODISCARD inline constexpr
append_t<decay_t<CompletionToken>, decay_t<Values>...>
append(CompletionToken&& completion_token, Values&&... values)
{
return append_t<decay_t<CompletionToken>, decay_t<Values>...>(
static_cast<CompletionToken&&>(completion_token),
static_cast<Values&&>(values)...);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/append.hpp"
#endif // ASIO_APPEND_HPP

View File

@@ -0,0 +1,126 @@
//
// as_tuple.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 ASIO_AS_TUPLE_HPP
#define ASIO_AS_TUPLE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// A @ref completion_token adapter used to specify that the completion handler
/// arguments should be combined into a single tuple argument.
/**
* The as_tuple_t class is used to indicate that any arguments to the
* completion handler should be combined and passed as a single tuple argument.
* The arguments are first moved into a @c std::tuple and that tuple is then
* passed to the completion handler.
*/
template <typename CompletionToken>
class as_tuple_t
{
public:
/// Tag type used to prevent the "default" constructor from being used for
/// conversions.
struct default_constructor_tag {};
/// Default constructor.
/**
* This constructor is only valid if the underlying completion token is
* default constructible and move constructible. The underlying completion
* token is itself defaulted as an argument to allow it to capture a source
* location.
*/
constexpr as_tuple_t(
default_constructor_tag = default_constructor_tag(),
CompletionToken token = CompletionToken())
: token_(static_cast<CompletionToken&&>(token))
{
}
/// Constructor.
template <typename T>
constexpr explicit as_tuple_t(
T&& completion_token)
: token_(static_cast<T&&>(completion_token))
{
}
/// Adapts an executor to add the @c as_tuple_t completion token as the
/// default.
template <typename InnerExecutor>
struct executor_with_default : InnerExecutor
{
/// Specify @c as_tuple_t as the default completion token type.
typedef as_tuple_t default_completion_token_type;
/// Construct the adapted executor from the inner executor type.
template <typename InnerExecutor1>
executor_with_default(const InnerExecutor1& ex,
constraint_t<
conditional_t<
!is_same<InnerExecutor1, executor_with_default>::value,
is_convertible<InnerExecutor1, InnerExecutor>,
false_type
>::value
> = 0) noexcept
: InnerExecutor(ex)
{
}
};
/// Type alias to adapt an I/O object to use @c as_tuple_t as its
/// default completion token type.
template <typename T>
using as_default_on_t = typename T::template rebind_executor<
executor_with_default<typename T::executor_type>>::other;
/// Function helper to adapt an I/O object to use @c as_tuple_t as its
/// default completion token type.
template <typename T>
static typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other
as_default_on(T&& object)
{
return typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other(static_cast<T&&>(object));
}
//private:
CompletionToken token_;
};
/// Adapt a @ref completion_token to specify that the completion handler
/// arguments should be combined into a single tuple argument.
template <typename CompletionToken>
ASIO_NODISCARD inline
constexpr as_tuple_t<decay_t<CompletionToken>>
as_tuple(CompletionToken&& completion_token)
{
return as_tuple_t<decay_t<CompletionToken>>(
static_cast<CompletionToken&&>(completion_token));
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/as_tuple.hpp"
#endif // ASIO_AS_TUPLE_HPP

View File

@@ -2,7 +2,7 @@
// associated_allocator.hpp // associated_allocator.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -17,40 +17,74 @@
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#include <memory> #include <memory>
#include "asio/associator.hpp"
#include "asio/detail/functional.hpp"
#include "asio/detail/type_traits.hpp" #include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
namespace asio { namespace asio {
template <typename T, typename Allocator>
struct associated_allocator;
namespace detail { namespace detail {
template <typename> template <typename T, typename = void>
struct associated_allocator_check struct has_allocator_type : false_type
{ {
typedef void type;
}; };
template <typename T, typename E, typename = void> template <typename T>
struct has_allocator_type<T, void_t<typename T::allocator_type>> : true_type
{
};
template <typename T, typename A, typename = void, typename = void>
struct associated_allocator_impl struct associated_allocator_impl
{ {
typedef E type; typedef void asio_associated_allocator_is_unspecialised;
static type get(const T&, const E& e) ASIO_NOEXCEPT typedef A type;
static type get(const T&) noexcept
{ {
return e; return type();
}
static const type& get(const T&, const A& a) noexcept
{
return a;
} }
}; };
template <typename T, typename E> template <typename T, typename A>
struct associated_allocator_impl<T, E, struct associated_allocator_impl<T, A, void_t<typename T::allocator_type>>
typename associated_allocator_check<typename T::allocator_type>::type>
{ {
typedef typename T::allocator_type type; typedef typename T::allocator_type type;
static type get(const T& t, const E&) ASIO_NOEXCEPT static auto get(const T& t) noexcept
-> decltype(t.get_allocator())
{ {
return t.get_allocator(); return t.get_allocator();
} }
static auto get(const T& t, const A&) noexcept
-> decltype(t.get_allocator())
{
return t.get_allocator();
}
};
template <typename T, typename A>
struct associated_allocator_impl<T, A,
enable_if_t<
!has_allocator_type<T>::value
>,
void_t<
typename associator<associated_allocator, T, A>::type
>> : associator<associated_allocator, T, A>
{
}; };
} // namespace detail } // namespace detail
@@ -69,29 +103,32 @@ struct associated_allocator_impl<T, E,
* Allocator requirements. * Allocator requirements.
* *
* @li Provide a noexcept static member function named @c get, callable as @c * @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type. * get(t) and with return type @c type or a (possibly const) reference to @c
* type.
* *
* @li Provide a noexcept static member function named @c get, callable as @c * @li Provide a noexcept static member function named @c get, callable as @c
* get(t,a) and with return type @c type. * get(t,a) and with return type @c type or a (possibly const) reference to @c
* type.
*/ */
template <typename T, typename Allocator = std::allocator<void>> template <typename T, typename Allocator = std::allocator<void>>
struct associated_allocator struct associated_allocator
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_allocator_impl<T, Allocator>
#endif // !defined(GENERATING_DOCUMENTATION)
{ {
#if defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>. /// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>.
/// Otherwise @c Allocator. /// Otherwise @c Allocator.
#if defined(GENERATING_DOCUMENTATION)
typedef see_below type; typedef see_below type;
#else // defined(GENERATING_DOCUMENTATION)
typedef typename detail::associated_allocator_impl<T, Allocator>::type type; /// If @c T has a nested type @c allocator_type, returns
#endif // defined(GENERATING_DOCUMENTATION) /// <tt>t.get_allocator()</tt>. Otherwise returns @c type().
static decltype(auto) get(const T& t) noexcept;
/// If @c T has a nested type @c allocator_type, returns /// If @c T has a nested type @c allocator_type, returns
/// <tt>t.get_allocator()</tt>. Otherwise returns @c a. /// <tt>t.get_allocator()</tt>. Otherwise returns @c a.
static type get(const T& t, static decltype(auto) get(const T& t, const Allocator& a) noexcept;
const Allocator& a = Allocator()) ASIO_NOEXCEPT #endif // defined(GENERATING_DOCUMENTATION)
{
return detail::associated_allocator_impl<T, Allocator>::get(t, a);
}
}; };
/// Helper function to obtain an object's associated allocator. /// Helper function to obtain an object's associated allocator.
@@ -99,8 +136,8 @@ struct associated_allocator
* @returns <tt>associated_allocator<T>::get(t)</tt> * @returns <tt>associated_allocator<T>::get(t)</tt>
*/ */
template <typename T> template <typename T>
inline typename associated_allocator<T>::type ASIO_NODISCARD inline typename associated_allocator<T>::type
get_associated_allocator(const T& t) ASIO_NOEXCEPT get_associated_allocator(const T& t) noexcept
{ {
return associated_allocator<T>::get(t); return associated_allocator<T>::get(t);
} }
@@ -110,19 +147,65 @@ get_associated_allocator(const T& t) ASIO_NOEXCEPT
* @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt> * @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt>
*/ */
template <typename T, typename Allocator> template <typename T, typename Allocator>
inline typename associated_allocator<T, Allocator>::type ASIO_NODISCARD inline auto get_associated_allocator(
get_associated_allocator(const T& t, const Allocator& a) ASIO_NOEXCEPT const T& t, const Allocator& a) noexcept
-> decltype(associated_allocator<T, Allocator>::get(t, a))
{ {
return associated_allocator<T, Allocator>::get(t, a); return associated_allocator<T, Allocator>::get(t, a);
} }
#if defined(ASIO_HAS_ALIAS_TEMPLATES)
template <typename T, typename Allocator = std::allocator<void>> template <typename T, typename Allocator = std::allocator<void>>
using associated_allocator_t using associated_allocator_t
= typename associated_allocator<T, Allocator>::type; = typename associated_allocator<T, Allocator>::type;
#endif // defined(ASIO_HAS_ALIAS_TEMPLATES) namespace detail {
template <typename T, typename A, typename = void>
struct associated_allocator_forwarding_base
{
};
template <typename T, typename A>
struct associated_allocator_forwarding_base<T, A,
enable_if_t<
is_same<
typename associated_allocator<T,
A>::asio_associated_allocator_is_unspecialised,
void
>::value
>>
{
typedef void asio_associated_allocator_is_unspecialised;
};
} // namespace detail
/// Specialisation of associated_allocator for @c std::reference_wrapper.
template <typename T, typename Allocator>
struct associated_allocator<reference_wrapper<T>, Allocator>
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_allocator_forwarding_base<T, Allocator>
#endif // !defined(GENERATING_DOCUMENTATION)
{
/// Forwards @c type to the associator specialisation for the unwrapped type
/// @c T.
typedef typename associated_allocator<T, Allocator>::type type;
/// Forwards the request to get the allocator to the associator specialisation
/// for the unwrapped type @c T.
static type get(reference_wrapper<T> t) noexcept
{
return associated_allocator<T, Allocator>::get(t.get());
}
/// Forwards the request to get the allocator to the associator specialisation
/// for the unwrapped type @c T.
static auto get(reference_wrapper<T> t, const Allocator& a) noexcept
-> decltype(associated_allocator<T, Allocator>::get(t.get(), a))
{
return associated_allocator<T, Allocator>::get(t.get(), a);
}
};
} // namespace asio } // namespace asio

View File

@@ -0,0 +1,221 @@
//
// associated_cancellation_slot.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 ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP
#define ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/associator.hpp"
#include "asio/cancellation_signal.hpp"
#include "asio/detail/functional.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename T, typename CancellationSlot>
struct associated_cancellation_slot;
namespace detail {
template <typename T, typename = void>
struct has_cancellation_slot_type : false_type
{
};
template <typename T>
struct has_cancellation_slot_type<T, void_t<typename T::cancellation_slot_type>>
: true_type
{
};
template <typename T, typename S, typename = void, typename = void>
struct associated_cancellation_slot_impl
{
typedef void asio_associated_cancellation_slot_is_unspecialised;
typedef S type;
static type get(const T&) noexcept
{
return type();
}
static const type& get(const T&, const S& s) noexcept
{
return s;
}
};
template <typename T, typename S>
struct associated_cancellation_slot_impl<T, S,
void_t<typename T::cancellation_slot_type>>
{
typedef typename T::cancellation_slot_type type;
static auto get(const T& t) noexcept
-> decltype(t.get_cancellation_slot())
{
return t.get_cancellation_slot();
}
static auto get(const T& t, const S&) noexcept
-> decltype(t.get_cancellation_slot())
{
return t.get_cancellation_slot();
}
};
template <typename T, typename S>
struct associated_cancellation_slot_impl<T, S,
enable_if_t<
!has_cancellation_slot_type<T>::value
>,
void_t<
typename associator<associated_cancellation_slot, T, S>::type
>> : associator<associated_cancellation_slot, T, S>
{
};
} // namespace detail
/// Traits type used to obtain the cancellation_slot associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* CancellationSlot shall be a type meeting the CancellationSlot requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c s is an object of type @c
* CancellationSlot.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* CancellationSlot requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type or a (possibly const) reference to @c
* type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,s) and with return type @c type or a (possibly const) reference to @c
* type.
*/
template <typename T, typename CancellationSlot = cancellation_slot>
struct associated_cancellation_slot
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_cancellation_slot_impl<T, CancellationSlot>
#endif // !defined(GENERATING_DOCUMENTATION)
{
#if defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c cancellation_slot_type,
/// <tt>T::cancellation_slot_type</tt>. Otherwise
/// @c CancellationSlot.
typedef see_below type;
/// If @c T has a nested type @c cancellation_slot_type, returns
/// <tt>t.get_cancellation_slot()</tt>. Otherwise returns @c type().
static decltype(auto) get(const T& t) noexcept;
/// If @c T has a nested type @c cancellation_slot_type, returns
/// <tt>t.get_cancellation_slot()</tt>. Otherwise returns @c s.
static decltype(auto) get(const T& t,
const CancellationSlot& s) noexcept;
#endif // defined(GENERATING_DOCUMENTATION)
};
/// Helper function to obtain an object's associated cancellation_slot.
/**
* @returns <tt>associated_cancellation_slot<T>::get(t)</tt>
*/
template <typename T>
ASIO_NODISCARD inline typename associated_cancellation_slot<T>::type
get_associated_cancellation_slot(const T& t) noexcept
{
return associated_cancellation_slot<T>::get(t);
}
/// Helper function to obtain an object's associated cancellation_slot.
/**
* @returns <tt>associated_cancellation_slot<T,
* CancellationSlot>::get(t, st)</tt>
*/
template <typename T, typename CancellationSlot>
ASIO_NODISCARD inline auto get_associated_cancellation_slot(
const T& t, const CancellationSlot& st) noexcept
-> decltype(associated_cancellation_slot<T, CancellationSlot>::get(t, st))
{
return associated_cancellation_slot<T, CancellationSlot>::get(t, st);
}
template <typename T, typename CancellationSlot = cancellation_slot>
using associated_cancellation_slot_t =
typename associated_cancellation_slot<T, CancellationSlot>::type;
namespace detail {
template <typename T, typename S, typename = void>
struct associated_cancellation_slot_forwarding_base
{
};
template <typename T, typename S>
struct associated_cancellation_slot_forwarding_base<T, S,
enable_if_t<
is_same<
typename associated_cancellation_slot<T,
S>::asio_associated_cancellation_slot_is_unspecialised,
void
>::value
>>
{
typedef void asio_associated_cancellation_slot_is_unspecialised;
};
} // namespace detail
/// Specialisation of associated_cancellation_slot for @c
/// std::reference_wrapper.
template <typename T, typename CancellationSlot>
struct associated_cancellation_slot<reference_wrapper<T>, CancellationSlot>
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_cancellation_slot_forwarding_base<T, CancellationSlot>
#endif // !defined(GENERATING_DOCUMENTATION)
{
/// Forwards @c type to the associator specialisation for the unwrapped type
/// @c T.
typedef typename associated_cancellation_slot<T, CancellationSlot>::type type;
/// Forwards the request to get the cancellation slot to the associator
/// specialisation for the unwrapped type @c T.
static type get(reference_wrapper<T> t) noexcept
{
return associated_cancellation_slot<T, CancellationSlot>::get(t.get());
}
/// Forwards the request to get the cancellation slot to the associator
/// specialisation for the unwrapped type @c T.
static auto get(reference_wrapper<T> t, const CancellationSlot& s) noexcept
-> decltype(
associated_cancellation_slot<T, CancellationSlot>::get(t.get(), s))
{
return associated_cancellation_slot<T, CancellationSlot>::get(t.get(), s);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP

View File

@@ -2,7 +2,7 @@
// associated_executor.hpp // associated_executor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,42 +16,78 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#include "asio/associator.hpp"
#include "asio/detail/functional.hpp"
#include "asio/detail/type_traits.hpp" #include "asio/detail/type_traits.hpp"
#include "asio/execution/executor.hpp"
#include "asio/is_executor.hpp" #include "asio/is_executor.hpp"
#include "asio/system_executor.hpp" #include "asio/system_executor.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
namespace asio { namespace asio {
template <typename T, typename Executor>
struct associated_executor;
namespace detail { namespace detail {
template <typename> template <typename T, typename = void>
struct associated_executor_check struct has_executor_type : false_type
{ {
typedef void type;
}; };
template <typename T, typename E, typename = void> template <typename T>
struct has_executor_type<T, void_t<typename T::executor_type>>
: true_type
{
};
template <typename T, typename E, typename = void, typename = void>
struct associated_executor_impl struct associated_executor_impl
{ {
typedef void asio_associated_executor_is_unspecialised;
typedef E type; typedef E type;
static type get(const T&, const E& e) ASIO_NOEXCEPT static type get(const T&) noexcept
{
return type();
}
static const type& get(const T&, const E& e) noexcept
{ {
return e; return e;
} }
}; };
template <typename T, typename E> template <typename T, typename E>
struct associated_executor_impl<T, E, struct associated_executor_impl<T, E, void_t<typename T::executor_type>>
typename associated_executor_check<typename T::executor_type>::type>
{ {
typedef typename T::executor_type type; typedef typename T::executor_type type;
static type get(const T& t, const E&) ASIO_NOEXCEPT static auto get(const T& t) noexcept
-> decltype(t.get_executor())
{ {
return t.get_executor(); return t.get_executor();
} }
static auto get(const T& t, const E&) noexcept
-> decltype(t.get_executor())
{
return t.get_executor();
}
};
template <typename T, typename E>
struct associated_executor_impl<T, E,
enable_if_t<
!has_executor_type<T>::value
>,
void_t<
typename associator<associated_executor, T, E>::type
>> : associator<associated_executor, T, E>
{
}; };
} // namespace detail } // namespace detail
@@ -70,29 +106,32 @@ struct associated_executor_impl<T, E,
* Executor requirements. * Executor requirements.
* *
* @li Provide a noexcept static member function named @c get, callable as @c * @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type. * get(t) and with return type @c type or a (possibly const) reference to @c
* type.
* *
* @li Provide a noexcept static member function named @c get, callable as @c * @li Provide a noexcept static member function named @c get, callable as @c
* get(t,e) and with return type @c type. * get(t,e) and with return type @c type or a (possibly const) reference to @c
* type.
*/ */
template <typename T, typename Executor = system_executor> template <typename T, typename Executor = system_executor>
struct associated_executor struct associated_executor
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_executor_impl<T, Executor>
#endif // !defined(GENERATING_DOCUMENTATION)
{ {
#if defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c executor_type, <tt>T::executor_type</tt>. /// If @c T has a nested type @c executor_type, <tt>T::executor_type</tt>.
/// Otherwise @c Executor. /// Otherwise @c Executor.
#if defined(GENERATING_DOCUMENTATION)
typedef see_below type; typedef see_below type;
#else // defined(GENERATING_DOCUMENTATION)
typedef typename detail::associated_executor_impl<T, Executor>::type type; /// If @c T has a nested type @c executor_type, returns
#endif // defined(GENERATING_DOCUMENTATION) /// <tt>t.get_executor()</tt>. Otherwise returns @c type().
static decltype(auto) get(const T& t) noexcept;
/// If @c T has a nested type @c executor_type, returns /// If @c T has a nested type @c executor_type, returns
/// <tt>t.get_executor()</tt>. Otherwise returns @c ex. /// <tt>t.get_executor()</tt>. Otherwise returns @c ex.
static type get(const T& t, static decltype(auto) get(const T& t, const Executor& ex) noexcept;
const Executor& ex = Executor()) ASIO_NOEXCEPT #endif // defined(GENERATING_DOCUMENTATION)
{
return detail::associated_executor_impl<T, Executor>::get(t, ex);
}
}; };
/// Helper function to obtain an object's associated executor. /// Helper function to obtain an object's associated executor.
@@ -100,8 +139,8 @@ struct associated_executor
* @returns <tt>associated_executor<T>::get(t)</tt> * @returns <tt>associated_executor<T>::get(t)</tt>
*/ */
template <typename T> template <typename T>
inline typename associated_executor<T>::type ASIO_NODISCARD inline typename associated_executor<T>::type
get_associated_executor(const T& t) ASIO_NOEXCEPT get_associated_executor(const T& t) noexcept
{ {
return associated_executor<T>::get(t); return associated_executor<T>::get(t);
} }
@@ -111,10 +150,12 @@ get_associated_executor(const T& t) ASIO_NOEXCEPT
* @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt> * @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt>
*/ */
template <typename T, typename Executor> template <typename T, typename Executor>
inline typename associated_executor<T, Executor>::type ASIO_NODISCARD inline auto get_associated_executor(
get_associated_executor(const T& t, const Executor& ex, const T& t, const Executor& ex,
typename enable_if<is_executor< constraint_t<
Executor>::value>::type* = 0) ASIO_NOEXCEPT is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0) noexcept
-> decltype(associated_executor<T, Executor>::get(t, ex))
{ {
return associated_executor<T, Executor>::get(t, ex); return associated_executor<T, Executor>::get(t, ex);
} }
@@ -125,22 +166,67 @@ get_associated_executor(const T& t, const Executor& ex,
* ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt> * ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt>
*/ */
template <typename T, typename ExecutionContext> template <typename T, typename ExecutionContext>
inline typename associated_executor<T, ASIO_NODISCARD inline typename associated_executor<T,
typename ExecutionContext::executor_type>::type typename ExecutionContext::executor_type>::type
get_associated_executor(const T& t, ExecutionContext& ctx, get_associated_executor(const T& t, ExecutionContext& ctx,
typename enable_if<is_convertible<ExecutionContext&, constraint_t<is_convertible<ExecutionContext&,
execution_context&>::value>::type* = 0) ASIO_NOEXCEPT execution_context&>::value> = 0) noexcept
{ {
return associated_executor<T, return associated_executor<T,
typename ExecutionContext::executor_type>::get(t, ctx.get_executor()); typename ExecutionContext::executor_type>::get(t, ctx.get_executor());
} }
#if defined(ASIO_HAS_ALIAS_TEMPLATES)
template <typename T, typename Executor = system_executor> template <typename T, typename Executor = system_executor>
using associated_executor_t = typename associated_executor<T, Executor>::type; using associated_executor_t = typename associated_executor<T, Executor>::type;
#endif // defined(ASIO_HAS_ALIAS_TEMPLATES) namespace detail {
template <typename T, typename E, typename = void>
struct associated_executor_forwarding_base
{
};
template <typename T, typename E>
struct associated_executor_forwarding_base<T, E,
enable_if_t<
is_same<
typename associated_executor<T,
E>::asio_associated_executor_is_unspecialised,
void
>::value
>>
{
typedef void asio_associated_executor_is_unspecialised;
};
} // namespace detail
/// Specialisation of associated_executor for @c std::reference_wrapper.
template <typename T, typename Executor>
struct associated_executor<reference_wrapper<T>, Executor>
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_executor_forwarding_base<T, Executor>
#endif // !defined(GENERATING_DOCUMENTATION)
{
/// Forwards @c type to the associator specialisation for the unwrapped type
/// @c T.
typedef typename associated_executor<T, Executor>::type type;
/// Forwards the request to get the executor to the associator specialisation
/// for the unwrapped type @c T.
static type get(reference_wrapper<T> t) noexcept
{
return associated_executor<T, Executor>::get(t.get());
}
/// Forwards the request to get the executor to the associator specialisation
/// for the unwrapped type @c T.
static auto get(reference_wrapper<T> t, const Executor& ex) noexcept
-> decltype(associated_executor<T, Executor>::get(t.get(), ex))
{
return associated_executor<T, Executor>::get(t.get(), ex);
}
};
} // namespace asio } // namespace asio

View File

@@ -0,0 +1,280 @@
//
// associated_immediate_executor.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 ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP
#define ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/associator.hpp"
#include "asio/detail/functional.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/execution/blocking.hpp"
#include "asio/execution/executor.hpp"
#include "asio/execution_context.hpp"
#include "asio/is_executor.hpp"
#include "asio/require.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename T, typename Executor>
struct associated_immediate_executor;
namespace detail {
template <typename T, typename = void>
struct has_immediate_executor_type : false_type
{
};
template <typename T>
struct has_immediate_executor_type<T,
void_t<typename T::immediate_executor_type>>
: true_type
{
};
template <typename E, typename = void, typename = void>
struct default_immediate_executor
{
typedef require_result_t<E, execution::blocking_t::never_t> type;
static type get(const E& e) noexcept
{
return asio::require(e, execution::blocking.never);
}
};
template <typename E>
struct default_immediate_executor<E,
enable_if_t<
!execution::is_executor<E>::value
>,
enable_if_t<
is_executor<E>::value
>>
{
class type : public E
{
public:
template <typename Executor1>
explicit type(const Executor1& e,
constraint_t<
conditional_t<
!is_same<Executor1, type>::value,
is_convertible<Executor1, E>,
false_type
>::value
> = 0) noexcept
: E(e)
{
}
type(const type& other) noexcept
: E(static_cast<const E&>(other))
{
}
type(type&& other) noexcept
: E(static_cast<E&&>(other))
{
}
template <typename Function, typename Allocator>
void dispatch(Function&& f, const Allocator& a) const
{
this->post(static_cast<Function&&>(f), a);
}
friend bool operator==(const type& a, const type& b) noexcept
{
return static_cast<const E&>(a) == static_cast<const E&>(b);
}
friend bool operator!=(const type& a, const type& b) noexcept
{
return static_cast<const E&>(a) != static_cast<const E&>(b);
}
};
static type get(const E& e) noexcept
{
return type(e);
}
};
template <typename T, typename E, typename = void, typename = void>
struct associated_immediate_executor_impl
{
typedef void asio_associated_immediate_executor_is_unspecialised;
typedef typename default_immediate_executor<E>::type type;
static auto get(const T&, const E& e) noexcept
-> decltype(default_immediate_executor<E>::get(e))
{
return default_immediate_executor<E>::get(e);
}
};
template <typename T, typename E>
struct associated_immediate_executor_impl<T, E,
void_t<typename T::immediate_executor_type>>
{
typedef typename T::immediate_executor_type type;
static auto get(const T& t, const E&) noexcept
-> decltype(t.get_immediate_executor())
{
return t.get_immediate_executor();
}
};
template <typename T, typename E>
struct associated_immediate_executor_impl<T, E,
enable_if_t<
!has_immediate_executor_type<T>::value
>,
void_t<
typename associator<associated_immediate_executor, T, E>::type
>> : associator<associated_immediate_executor, T, E>
{
};
} // namespace detail
/// Traits type used to obtain the immediate executor associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* Executor shall be a type meeting the Executor requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c e is an object of type @c
* Executor.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* Executor requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type or a (possibly const) reference to @c
* type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,e) and with return type @c type or a (possibly const) reference to @c
* type.
*/
template <typename T, typename Executor>
struct associated_immediate_executor
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_immediate_executor_impl<T, Executor>
#endif // !defined(GENERATING_DOCUMENTATION)
{
#if defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c immediate_executor_type,
// <tt>T::immediate_executor_type</tt>. Otherwise @c Executor.
typedef see_below type;
/// If @c T has a nested type @c immediate_executor_type, returns
/// <tt>t.get_immediate_executor()</tt>. Otherwise returns
/// <tt>asio::require(ex, asio::execution::blocking.never)</tt>.
static decltype(auto) get(const T& t, const Executor& ex) noexcept;
#endif // defined(GENERATING_DOCUMENTATION)
};
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_immediate_executor<T, Executor>::get(t, ex)</tt>
*/
template <typename T, typename Executor>
ASIO_NODISCARD inline auto get_associated_immediate_executor(
const T& t, const Executor& ex,
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0) noexcept
-> decltype(associated_immediate_executor<T, Executor>::get(t, ex))
{
return associated_immediate_executor<T, Executor>::get(t, ex);
}
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_immediate_executor<T, typename
* ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt>
*/
template <typename T, typename ExecutionContext>
ASIO_NODISCARD inline typename associated_immediate_executor<T,
typename ExecutionContext::executor_type>::type
get_associated_immediate_executor(const T& t, ExecutionContext& ctx,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0) noexcept
{
return associated_immediate_executor<T,
typename ExecutionContext::executor_type>::get(t, ctx.get_executor());
}
template <typename T, typename Executor>
using associated_immediate_executor_t =
typename associated_immediate_executor<T, Executor>::type;
namespace detail {
template <typename T, typename E, typename = void>
struct associated_immediate_executor_forwarding_base
{
};
template <typename T, typename E>
struct associated_immediate_executor_forwarding_base<T, E,
enable_if_t<
is_same<
typename associated_immediate_executor<T,
E>::asio_associated_immediate_executor_is_unspecialised,
void
>::value
>>
{
typedef void asio_associated_immediate_executor_is_unspecialised;
};
} // namespace detail
/// Specialisation of associated_immediate_executor for
/// @c std::reference_wrapper.
template <typename T, typename Executor>
struct associated_immediate_executor<reference_wrapper<T>, Executor>
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_immediate_executor_forwarding_base<T, Executor>
#endif // !defined(GENERATING_DOCUMENTATION)
{
/// Forwards @c type to the associator specialisation for the unwrapped type
/// @c T.
typedef typename associated_immediate_executor<T, Executor>::type type;
/// Forwards the request to get the executor to the associator specialisation
/// for the unwrapped type @c T.
static auto get(reference_wrapper<T> t, const Executor& ex) noexcept
-> decltype(associated_immediate_executor<T, Executor>::get(t.get(), ex))
{
return associated_immediate_executor<T, Executor>::get(t.get(), ex);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP

View File

@@ -0,0 +1,35 @@
//
// associator.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 ASIO_ASSOCIATOR_HPP
#define ASIO_ASSOCIATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Used to generically specialise associators for a type.
template <template <typename, typename> class Associator,
typename T, typename DefaultCandidate>
struct associator
{
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_ASSOCIATOR_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,142 @@
//
// awaitable.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 ASIO_AWAITABLE_HPP
#define ASIO_AWAITABLE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#if defined(ASIO_HAS_STD_COROUTINE)
# include <coroutine>
#else // defined(ASIO_HAS_STD_COROUTINE)
# include <experimental/coroutine>
#endif // defined(ASIO_HAS_STD_COROUTINE)
#include <utility>
#include "asio/any_io_executor.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
#if defined(ASIO_HAS_STD_COROUTINE)
using std::coroutine_handle;
using std::suspend_always;
#else // defined(ASIO_HAS_STD_COROUTINE)
using std::experimental::coroutine_handle;
using std::experimental::suspend_always;
#endif // defined(ASIO_HAS_STD_COROUTINE)
template <typename> class awaitable_thread;
template <typename, typename> class awaitable_frame;
} // namespace detail
/// The return type of a coroutine or asynchronous operation.
template <typename T, typename Executor = any_io_executor>
class ASIO_NODISCARD awaitable
{
public:
/// The type of the awaited value.
typedef T value_type;
/// The executor type that will be used for the coroutine.
typedef Executor executor_type;
/// Default constructor.
constexpr awaitable() noexcept
: frame_(nullptr)
{
}
/// Move constructor.
awaitable(awaitable&& other) noexcept
: frame_(std::exchange(other.frame_, nullptr))
{
}
/// Destructor
~awaitable()
{
if (frame_)
frame_->destroy();
}
/// Move assignment.
awaitable& operator=(awaitable&& other) noexcept
{
if (this != &other)
frame_ = std::exchange(other.frame_, nullptr);
return *this;
}
/// Checks if the awaitable refers to a future result.
bool valid() const noexcept
{
return !!frame_;
}
#if !defined(GENERATING_DOCUMENTATION)
// Support for co_await keyword.
bool await_ready() const noexcept
{
return false;
}
// Support for co_await keyword.
template <class U>
void await_suspend(
detail::coroutine_handle<detail::awaitable_frame<U, Executor>> h)
{
frame_->push_frame(&h.promise());
}
// Support for co_await keyword.
T await_resume()
{
return awaitable(static_cast<awaitable&&>(*this)).frame_->get();
}
#endif // !defined(GENERATING_DOCUMENTATION)
private:
template <typename> friend class detail::awaitable_thread;
template <typename, typename> friend class detail::awaitable_frame;
// Not copy constructible or copy assignable.
awaitable(const awaitable&) = delete;
awaitable& operator=(const awaitable&) = delete;
// Construct the awaitable from a coroutine's frame object.
explicit awaitable(detail::awaitable_frame<T, Executor>* a)
: frame_(a)
{
}
detail::awaitable_frame<T, Executor>* frame_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/awaitable.hpp"
#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_AWAITABLE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// basic_deadline_timer.hpp // basic_deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -21,19 +21,16 @@
|| defined(GENERATING_DOCUMENTATION) || defined(GENERATING_DOCUMENTATION)
#include <cstddef> #include <cstddef>
#include "asio/basic_io_object.hpp" #include "asio/any_io_executor.hpp"
#include "asio/detail/deadline_timer_service.hpp"
#include "asio/detail/handler_type_requirements.hpp" #include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp" #include "asio/detail/throw_error.hpp"
#include "asio/error.hpp" #include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/time_traits.hpp" #include "asio/time_traits.hpp"
#if defined(ASIO_ENABLE_OLD_SERVICES)
# include "asio/deadline_timer_service.hpp"
#else // defined(ASIO_ENABLE_OLD_SERVICES)
# include "asio/detail/deadline_timer_service.hpp"
# define ASIO_SVC_T detail::deadline_timer_service<TimeTraits>
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
namespace asio { namespace asio {
@@ -57,7 +54,7 @@ namespace asio {
* Performing a blocking wait: * Performing a blocking wait:
* @code * @code
* // Construct a timer without setting an expiry time. * // Construct a timer without setting an expiry time.
* asio::deadline_timer timer(io_context); * asio::deadline_timer timer(my_context);
* *
* // Set an expiry time relative to now. * // Set an expiry time relative to now.
* timer.expires_from_now(boost::posix_time::seconds(5)); * timer.expires_from_now(boost::posix_time::seconds(5));
@@ -80,7 +77,7 @@ namespace asio {
* ... * ...
* *
* // Construct a timer with an absolute expiry time. * // Construct a timer with an absolute expiry time.
* asio::deadline_timer timer(io_context, * asio::deadline_timer timer(my_context,
* boost::posix_time::time_from_string("2005-12-07 23:59:59.000")); * boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));
* *
* // Start an asynchronous wait. * // Start an asynchronous wait.
@@ -127,14 +124,24 @@ namespace asio {
* it contains the value asio::error::operation_aborted. * it contains the value asio::error::operation_aborted.
*/ */
template <typename Time, template <typename Time,
typename TimeTraits = asio::time_traits<Time> typename TimeTraits = asio::time_traits<Time>,
ASIO_SVC_TPARAM_DEF2(= deadline_timer_service<Time, TimeTraits>)> typename Executor = any_io_executor>
class basic_deadline_timer class basic_deadline_timer
: ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T>
{ {
private:
class initiate_async_wait;
public: public:
/// The type of the executor associated with the object. /// The type of the executor associated with the object.
typedef io_context::executor_type executor_type; typedef Executor executor_type;
/// Rebinds the timer type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The timer type when rebound to the specified executor.
typedef basic_deadline_timer<Time, TimeTraits, Executor1> other;
};
/// The time traits type. /// The time traits type.
typedef TimeTraits traits_type; typedef TimeTraits traits_type;
@@ -151,11 +158,30 @@ public:
* expires_at() or expires_from_now() functions must be called to set an * expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on. * expiry time before the timer can be waited on.
* *
* @param io_context The io_context object that the timer will use to dispatch * @param ex The I/O executor that the timer will use, by default, to
* handlers for any asynchronous operations performed on the timer. * dispatch handlers for any asynchronous operations performed on the timer.
*/ */
explicit basic_deadline_timer(asio::io_context& io_context) explicit basic_deadline_timer(const executor_type& ex)
: basic_io_object<ASIO_SVC_T>(io_context) : impl_(0, ex)
{
}
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*/
template <typename ExecutionContext>
explicit basic_deadline_timer(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{ {
} }
@@ -163,18 +189,40 @@ public:
/** /**
* This constructor creates a timer and sets the expiry time. * This constructor creates a timer and sets the expiry time.
* *
* @param io_context The io_context object that the timer will use to dispatch * @param ex The I/O executor that the timer will use, by default, to
* handlers for any asynchronous operations performed on the timer. * dispatch handlers for any asynchronous operations performed on the timer.
* *
* @param expiry_time The expiry time to be used for the timer, expressed * @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time. * as an absolute time.
*/ */
basic_deadline_timer(asio::io_context& io_context, basic_deadline_timer(const executor_type& ex, const time_type& expiry_time)
const time_type& expiry_time) : impl_(0, ex)
: basic_io_object<ASIO_SVC_T>(io_context)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().expires_at(this->get_implementation(), expiry_time, ec); impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
template <typename ExecutionContext>
basic_deadline_timer(ExecutionContext& context, const time_type& expiry_time,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at"); asio::detail::throw_error(ec, "expires_at");
} }
@@ -182,23 +230,47 @@ public:
/** /**
* This constructor creates a timer and sets the expiry time. * This constructor creates a timer and sets the expiry time.
* *
* @param io_context The io_context object that the timer will use to dispatch * @param ex The I/O executor that the timer will use, by default, to
* handlers for any asynchronous operations performed on the timer. * dispatch handlers for any asynchronous operations performed on the timer.
* *
* @param expiry_time The expiry time to be used for the timer, relative to * @param expiry_time The expiry time to be used for the timer, relative to
* now. * now.
*/ */
basic_deadline_timer(asio::io_context& io_context, basic_deadline_timer(const executor_type& ex,
const duration_type& expiry_time) const duration_type& expiry_time)
: basic_io_object<ASIO_SVC_T>(io_context) : impl_(0, ex)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().expires_from_now( impl_.get_service().expires_from_now(
this->get_implementation(), expiry_time, ec); impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
template <typename ExecutionContext>
basic_deadline_timer(ExecutionContext& context,
const duration_type& expiry_time,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now"); asio::detail::throw_error(ec, "expires_from_now");
} }
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_deadline_timer from another. /// Move-construct a basic_deadline_timer from another.
/** /**
* This constructor moves a timer from one object to another. * This constructor moves a timer from one object to another.
@@ -207,10 +279,11 @@ public:
* occur. * occur.
* *
* @note Following the move, the moved-from object is in the same state as if * @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_deadline_timer(io_context&) constructor. * constructed using the @c basic_deadline_timer(const executor_type&)
* constructor.
*/ */
basic_deadline_timer(basic_deadline_timer&& other) basic_deadline_timer(basic_deadline_timer&& other)
: basic_io_object<ASIO_SVC_T>(std::move(other)) : impl_(std::move(other.impl_))
{ {
} }
@@ -223,14 +296,14 @@ public:
* occur. * occur.
* *
* @note Following the move, the moved-from object is in the same state as if * @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_deadline_timer(io_context&) constructor. * constructed using the @c basic_deadline_timer(const executor_type&)
* constructor.
*/ */
basic_deadline_timer& operator=(basic_deadline_timer&& other) basic_deadline_timer& operator=(basic_deadline_timer&& other)
{ {
basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); impl_ = std::move(other.impl_);
return *this; return *this;
} }
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the timer. /// Destroys the timer.
/** /**
@@ -241,45 +314,11 @@ public:
{ {
} }
#if defined(ASIO_ENABLE_OLD_SERVICES)
// These functions are provided by basic_io_object<>.
#else // defined(ASIO_ENABLE_OLD_SERVICES)
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
/**
* This function may be used to obtain the io_context object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_context object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_context& get_io_context()
{
return basic_io_object<ASIO_SVC_T>::get_io_context();
}
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
/**
* This function may be used to obtain the io_context object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_context object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_context& get_io_service()
{
return basic_io_object<ASIO_SVC_T>::get_io_service();
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// Get the executor associated with the object. /// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT const executor_type& get_executor() noexcept
{ {
return basic_io_object<ASIO_SVC_T>::get_executor(); return impl_.get_executor();
} }
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
/// Cancel any asynchronous operations that are waiting on the timer. /// Cancel any asynchronous operations that are waiting on the timer.
/** /**
@@ -306,7 +345,7 @@ public:
std::size_t cancel() std::size_t cancel()
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().cancel(this->get_implementation(), ec); std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel"); asio::detail::throw_error(ec, "cancel");
return s; return s;
} }
@@ -335,7 +374,7 @@ public:
*/ */
std::size_t cancel(asio::error_code& ec) std::size_t cancel(asio::error_code& ec)
{ {
return this->get_service().cancel(this->get_implementation(), ec); return impl_.get_service().cancel(impl_.get_implementation(), ec);
} }
/// Cancels one asynchronous operation that is waiting on the timer. /// Cancels one asynchronous operation that is waiting on the timer.
@@ -365,8 +404,8 @@ public:
std::size_t cancel_one() std::size_t cancel_one()
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().cancel_one( std::size_t s = impl_.get_service().cancel_one(
this->get_implementation(), ec); impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel_one"); asio::detail::throw_error(ec, "cancel_one");
return s; return s;
} }
@@ -397,7 +436,7 @@ public:
*/ */
std::size_t cancel_one(asio::error_code& ec) std::size_t cancel_one(asio::error_code& ec)
{ {
return this->get_service().cancel_one(this->get_implementation(), ec); return impl_.get_service().cancel_one(impl_.get_implementation(), ec);
} }
/// Get the timer's expiry time as an absolute time. /// Get the timer's expiry time as an absolute time.
@@ -407,7 +446,7 @@ public:
*/ */
time_type expires_at() const time_type expires_at() const
{ {
return this->get_service().expires_at(this->get_implementation()); return impl_.get_service().expires_at(impl_.get_implementation());
} }
/// Set the timer's expiry time as an absolute time. /// Set the timer's expiry time as an absolute time.
@@ -435,8 +474,8 @@ public:
std::size_t expires_at(const time_type& expiry_time) std::size_t expires_at(const time_type& expiry_time)
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().expires_at( std::size_t s = impl_.get_service().expires_at(
this->get_implementation(), expiry_time, ec); impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at"); asio::detail::throw_error(ec, "expires_at");
return s; return s;
} }
@@ -466,8 +505,8 @@ public:
std::size_t expires_at(const time_type& expiry_time, std::size_t expires_at(const time_type& expiry_time,
asio::error_code& ec) asio::error_code& ec)
{ {
return this->get_service().expires_at( return impl_.get_service().expires_at(
this->get_implementation(), expiry_time, ec); impl_.get_implementation(), expiry_time, ec);
} }
/// Get the timer's expiry time relative to now. /// Get the timer's expiry time relative to now.
@@ -477,7 +516,7 @@ public:
*/ */
duration_type expires_from_now() const duration_type expires_from_now() const
{ {
return this->get_service().expires_from_now(this->get_implementation()); return impl_.get_service().expires_from_now(impl_.get_implementation());
} }
/// Set the timer's expiry time relative to now. /// Set the timer's expiry time relative to now.
@@ -505,8 +544,8 @@ public:
std::size_t expires_from_now(const duration_type& expiry_time) std::size_t expires_from_now(const duration_type& expiry_time)
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().expires_from_now( std::size_t s = impl_.get_service().expires_from_now(
this->get_implementation(), expiry_time, ec); impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now"); asio::detail::throw_error(ec, "expires_from_now");
return s; return s;
} }
@@ -536,8 +575,8 @@ public:
std::size_t expires_from_now(const duration_type& expiry_time, std::size_t expires_from_now(const duration_type& expiry_time,
asio::error_code& ec) asio::error_code& ec)
{ {
return this->get_service().expires_from_now( return impl_.get_service().expires_from_now(
this->get_implementation(), expiry_time, ec); impl_.get_implementation(), expiry_time, ec);
} }
/// Perform a blocking wait on the timer. /// Perform a blocking wait on the timer.
@@ -550,7 +589,7 @@ public:
void wait() void wait()
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().wait(this->get_implementation(), ec); impl_.get_service().wait(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "wait"); asio::detail::throw_error(ec, "wait");
} }
@@ -563,65 +602,108 @@ public:
*/ */
void wait(asio::error_code& ec) void wait(asio::error_code& ec)
{ {
this->get_service().wait(this->get_implementation(), ec); impl_.get_service().wait(impl_.get_implementation(), ec);
} }
/// Start an asynchronous wait on the timer. /// Start an asynchronous wait on the timer.
/** /**
* This function may be used to initiate an asynchronous wait against the * This function may be used to initiate an asynchronous wait against the
* timer. It always returns immediately. * timer. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
* *
* For each call to async_wait(), the supplied handler will be called exactly * For each call to async_wait(), the completion handler will be called
* once. The handler will be called when: * exactly once. The completion handler will be called when:
* *
* @li The timer has expired. * @li The timer has expired.
* *
* @li The timer was cancelled, in which case the handler is passed the error * @li The timer was cancelled, in which case the handler is passed the error
* code asio::error::operation_aborted. * code asio::error::operation_aborted.
* *
* @param handler The handler to be called when the timer expires. Copies * @param token The @ref completion_token that will be used to produce a
* will be made of the handler as required. The function signature of the * completion handler, which will be called when the timer expires. Potential
* handler must be: * completion tokens include @ref use_future, @ref use_awaitable, @ref
* yield_context, or a function object with the correct completion signature.
* The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* const asio::error_code& error // Result of operation. * const asio::error_code& error // Result of operation.
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code) @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/ */
template <typename WaitHandler> template <
ASIO_INITFN_RESULT_TYPE(WaitHandler, ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
void (asio::error_code)) WaitToken = default_completion_token_t<executor_type>>
async_wait(ASIO_MOVE_ARG(WaitHandler) handler) auto async_wait(
WaitToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WaitToken, void (asio::error_code)>(
declval<initiate_async_wait>(), token))
{ {
// If you get an error on the following line it means that your handler does return async_initiate<WaitToken, void (asio::error_code)>(
// not meet the documented type requirements for a WaitHandler. initiate_async_wait(this), token);
}
private:
// Disallow copying and assignment.
basic_deadline_timer(const basic_deadline_timer&) = delete;
basic_deadline_timer& operator=(
const basic_deadline_timer&) = delete;
class initiate_async_wait
{
public:
typedef Executor executor_type;
explicit initiate_async_wait(basic_deadline_timer* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WaitHandler>
void operator()(WaitHandler&& handler) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WaitHandler.
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
#if defined(ASIO_ENABLE_OLD_SERVICES) detail::non_const_lvalue<WaitHandler> handler2(handler);
return this->get_service().async_wait(this->get_implementation(), self_->impl_.get_service().async_wait(
ASIO_MOVE_CAST(WaitHandler)(handler)); self_->impl_.get_implementation(),
#else // defined(ASIO_ENABLE_OLD_SERVICES) handler2.value, self_->impl_.get_executor());
async_completion<WaitHandler,
void (asio::error_code)> init(handler);
this->get_service().async_wait(this->get_implementation(),
init.completion_handler);
return init.result.get();
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
} }
private:
basic_deadline_timer* self_;
};
detail::io_object_impl<
detail::deadline_timer_service<TimeTraits>, Executor> impl_;
}; };
} // namespace asio } // namespace asio
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
#if !defined(ASIO_ENABLE_OLD_SERVICES)
# undef ASIO_SVC_T
#endif // !defined(ASIO_ENABLE_OLD_SERVICES)
#endif // defined(ASIO_HAS_BOOST_DATE_TIME) #endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// || defined(GENERATING_DOCUMENTATION) // || defined(GENERATING_DOCUMENTATION)

View File

@@ -0,0 +1,824 @@
//
// basic_file.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 ASIO_BASIC_FILE_HPP
#define ASIO_BASIC_FILE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_FILE) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include <utility>
#include "asio/any_io_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/cstdint.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/post.hpp"
#include "asio/file_base.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_file_service.hpp"
#elif defined(ASIO_HAS_IO_URING)
# include "asio/detail/io_uring_file_service.hpp"
#endif
#include "asio/detail/push_options.hpp"
namespace asio {
#if !defined(ASIO_BASIC_FILE_FWD_DECL)
#define ASIO_BASIC_FILE_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Executor = any_io_executor>
class basic_file;
#endif // !defined(ASIO_BASIC_FILE_FWD_DECL)
/// Provides file functionality.
/**
* The basic_file class template provides functionality that is common to both
* stream-oriented and random-access files.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor>
class basic_file
: public file_base
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the file type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The file type when rebound to the specified executor.
typedef basic_file<Executor1> other;
};
/// The native representation of a file.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_file_service::native_handle_type native_handle_type;
#elif defined(ASIO_HAS_IO_URING)
typedef detail::io_uring_file_service::native_handle_type native_handle_type;
#endif
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file without opening it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*/
explicit basic_file(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file without opening it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*/
template <typename ExecutionContext>
explicit basic_file(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct and open a basic_file.
/**
* This constructor initialises a file and opens it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
explicit basic_file(const executor_type& ex,
const char* path, file_base::flags open_flags)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file and opens it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
template <typename ExecutionContext>
explicit basic_file(ExecutionContext& context,
const char* path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_file.
/**
* This constructor initialises a file and opens it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
explicit basic_file(const executor_type& ex,
const std::string& path, file_base::flags open_flags)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file and opens it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
template <typename ExecutionContext>
explicit basic_file(ExecutionContext& context,
const std::string& path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct a basic_file on an existing native file handle.
/**
* This constructor initialises a file object to hold an existing native file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param native_file A native file handle.
*
* @throws asio::system_error Thrown on failure.
*/
basic_file(const executor_type& ex, const native_handle_type& native_file)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_file on an existing native file.
/**
* This constructor initialises a file object to hold an existing native file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param native_file A native file.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_file(ExecutionContext& context, const native_handle_type& native_file,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
asio::detail::throw_error(ec, "assign");
}
/// Move-construct a basic_file from another.
/**
* This constructor moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
basic_file(basic_file&& other) noexcept
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_file from another.
/**
* This assignment operator moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
basic_file& operator=(basic_file&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
// All files have access to each other's implementations.
template <typename Executor1>
friend class basic_file;
/// Move-construct a basic_file from a file of another executor type.
/**
* This constructor moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
template <typename Executor1>
basic_file(basic_file<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_file from a file of another executor type.
/**
* This assignment operator moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_file&
> operator=(basic_file<Executor1>&& other)
{
basic_file tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this;
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::stream_file file(my_context);
* file.open("/path/to/my/file", asio::stream_file::read_only);
* @endcode
*/
void open(const char* path, file_base::flags open_flags)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::stream_file file(my_context);
* asio::error_code ec;
* file.open("/path/to/my/file", asio::stream_file::read_only, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
ASIO_SYNC_OP_VOID open(const char* path,
file_base::flags open_flags, asio::error_code& ec)
{
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::stream_file file(my_context);
* file.open("/path/to/my/file", asio::stream_file::read_only);
* @endcode
*/
void open(const std::string& path, file_base::flags open_flags)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::stream_file file(my_context);
* asio::error_code ec;
* file.open("/path/to/my/file", asio::stream_file::read_only, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
ASIO_SYNC_OP_VOID open(const std::string& path,
file_base::flags open_flags, asio::error_code& ec)
{
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Assign an existing native file to the file.
/*
* This function opens the file to hold an existing native file.
*
* @param native_file A native file.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_file)
{
asio::error_code ec;
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native file to the file.
/*
* This function opens the file to hold an existing native file.
*
* @param native_file A native file.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_file,
asio::error_code& ec)
{
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the file is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the file.
/**
* This function is used to close the file. Any asynchronous read or write
* operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure. Note that, even if
* the function indicates an error, the underlying descriptor is closed.
*/
void close()
{
asio::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}
/// Close the file.
/**
* This function is used to close the file. Any asynchronous read or write
* operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any. Note that, even if
* the function indicates an error, the underlying descriptor is closed.
*
* @par Example
* @code
* asio::stream_file file(my_context);
* ...
* asio::error_code ec;
* file.close(ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Release ownership of the underlying native file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the asio::error::operation_aborted error.
* Ownership of the native file is then transferred to the caller.
*
* @throws asio::system_error Thrown on failure.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with asio::error::operation_not_supported on
* these platforms.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release()
{
asio::error_code ec;
native_handle_type s = impl_.get_service().release(
impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "release");
return s;
}
/// Release ownership of the underlying native file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the asio::error::operation_aborted error.
* Ownership of the native file is then transferred to the caller.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with asio::error::operation_not_supported on
* these platforms.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release(asio::error_code& ec)
{
return impl_.get_service().release(impl_.get_implementation(), ec);
}
/// Get the native file representation.
/**
* This function may be used to obtain the underlying representation of the
* file. This is intended to allow access to native file functionality
* that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*
* @note Calls to cancel() will always fail with
* asio::error::operation_not_supported when run on Windows XP, Windows
* Server 2003, and earlier versions of Windows, unless
* ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
* two issues that should be considered before enabling its use:
*
* @li It will only cancel asynchronous operations that were initiated in the
* current thread.
*
* @li It can appear to complete without error, but the request to cancel the
* unfinished operations may be silently ignored by the operating system.
* Whether it works or not seems to depend on the drivers that are installed.
*
* For portable cancellation, consider using the close() function to
* simultaneously cancel the outstanding operations and close the file.
*
* When running on Windows Vista, Windows Server 2008, and later, the
* CancelIoEx function is always used. This function does not have the
* problems described above.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
&& !defined(ASIO_ENABLE_CANCELIO)
__declspec(deprecated("By default, this function always fails with "
"operation_not_supported when used on Windows XP, Windows Server 2003, "
"or earlier. Consult documentation for details."))
#endif
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note Calls to cancel() will always fail with
* asio::error::operation_not_supported when run on Windows XP, Windows
* Server 2003, and earlier versions of Windows, unless
* ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
* two issues that should be considered before enabling its use:
*
* @li It will only cancel asynchronous operations that were initiated in the
* current thread.
*
* @li It can appear to complete without error, but the request to cancel the
* unfinished operations may be silently ignored by the operating system.
* Whether it works or not seems to depend on the drivers that are installed.
*
* For portable cancellation, consider using the close() function to
* simultaneously cancel the outstanding operations and close the file.
*
* When running on Windows Vista, Windows Server 2008, and later, the
* CancelIoEx function is always used. This function does not have the
* problems described above.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
&& !defined(ASIO_ENABLE_CANCELIO)
__declspec(deprecated("By default, this function always fails with "
"operation_not_supported when used on Windows XP, Windows Server 2003, "
"or earlier. Consult documentation for details."))
#endif
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get the size of the file.
/**
* This function determines the size of the file, in bytes.
*
* @throws asio::system_error Thrown on failure.
*/
uint64_t size() const
{
asio::error_code ec;
uint64_t s = impl_.get_service().size(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "size");
return s;
}
/// Get the size of the file.
/**
* This function determines the size of the file, in bytes.
*
* @param ec Set to indicate what error occurred, if any.
*/
uint64_t size(asio::error_code& ec) const
{
return impl_.get_service().size(impl_.get_implementation(), ec);
}
/// Alter the size of the file.
/**
* This function resizes the file to the specified size, in bytes. If the
* current file size exceeds @c n then any extra data is discarded. If the
* current size is less than @c n then the file is extended and filled with
* zeroes.
*
* @param n The new size for the file.
*
* @throws asio::system_error Thrown on failure.
*/
void resize(uint64_t n)
{
asio::error_code ec;
impl_.get_service().resize(impl_.get_implementation(), n, ec);
asio::detail::throw_error(ec, "resize");
}
/// Alter the size of the file.
/**
* This function resizes the file to the specified size, in bytes. If the
* current file size exceeds @c n then any extra data is discarded. If the
* current size is less than @c n then the file is extended and filled with
* zeroes.
*
* @param n The new size for the file.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID resize(uint64_t n, asio::error_code& ec)
{
impl_.get_service().resize(impl_.get_implementation(), n, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Synchronise the file to disk.
/**
* This function synchronises the file data and metadata to disk. Note that
* the semantics of this synchronisation vary between operation systems.
*
* @throws asio::system_error Thrown on failure.
*/
void sync_all()
{
asio::error_code ec;
impl_.get_service().sync_all(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "sync_all");
}
/// Synchronise the file to disk.
/**
* This function synchronises the file data and metadata to disk. Note that
* the semantics of this synchronisation vary between operation systems.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID sync_all(asio::error_code& ec)
{
impl_.get_service().sync_all(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Synchronise the file data to disk.
/**
* This function synchronises the file data to disk. Note that the semantics
* of this synchronisation vary between operation systems.
*
* @throws asio::system_error Thrown on failure.
*/
void sync_data()
{
asio::error_code ec;
impl_.get_service().sync_data(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "sync_data");
}
/// Synchronise the file data to disk.
/**
* This function synchronises the file data to disk. Note that the semantics
* of this synchronisation vary between operation systems.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID sync_data(asio::error_code& ec)
{
impl_.get_service().sync_data(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
protected:
/// Protected destructor to prevent deletion through this type.
/**
* This function destroys the file, cancelling any outstanding asynchronous
* operations associated with the file as if by calling @c cancel.
*/
~basic_file()
{
}
#if defined(ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_file_service, Executor> impl_;
#elif defined(ASIO_HAS_IO_URING)
detail::io_object_impl<detail::io_uring_file_service, Executor> impl_;
#endif
private:
// Disallow copying and assignment.
basic_file(const basic_file&) = delete;
basic_file& operator=(const basic_file&) = delete;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_FILE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_FILE_HPP

View File

@@ -2,7 +2,7 @@
// basic_io_object.hpp // basic_io_object.hpp
// ~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -22,7 +22,6 @@
namespace asio { namespace asio {
#if defined(ASIO_HAS_MOVE)
namespace detail namespace detail
{ {
// Type trait used to determine whether a service supports move. // Type trait used to determine whether a service supports move.
@@ -45,14 +44,13 @@ namespace detail
static_cast<implementation_type*>(0))) == 1; static_cast<implementation_type*>(0))) == 1;
}; };
} }
#endif // defined(ASIO_HAS_MOVE)
/// Base class for all I/O objects. /// Base class for all I/O objects.
/** /**
* @note All I/O objects are non-copyable. However, when using C++0x, certain * @note All I/O objects are non-copyable. However, when using C++0x, certain
* I/O objects do support move construction and move assignment. * I/O objects do support move construction and move assignment.
*/ */
#if !defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) #if defined(GENERATING_DOCUMENTATION)
template <typename IoObjectService> template <typename IoObjectService>
#else #else
template <typename IoObjectService, template <typename IoObjectService,
@@ -101,7 +99,7 @@ public:
typedef asio::io_context::executor_type executor_type; typedef asio::io_context::executor_type executor_type;
/// Get the executor associated with the object. /// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT executor_type get_executor() noexcept
{ {
return service_.get_io_context().get_executor(); return service_.get_io_context().get_executor();
} }
@@ -190,7 +188,6 @@ private:
implementation_type implementation_; implementation_type implementation_;
}; };
#if defined(ASIO_HAS_MOVE)
// Specialisation for movable objects. // Specialisation for movable objects.
template <typename IoObjectService> template <typename IoObjectService>
class basic_io_object<IoObjectService, true> class basic_io_object<IoObjectService, true>
@@ -213,7 +210,7 @@ public:
typedef asio::io_context::executor_type executor_type; typedef asio::io_context::executor_type executor_type;
executor_type get_executor() ASIO_NOEXCEPT executor_type get_executor() noexcept
{ {
return service_->get_io_context().get_executor(); return service_->get_io_context().get_executor();
} }
@@ -281,7 +278,6 @@ private:
IoObjectService* service_; IoObjectService* service_;
implementation_type implementation_; implementation_type implementation_;
}; };
#endif // defined(ASIO_HAS_MOVE)
} // namespace asio } // namespace asio

View File

@@ -0,0 +1,689 @@
//
// basic_random_access_file.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 ASIO_BASIC_RANDOM_ACCESS_FILE_HPP
#define ASIO_BASIC_RANDOM_ACCESS_FILE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_FILE) \
|| defined(GENERATING_DOCUMENTATION)
#include <cstddef>
#include "asio/async_result.hpp"
#include "asio/basic_file.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
#if !defined(ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL)
#define ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Executor = any_io_executor>
class basic_random_access_file;
#endif // !defined(ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL)
/// Provides random-access file functionality.
/**
* The basic_random_access_file class template provides asynchronous and
* blocking random-access file functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* Synchronous @c read_some_at and @c write_some_at operations are thread safe
* with respect to each other, if the underlying operating system calls are
* also thread safe. This means that it is permitted to perform concurrent
* calls to these synchronous operations on a single file object. Other
* synchronous operations, such as @c open or @c close, are not thread safe.
*/
template <typename Executor>
class basic_random_access_file
: public basic_file<Executor>
{
private:
class initiate_async_write_some_at;
class initiate_async_read_some_at;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the file type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The file type when rebound to the specified executor.
typedef basic_random_access_file<Executor1> other;
};
/// The native representation of a file.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_file<Executor>::native_handle_type native_handle_type;
#endif
/// Construct a basic_random_access_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*/
explicit basic_random_access_file(const executor_type& ex)
: basic_file<Executor>(ex)
{
}
/// Construct a basic_random_access_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*/
template <typename ExecutionContext>
explicit basic_random_access_file(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
basic_random_access_file(const executor_type& ex,
const char* path, file_base::flags open_flags)
: basic_file<Executor>(ex, path, open_flags)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_random_access_file(ExecutionContext& context,
const char* path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context, path, open_flags)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
basic_random_access_file(const executor_type& ex,
const std::string& path, file_base::flags open_flags)
: basic_file<Executor>(ex, path, open_flags)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_random_access_file(ExecutionContext& context,
const std::string& path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context, path, open_flags)
{
}
/// Construct a basic_random_access_file on an existing native file.
/**
* This constructor initialises a random-access file object to hold an
* existing native file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_random_access_file(const executor_type& ex,
const native_handle_type& native_file)
: basic_file<Executor>(ex, native_file)
{
}
/// Construct a basic_random_access_file on an existing native file.
/**
* This constructor initialises a random-access file object to hold an
* existing native file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_random_access_file(ExecutionContext& context,
const native_handle_type& native_file,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context, native_file)
{
}
/// Move-construct a basic_random_access_file from another.
/**
* This constructor moves a random-access file from one object to another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
basic_random_access_file(basic_random_access_file&& other) noexcept
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_random_access_file from another.
/**
* This assignment operator moves a random-access file from one object to
* another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
basic_random_access_file& operator=(basic_random_access_file&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
/// Move-construct a basic_random_access_file from a file of another executor
/// type.
/**
* This constructor moves a random-access file from one object to another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_random_access_file(basic_random_access_file<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_random_access_file from a file of another executor
/// type.
/**
* This assignment operator moves a random-access file from one object to
* another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_random_access_file&
> operator=(basic_random_access_file<Executor1>&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
/// Destroys the file.
/**
* This function destroys the file, cancelling any outstanding asynchronous
* operations associated with the file as if by calling @c cancel.
*/
~basic_random_access_file()
{
}
/// Write some data to the handle at the specified offset.
/**
* This function is used to write data to the random-access handle. The
* function call will block until one or more bytes of the data has been
* written successfully, or until an error occurs.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the end of the file was reached.
*
* @note The write_some_at operation may not write all of the data. Consider
* using the @ref write_at function if you need to ensure that all data is
* written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* handle.write_some_at(42, asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some_at(uint64_t offset,
const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().write_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
asio::detail::throw_error(ec, "write_some_at");
return s;
}
/// Write some data to the handle at the specified offset.
/**
* This function is used to write data to the random-access handle. The
* function call will block until one or more bytes of the data has been
* written successfully, or until an error occurs.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not write all of the data to the
* file. Consider using the @ref write_at function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some_at(uint64_t offset,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
return this->impl_.get_service().write_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
}
/// Start an asynchronous write at the specified offset.
/**
* This function is used to asynchronously write data to the random-access
* handle. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The write operation may not write all of the data to the file.
* Consider using the @ref async_write_at function if you need to ensure that
* all data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* handle.async_write_some_at(42, asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteToken = default_completion_token_t<executor_type>>
auto async_write_some_at(uint64_t offset, const ConstBufferSequence& buffers,
WriteToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
declval<initiate_async_write_some_at>(), token, offset, buffers))
{
return async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
initiate_async_write_some_at(this), token, offset, buffers);
}
/// Read some data from the handle at the specified offset.
/**
* This function is used to read data from the random-access handle. The
* function call will block until one or more bytes of data has been read
* successfully, or until an error occurs.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the end of the file was reached.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read_at function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* handle.read_some_at(42, asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some_at(uint64_t offset,
const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().read_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
asio::detail::throw_error(ec, "read_some_at");
return s;
}
/// Read some data from the handle at the specified offset.
/**
* This function is used to read data from the random-access handle. The
* function call will block until one or more bytes of data has been read
* successfully, or until an error occurs.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read_at function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some_at(uint64_t offset,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
return this->impl_.get_service().read_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
}
/// Start an asynchronous read at the specified offset.
/**
* This function is used to asynchronously read data from the random-access
* handle. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read_at function if you need to ensure that
* the requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* handle.async_read_some_at(42, asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadToken = default_completion_token_t<executor_type>>
auto async_read_some_at(uint64_t offset, const MutableBufferSequence& buffers,
ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
declval<initiate_async_read_some_at>(), token, offset, buffers))
{
return async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
initiate_async_read_some_at(this), token, offset, buffers);
}
private:
// Disallow copying and assignment.
basic_random_access_file(const basic_random_access_file&) = delete;
basic_random_access_file& operator=(
const basic_random_access_file&) = delete;
class initiate_async_write_some_at
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some_at(basic_random_access_file* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(WriteHandler&& handler,
uint64_t offset, const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some_at(
self_->impl_.get_implementation(), offset, buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_random_access_file* self_;
};
class initiate_async_read_some_at
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some_at(basic_random_access_file* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ReadHandler&& handler,
uint64_t offset, const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_read_some_at(
self_->impl_.get_implementation(), offset, buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_random_access_file* self_;
};
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_FILE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_RANDOM_ACCESS_FILE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,626 @@
//
// basic_readable_pipe.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 ASIO_BASIC_READABLE_PIPE_HPP
#define ASIO_BASIC_READABLE_PIPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_PIPE) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include <utility>
#include "asio/any_io_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_handle_service.hpp"
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
# include "asio/detail/io_uring_descriptor_service.hpp"
#else
# include "asio/detail/reactive_descriptor_service.hpp"
#endif
#include "asio/detail/push_options.hpp"
namespace asio {
/// Provides pipe functionality.
/**
* The basic_readable_pipe class provides a wrapper over pipe
* functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor = any_io_executor>
class basic_readable_pipe
{
private:
class initiate_async_read_some;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the pipe type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The pipe type when rebound to the specified executor.
typedef basic_readable_pipe<Executor1> other;
};
/// The native representation of a pipe.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_handle_service::native_handle_type
native_handle_type;
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
typedef detail::io_uring_descriptor_service::native_handle_type
native_handle_type;
#else
typedef detail::reactive_descriptor_service::native_handle_type
native_handle_type;
#endif
/// A basic_readable_pipe is always the lowest layer.
typedef basic_readable_pipe lowest_layer_type;
/// Construct a basic_readable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param ex The I/O executor that the pipe will use, by default, to dispatch
* handlers for any asynchronous operations performed on the pipe.
*/
explicit basic_readable_pipe(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a basic_readable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any asynchronous
* operations performed on the pipe.
*/
template <typename ExecutionContext>
explicit basic_readable_pipe(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct a basic_readable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param ex The I/O executor that the pipe will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
basic_readable_pipe(const executor_type& ex,
const native_handle_type& native_pipe)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_readable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any
* asynchronous operations performed on the pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_readable_pipe(ExecutionContext& context,
const native_handle_type& native_pipe,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
/// Move-construct a basic_readable_pipe from another.
/**
* This constructor moves a pipe from one object to another.
*
* @param other The other basic_readable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_readable_pipe(const executor_type&)
* constructor.
*/
basic_readable_pipe(basic_readable_pipe&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_readable_pipe from another.
/**
* This assignment operator moves a pipe from one object to another.
*
* @param other The other basic_readable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_readable_pipe(const executor_type&)
* constructor.
*/
basic_readable_pipe& operator=(basic_readable_pipe&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
// All pipes have access to each other's implementations.
template <typename Executor1>
friend class basic_readable_pipe;
/// Move-construct a basic_readable_pipe from a pipe of another executor type.
/**
* This constructor moves a pipe from one object to another.
*
* @param other The other basic_readable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_readable_pipe(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_readable_pipe(basic_readable_pipe<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_readable_pipe from a pipe of another executor type.
/**
* This assignment operator moves a pipe from one object to another.
*
* @param other The other basic_readable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_readable_pipe(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_readable_pipe&
> operator=(basic_readable_pipe<Executor1>&& other)
{
basic_readable_pipe tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this;
}
/// Destroys the pipe.
/**
* This function destroys the pipe, cancelling any outstanding
* asynchronous wait operations associated with the pipe as if by
* calling @c cancel.
*/
~basic_readable_pipe()
{
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_readable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_readable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_pipe)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_pipe,
asio::error_code& ec)
{
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the pipe is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous read operations
* will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void close()
{
asio::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous read operations
* will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Release ownership of the underlying native pipe.
/**
* This function causes all outstanding asynchronous read operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error. Ownership of the
* native pipe is then transferred to the caller.
*
* @throws asio::system_error Thrown on failure.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with asio::error::operation_not_supported on
* these platforms.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release()
{
asio::error_code ec;
native_handle_type s = impl_.get_service().release(
impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "release");
return s;
}
/// Release ownership of the underlying native pipe.
/**
* This function causes all outstanding asynchronous read operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error. Ownership of the
* native pipe is then transferred to the caller.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with asio::error::operation_not_supported on
* these platforms.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release(asio::error_code& ec)
{
return impl_.get_service().release(impl_.get_implementation(), ec);
}
/// Get the native pipe representation.
/**
* This function may be used to obtain the underlying representation of the
* pipe. This is intended to allow access to native pipe
* functionality that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous read operations to finish
* immediately, and the handlers for cancelled operations will be passed the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous read operations to finish
* immediately, and the handlers for cancelled operations will be passed the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Read some data from the pipe.
/**
* This function is used to read data from the pipe. The function call will
* block until one or more bytes of data has been read successfully, or until
* an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_readable_pipe.read_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "read_some");
return s;
}
/// Read some data from the pipe.
/**
* This function is used to read data from the pipe. The function call will
* block until one or more bytes of data has been read successfully, or until
* an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the pipe. It is an
* initiating function for an @ref asynchronous_operation, and always returns
* immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_readable_pipe.async_read_some(
* asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadToken = default_completion_token_t<executor_type>>
auto async_read_some(const MutableBufferSequence& buffers,
ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
declval<initiate_async_read_some>(), token, buffers))
{
return async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
initiate_async_read_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_readable_pipe(const basic_readable_pipe&) = delete;
basic_readable_pipe& operator=(const basic_readable_pipe&) = delete;
class initiate_async_read_some
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some(basic_readable_pipe* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ReadHandler&& handler,
const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_read_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_readable_pipe* self_;
};
#if defined(ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_handle_service, Executor> impl_;
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_;
#else
detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;
#endif
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_PIPE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_READABLE_PIPE_HPP

View File

@@ -2,7 +2,7 @@
// basic_seq_packet_socket.hpp // basic_seq_packet_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -22,14 +22,19 @@
#include "asio/detail/throw_error.hpp" #include "asio/detail/throw_error.hpp"
#include "asio/error.hpp" #include "asio/error.hpp"
#if defined(ASIO_ENABLE_OLD_SERVICES)
# include "asio/seq_packet_socket_service.hpp"
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
namespace asio { namespace asio {
#if !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
#define ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = any_io_executor>
class basic_seq_packet_socket;
#endif // !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
/// Provides sequenced packet socket functionality. /// Provides sequenced packet socket functionality.
/** /**
* The basic_seq_packet_socket class template provides asynchronous and blocking * The basic_seq_packet_socket class template provides asynchronous and blocking
@@ -38,19 +43,40 @@ namespace asio {
* @par Thread Safety * @par Thread Safety
* @e Distinct @e objects: Safe.@n * @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe. * @e Shared @e objects: Unsafe.
*
* Synchronous @c send, @c receive, @c connect, and @c shutdown operations are
* thread safe with respect to each other, if the underlying operating system
* calls are also thread safe. This means that it is permitted to perform
* concurrent calls to these synchronous operations on a single socket object.
* Other synchronous operations, such as @c open or @c close, are not thread
* safe.
*/ */
template <typename Protocol template <typename Protocol, typename Executor>
ASIO_SVC_TPARAM_DEF1(= seq_packet_socket_service<Protocol>)>
class basic_seq_packet_socket class basic_seq_packet_socket
: public basic_socket<Protocol ASIO_SVC_TARG> : public basic_socket<Protocol, Executor>
{ {
private:
class initiate_async_send;
class initiate_async_receive_with_flags;
public: public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_seq_packet_socket<Protocol, Executor1> other;
};
/// The native representation of a socket. /// The native representation of a socket.
#if defined(GENERATING_DOCUMENTATION) #if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type; typedef implementation_defined native_handle_type;
#else #else
typedef typename basic_socket< typedef typename basic_socket<Protocol,
Protocol ASIO_SVC_TARG>::native_handle_type native_handle_type; Executor>::native_handle_type native_handle_type;
#endif #endif
/// The protocol type. /// The protocol type.
@@ -65,12 +91,30 @@ public:
* socket needs to be opened and then connected or accepted before data can * socket needs to be opened and then connected or accepted before data can
* be sent or received on it. * be sent or received on it.
* *
* @param io_context The io_context object that the sequenced packet socket * @param ex The I/O executor that the socket will use, by default, to
* will use to dispatch handlers for any asynchronous operations performed on * dispatch handlers for any asynchronous operations performed on the socket.
* the socket.
*/ */
explicit basic_seq_packet_socket(asio::io_context& io_context) explicit basic_seq_packet_socket(const executor_type& ex)
: basic_socket<Protocol ASIO_SVC_TARG>(io_context) : basic_socket<Protocol, Executor>(ex)
{
}
/// Construct a basic_seq_packet_socket without opening it.
/**
* This constructor creates a sequenced packet socket without opening it. The
* socket needs to be opened and then connected or accepted before data can
* be sent or received on it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
template <typename ExecutionContext>
explicit basic_seq_packet_socket(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: basic_socket<Protocol, Executor>(context)
{ {
} }
@@ -80,17 +124,41 @@ public:
* needs to be connected or accepted before data can be sent or received on * needs to be connected or accepted before data can be sent or received on
* it. * it.
* *
* @param io_context The io_context object that the sequenced packet socket * @param ex The I/O executor that the socket will use, by default, to
* will use to dispatch handlers for any asynchronous operations performed on * dispatch handlers for any asynchronous operations performed on the socket.
* the socket.
* *
* @param protocol An object specifying protocol parameters to be used. * @param protocol An object specifying protocol parameters to be used.
* *
* @throws asio::system_error Thrown on failure. * @throws asio::system_error Thrown on failure.
*/ */
basic_seq_packet_socket(asio::io_context& io_context, basic_seq_packet_socket(const executor_type& ex,
const protocol_type& protocol) const protocol_type& protocol)
: basic_socket<Protocol ASIO_SVC_TARG>(io_context, protocol) : basic_socket<Protocol, Executor>(ex, protocol)
{
}
/// Construct and open a basic_seq_packet_socket.
/**
* This constructor creates and opens a sequenced_packet socket. The socket
* needs to be connected or accepted before data can be sent or received on
* it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const protocol_type& protocol,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_socket<Protocol, Executor>(context, protocol)
{ {
} }
@@ -101,18 +169,43 @@ public:
* it bound to the specified endpoint on the local machine. The protocol used * it bound to the specified endpoint on the local machine. The protocol used
* is the protocol associated with the given endpoint. * is the protocol associated with the given endpoint.
* *
* @param io_context The io_context object that the sequenced packet socket * @param ex The I/O executor that the socket will use, by default, to
* will use to dispatch handlers for any asynchronous operations performed on * dispatch handlers for any asynchronous operations performed on the socket.
* the socket.
* *
* @param endpoint An endpoint on the local machine to which the sequenced * @param endpoint An endpoint on the local machine to which the sequenced
* packet socket will be bound. * packet socket will be bound.
* *
* @throws asio::system_error Thrown on failure. * @throws asio::system_error Thrown on failure.
*/ */
basic_seq_packet_socket(asio::io_context& io_context, basic_seq_packet_socket(const executor_type& ex,
const endpoint_type& endpoint) const endpoint_type& endpoint)
: basic_socket<Protocol ASIO_SVC_TARG>(io_context, endpoint) : basic_socket<Protocol, Executor>(ex, endpoint)
{
}
/// Construct a basic_seq_packet_socket, opening it and binding it to the
/// given local endpoint.
/**
* This constructor creates a sequenced packet socket and automatically opens
* it bound to the specified endpoint on the local machine. The protocol used
* is the protocol associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the sequenced
* packet socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const endpoint_type& endpoint,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: basic_socket<Protocol, Executor>(context, endpoint)
{ {
} }
@@ -121,9 +214,8 @@ public:
* This constructor creates a sequenced packet socket object to hold an * This constructor creates a sequenced packet socket object to hold an
* existing native socket. * existing native socket.
* *
* @param io_context The io_context object that the sequenced packet socket * @param ex The I/O executor that the socket will use, by default, to
* will use to dispatch handlers for any asynchronous operations performed on * dispatch handlers for any asynchronous operations performed on the socket.
* the socket.
* *
* @param protocol An object specifying protocol parameters to be used. * @param protocol An object specifying protocol parameters to be used.
* *
@@ -131,14 +223,37 @@ public:
* *
* @throws asio::system_error Thrown on failure. * @throws asio::system_error Thrown on failure.
*/ */
basic_seq_packet_socket(asio::io_context& io_context, basic_seq_packet_socket(const executor_type& ex,
const protocol_type& protocol, const native_handle_type& native_socket) const protocol_type& protocol, const native_handle_type& native_socket)
: basic_socket<Protocol ASIO_SVC_TARG>( : basic_socket<Protocol, Executor>(ex, protocol, native_socket)
io_context, protocol, native_socket) {
}
/// Construct a basic_seq_packet_socket on an existing native socket.
/**
* This constructor creates a sequenced packet socket object to hold an
* existing native socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const protocol_type& protocol, const native_handle_type& native_socket,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: basic_socket<Protocol, Executor>(context, protocol, native_socket)
{ {
} }
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_seq_packet_socket from another. /// Move-construct a basic_seq_packet_socket from another.
/** /**
* This constructor moves a sequenced packet socket from one object to * This constructor moves a sequenced packet socket from one object to
@@ -148,10 +263,11 @@ public:
* will occur. * will occur.
* *
* @note Following the move, the moved-from object is in the same state as if * @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor. * constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/ */
basic_seq_packet_socket(basic_seq_packet_socket&& other) basic_seq_packet_socket(basic_seq_packet_socket&& other) noexcept
: basic_socket<Protocol ASIO_SVC_TARG>(std::move(other)) : basic_socket<Protocol, Executor>(std::move(other))
{ {
} }
@@ -164,11 +280,12 @@ public:
* will occur. * will occur.
* *
* @note Following the move, the moved-from object is in the same state as if * @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor. * constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/ */
basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other) basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other)
{ {
basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other)); basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this; return *this;
} }
@@ -182,13 +299,16 @@ public:
* will occur. * will occur.
* *
* @note Following the move, the moved-from object is in the same state as if * @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor. * constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/ */
template <typename Protocol1 ASIO_SVC_TPARAM1> template <typename Protocol1, typename Executor1>
basic_seq_packet_socket( basic_seq_packet_socket(basic_seq_packet_socket<Protocol1, Executor1>&& other,
basic_seq_packet_socket<Protocol1 ASIO_SVC_TARG1>&& other, constraint_t<
typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) is_convertible<Protocol1, Protocol>::value
: basic_socket<Protocol ASIO_SVC_TARG>(std::move(other)) && is_convertible<Executor1, Executor>::value
> = 0)
: basic_socket<Protocol, Executor>(std::move(other))
{ {
} }
@@ -202,17 +322,19 @@ public:
* will occur. * will occur.
* *
* @note Following the move, the moved-from object is in the same state as if * @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor. * constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/ */
template <typename Protocol1 ASIO_SVC_TPARAM1> template <typename Protocol1, typename Executor1>
typename enable_if<is_convertible<Protocol1, Protocol>::value, constraint_t<
basic_seq_packet_socket>::type& operator=( is_convertible<Protocol1, Protocol>::value
basic_seq_packet_socket<Protocol1 ASIO_SVC_TARG1>&& other) && is_convertible<Executor1, Executor>::value,
basic_seq_packet_socket&
> operator=(basic_seq_packet_socket<Protocol1, Executor1>&& other)
{ {
basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other)); basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this; return *this;
} }
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the socket. /// Destroys the socket.
/** /**
@@ -251,8 +373,8 @@ public:
socket_base::message_flags flags) socket_base::message_flags flags)
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().send( std::size_t s = this->impl_.get_service().send(
this->get_implementation(), buffers, flags, ec); this->impl_.get_implementation(), buffers, flags, ec);
asio::detail::throw_error(ec, "send"); asio::detail::throw_error(ec, "send");
return s; return s;
} }
@@ -279,33 +401,39 @@ public:
std::size_t send(const ConstBufferSequence& buffers, std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec) socket_base::message_flags flags, asio::error_code& ec)
{ {
return this->get_service().send( return this->impl_.get_service().send(
this->get_implementation(), buffers, flags, ec); this->impl_.get_implementation(), buffers, flags, ec);
} }
/// Start an asynchronous send. /// Start an asynchronous send.
/** /**
* This function is used to asynchronously send data on the sequenced packet * This function is used to asynchronously send data on the sequenced packet
* socket. The function call always returns immediately. * socket. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
* *
* @param buffers One or more data buffers to be sent on the socket. Although * @param buffers One or more data buffers to be sent on the socket. Although
* the buffers object may be copied as necessary, ownership of the underlying * the buffers object may be copied as necessary, ownership of the underlying
* memory blocks is retained by the caller, which must guarantee that they * memory blocks is retained by the caller, which must guarantee that they
* remain valid until the handler is called. * remain valid until the completion handler is called.
* *
* @param flags Flags specifying how the send call is to be made. * @param flags Flags specifying how the send call is to be made.
* *
* @param handler The handler to be called when the send operation completes. * @param token The @ref completion_token that will be used to produce a
* Copies will be made of the handler as required. The function signature of * completion handler, which will be called when the send completes.
* the handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* const asio::error_code& error, // Result of operation. * const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent. * std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
* *
* @par Example * @par Example
* To send a single data buffer use the @ref buffer function as follows: * To send a single data buffer use the @ref buffer function as follows:
@@ -315,30 +443,33 @@ public:
* See the @ref buffer documentation for information on sending multiple * See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or * buffers in one go, and how to use it with arrays, boost::array or
* std::vector. * std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/ */
template <typename ConstBufferSequence, typename WriteHandler> template <typename ConstBufferSequence,
ASIO_INITFN_RESULT_TYPE(WriteHandler, ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
void (asio::error_code, std::size_t)) std::size_t)) WriteToken
async_send(const ConstBufferSequence& buffers, = default_completion_token_t<executor_type>>
auto async_send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, socket_base::message_flags flags,
ASIO_MOVE_ARG(WriteHandler) handler) WriteToken&& token
= default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
declval<initiate_async_send>(), token, buffers, flags))
{ {
// If you get an error on the following line it means that your handler does return async_initiate<WriteToken,
// not meet the documented type requirements for a WriteHandler. void (asio::error_code, std::size_t)>(
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; initiate_async_send(this), token, buffers, flags);
#if defined(ASIO_ENABLE_OLD_SERVICES)
return this->get_service().async_send(this->get_implementation(),
buffers, flags, ASIO_MOVE_CAST(WriteHandler)(handler));
#else // defined(ASIO_ENABLE_OLD_SERVICES)
async_completion<WriteHandler,
void (asio::error_code, std::size_t)> init(handler);
this->get_service().async_send(this->get_implementation(),
buffers, flags, init.completion_handler);
return init.result.get();
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
} }
/// Receive some data on the socket. /// Receive some data on the socket.
@@ -375,13 +506,8 @@ public:
socket_base::message_flags& out_flags) socket_base::message_flags& out_flags)
{ {
asio::error_code ec; asio::error_code ec;
#if defined(ASIO_ENABLE_OLD_SERVICES) std::size_t s = this->impl_.get_service().receive_with_flags(
std::size_t s = this->get_service().receive( this->impl_.get_implementation(), buffers, 0, out_flags, ec);
this->get_implementation(), buffers, 0, out_flags, ec);
#else // defined(ASIO_ENABLE_OLD_SERVICES)
std::size_t s = this->get_service().receive_with_flags(
this->get_implementation(), buffers, 0, out_flags, ec);
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
asio::detail::throw_error(ec, "receive"); asio::detail::throw_error(ec, "receive");
return s; return s;
} }
@@ -427,13 +553,8 @@ public:
socket_base::message_flags& out_flags) socket_base::message_flags& out_flags)
{ {
asio::error_code ec; asio::error_code ec;
#if defined(ASIO_ENABLE_OLD_SERVICES) std::size_t s = this->impl_.get_service().receive_with_flags(
std::size_t s = this->get_service().receive( this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);
this->get_implementation(), buffers, in_flags, out_flags, ec);
#else // defined(ASIO_ENABLE_OLD_SERVICES)
std::size_t s = this->get_service().receive_with_flags(
this->get_implementation(), buffers, in_flags, out_flags, ec);
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
asio::detail::throw_error(ec, "receive"); asio::detail::throw_error(ec, "receive");
return s; return s;
} }
@@ -466,42 +587,43 @@ public:
socket_base::message_flags in_flags, socket_base::message_flags in_flags,
socket_base::message_flags& out_flags, asio::error_code& ec) socket_base::message_flags& out_flags, asio::error_code& ec)
{ {
#if defined(ASIO_ENABLE_OLD_SERVICES) return this->impl_.get_service().receive_with_flags(
return this->get_service().receive(this->get_implementation(), this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);
buffers, in_flags, out_flags, ec);
#else // defined(ASIO_ENABLE_OLD_SERVICES)
return this->get_service().receive_with_flags(this->get_implementation(),
buffers, in_flags, out_flags, ec);
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
} }
/// Start an asynchronous receive. /// Start an asynchronous receive.
/** /**
* This function is used to asynchronously receive data from the sequenced * This function is used to asynchronously receive data from the sequenced
* packet socket. The function call always returns immediately. * packet socket. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
* *
* @param buffers One or more buffers into which the data will be received. * @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the * Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee * underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called. * that they remain valid until the completion handler is called.
* *
* @param out_flags Once the asynchronous operation completes, contains flags * @param out_flags Once the asynchronous operation completes, contains flags
* associated with the received data. For example, if the * associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks * socket_base::message_end_of_record bit is set then the received data marks
* the end of a record. The caller must guarantee that the referenced * the end of a record. The caller must guarantee that the referenced
* variable remains valid until the handler is called. * variable remains valid until the completion handler is called.
* *
* @param handler The handler to be called when the receive operation * @param token The @ref completion_token that will be used to produce a
* completes. Copies will be made of the handler as required. The function * completion handler, which will be called when the receive completes.
* signature of the handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* const asio::error_code& error, // Result of operation. * const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received. * std::size_t bytes_transferred // Number of bytes received.
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
* *
* @par Example * @par Example
* To receive into a single data buffer use the @ref buffer function as * To receive into a single data buffer use the @ref buffer function as
@@ -512,43 +634,45 @@ public:
* See the @ref buffer documentation for information on receiving into * See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or * multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector. * std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/ */
template <typename MutableBufferSequence, typename ReadHandler> template <typename MutableBufferSequence,
ASIO_INITFN_RESULT_TYPE(ReadHandler, ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
void (asio::error_code, std::size_t)) std::size_t)) ReadToken = default_completion_token_t<executor_type>>
async_receive(const MutableBufferSequence& buffers, auto async_receive(const MutableBufferSequence& buffers,
socket_base::message_flags& out_flags, socket_base::message_flags& out_flags,
ASIO_MOVE_ARG(ReadHandler) handler) ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
declval<initiate_async_receive_with_flags>(), token,
buffers, socket_base::message_flags(0), &out_flags))
{ {
// If you get an error on the following line it means that your handler does return async_initiate<ReadToken,
// not meet the documented type requirements for a ReadHandler. void (asio::error_code, std::size_t)>(
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; initiate_async_receive_with_flags(this), token,
buffers, socket_base::message_flags(0), &out_flags);
#if defined(ASIO_ENABLE_OLD_SERVICES)
return this->get_service().async_receive(
this->get_implementation(), buffers, 0, out_flags,
ASIO_MOVE_CAST(ReadHandler)(handler));
#else // defined(ASIO_ENABLE_OLD_SERVICES)
async_completion<ReadHandler,
void (asio::error_code, std::size_t)> init(handler);
this->get_service().async_receive_with_flags(
this->get_implementation(), buffers, 0, out_flags,
init.completion_handler);
return init.result.get();
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
} }
/// Start an asynchronous receive. /// Start an asynchronous receive.
/** /**
* This function is used to asynchronously receive data from the sequenced * This function is used to asynchronously receive data from the sequenced
* data socket. The function call always returns immediately. * data socket. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
* *
* @param buffers One or more buffers into which the data will be received. * @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the * Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee * underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called. * that they remain valid until the completion handler is called.
* *
* @param in_flags Flags specifying how the receive call is to be made. * @param in_flags Flags specifying how the receive call is to be made.
* *
@@ -556,19 +680,24 @@ public:
* associated with the received data. For example, if the * associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks * socket_base::message_end_of_record bit is set then the received data marks
* the end of a record. The caller must guarantee that the referenced * the end of a record. The caller must guarantee that the referenced
* variable remains valid until the handler is called. * variable remains valid until the completion handler is called.
* *
* @param handler The handler to be called when the receive operation * @param token The @ref completion_token that will be used to produce a
* completes. Copies will be made of the handler as required. The function * completion handler, which will be called when the receive completes.
* signature of the handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* const asio::error_code& error, // Result of operation. * const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received. * std::size_t bytes_transferred // Number of bytes received.
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
* *
* @par Example * @par Example
* To receive into a single data buffer use the @ref buffer function as * To receive into a single data buffer use the @ref buffer function as
@@ -581,34 +710,110 @@ public:
* See the @ref buffer documentation for information on receiving into * See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or * multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector. * std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/ */
template <typename MutableBufferSequence, typename ReadHandler> template <typename MutableBufferSequence,
ASIO_INITFN_RESULT_TYPE(ReadHandler, ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
void (asio::error_code, std::size_t)) std::size_t)) ReadToken = default_completion_token_t<executor_type>>
async_receive(const MutableBufferSequence& buffers, auto async_receive(const MutableBufferSequence& buffers,
socket_base::message_flags in_flags, socket_base::message_flags in_flags,
socket_base::message_flags& out_flags, socket_base::message_flags& out_flags,
ASIO_MOVE_ARG(ReadHandler) handler) ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
declval<initiate_async_receive_with_flags>(),
token, buffers, in_flags, &out_flags))
{ {
// If you get an error on the following line it means that your handler does return async_initiate<ReadToken,
// not meet the documented type requirements for a ReadHandler. void (asio::error_code, std::size_t)>(
initiate_async_receive_with_flags(this),
token, buffers, in_flags, &out_flags);
}
private:
// Disallow copying and assignment.
basic_seq_packet_socket(const basic_seq_packet_socket&) = delete;
basic_seq_packet_socket& operator=(
const basic_seq_packet_socket&) = delete;
class initiate_async_send
{
public:
typedef Executor executor_type;
explicit initiate_async_send(basic_seq_packet_socket* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(WriteHandler&& handler,
const ConstBufferSequence& buffers,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_send(
self_->impl_.get_implementation(), buffers, flags,
handler2.value, self_->impl_.get_executor());
}
private:
basic_seq_packet_socket* self_;
};
class initiate_async_receive_with_flags
{
public:
typedef Executor executor_type;
explicit initiate_async_receive_with_flags(basic_seq_packet_socket* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ReadHandler&& handler,
const MutableBufferSequence& buffers,
socket_base::message_flags in_flags,
socket_base::message_flags* out_flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
#if defined(ASIO_ENABLE_OLD_SERVICES) detail::non_const_lvalue<ReadHandler> handler2(handler);
return this->get_service().async_receive( self_->impl_.get_service().async_receive_with_flags(
this->get_implementation(), buffers, in_flags, out_flags, self_->impl_.get_implementation(), buffers, in_flags,
ASIO_MOVE_CAST(ReadHandler)(handler)); *out_flags, handler2.value, self_->impl_.get_executor());
#else // defined(ASIO_ENABLE_OLD_SERVICES)
async_completion<ReadHandler,
void (asio::error_code, std::size_t)> init(handler);
this->get_service().async_receive_with_flags(
this->get_implementation(), buffers, in_flags, out_flags,
init.completion_handler);
return init.result.get();
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
} }
private:
basic_seq_packet_socket* self_;
};
}; };
} // namespace asio } // namespace asio

View File

@@ -2,7 +2,7 @@
// basic_serial_port.hpp // basic_serial_port.hpp
// ~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -18,18 +18,26 @@
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#if defined(ASIO_ENABLE_OLD_SERVICES)
#if defined(ASIO_HAS_SERIAL_PORT) \ #if defined(ASIO_HAS_SERIAL_PORT) \
|| defined(GENERATING_DOCUMENTATION) || defined(GENERATING_DOCUMENTATION)
#include <string> #include <string>
#include "asio/basic_io_object.hpp" #include <utility>
#include "asio/any_io_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp" #include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp" #include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp" #include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/serial_port_base.hpp" #include "asio/serial_port_base.hpp"
#include "asio/serial_port_service.hpp" #if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_serial_port_service.hpp"
#else
# include "asio/detail/posix_serial_port_service.hpp"
#endif
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
@@ -37,34 +45,75 @@ namespace asio {
/// Provides serial port functionality. /// Provides serial port functionality.
/** /**
* The basic_serial_port class template provides functionality that is common * The basic_serial_port class provides a wrapper over serial port
* to all serial ports. * functionality.
* *
* @par Thread Safety * @par Thread Safety
* @e Distinct @e objects: Safe.@n * @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe. * @e Shared @e objects: Unsafe.
*/ */
template <typename SerialPortService = serial_port_service> template <typename Executor = any_io_executor>
class basic_serial_port class basic_serial_port
: public basic_io_object<SerialPortService>, : public serial_port_base
public serial_port_base
{ {
public: private:
/// The native representation of a serial port. class initiate_async_write_some;
typedef typename SerialPortService::native_handle_type native_handle_type; class initiate_async_read_some;
/// A basic_serial_port is always the lowest layer. public:
typedef basic_serial_port<SerialPortService> lowest_layer_type; /// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the serial port type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The serial port type when rebound to the specified executor.
typedef basic_serial_port<Executor1> other;
};
/// The native representation of a serial port.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_serial_port_service::native_handle_type
native_handle_type;
#else
typedef detail::posix_serial_port_service::native_handle_type
native_handle_type;
#endif
/// A basic_basic_serial_port is always the lowest layer.
typedef basic_serial_port lowest_layer_type;
/// Construct a basic_serial_port without opening it. /// Construct a basic_serial_port without opening it.
/** /**
* This constructor creates a serial port without opening it. * This constructor creates a serial port without opening it.
* *
* @param io_context The io_context object that the serial port will use to * @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the port. * dispatch handlers for any asynchronous operations performed on the
* serial port.
*/ */
explicit basic_serial_port(asio::io_context& io_context) explicit basic_serial_port(const executor_type& ex)
: basic_io_object<SerialPortService>(io_context) : impl_(0, ex)
{
}
/// Construct a basic_serial_port without opening it.
/**
* This constructor creates a serial port without opening it.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*/
template <typename ExecutionContext>
explicit basic_serial_port(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{ {
} }
@@ -73,18 +122,18 @@ public:
* This constructor creates and opens a serial port for the specified device * This constructor creates and opens a serial port for the specified device
* name. * name.
* *
* @param io_context The io_context object that the serial port will use to * @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the port. * dispatch handlers for any asynchronous operations performed on the
* serial port.
* *
* @param device The platform-specific device name for this serial * @param device The platform-specific device name for this serial
* port. * port.
*/ */
explicit basic_serial_port(asio::io_context& io_context, basic_serial_port(const executor_type& ex, const char* device)
const char* device) : impl_(0, ex)
: basic_io_object<SerialPortService>(io_context)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().open(this->get_implementation(), device, ec); impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open"); asio::detail::throw_error(ec, "open");
} }
@@ -93,18 +142,66 @@ public:
* This constructor creates and opens a serial port for the specified device * This constructor creates and opens a serial port for the specified device
* name. * name.
* *
* @param io_context The io_context object that the serial port will use to * @param context An execution context which provides the I/O executor that
* dispatch handlers for any asynchronous operations performed on the port. * the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
* *
* @param device The platform-specific device name for this serial * @param device The platform-specific device name for this serial
* port. * port.
*/ */
explicit basic_serial_port(asio::io_context& io_context, template <typename ExecutionContext>
const std::string& device) basic_serial_port(ExecutionContext& context, const char* device,
: basic_io_object<SerialPortService>(io_context) constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().open(this->get_implementation(), device, ec); impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
basic_serial_port(const executor_type& ex, const std::string& device)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context, const std::string& device,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open"); asio::detail::throw_error(ec, "open");
} }
@@ -113,24 +210,51 @@ public:
* This constructor creates a serial port object to hold an existing native * This constructor creates a serial port object to hold an existing native
* serial port. * serial port.
* *
* @param io_context The io_context object that the serial port will use to * @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the port. * dispatch handlers for any asynchronous operations performed on the
* serial port.
* *
* @param native_serial_port A native serial port. * @param native_serial_port A native serial port.
* *
* @throws asio::system_error Thrown on failure. * @throws asio::system_error Thrown on failure.
*/ */
basic_serial_port(asio::io_context& io_context, basic_serial_port(const executor_type& ex,
const native_handle_type& native_serial_port) const native_handle_type& native_serial_port)
: basic_io_object<SerialPortService>(io_context) : impl_(0, ex)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().assign(this->get_implementation(), impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_serial_port on an existing native serial port.
/**
* This constructor creates a serial port object to hold an existing native
* serial port.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param native_serial_port A native serial port.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context,
const native_handle_type& native_serial_port,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec); native_serial_port, ec);
asio::detail::throw_error(ec, "assign"); asio::detail::throw_error(ec, "assign");
} }
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_serial_port from another. /// Move-construct a basic_serial_port from another.
/** /**
* This constructor moves a serial port from one object to another. * This constructor moves a serial port from one object to another.
@@ -139,11 +263,11 @@ public:
* occur. * occur.
* *
* @note Following the move, the moved-from object is in the same state as if * @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(io_context&) constructor. * constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/ */
basic_serial_port(basic_serial_port&& other) basic_serial_port(basic_serial_port&& other)
: basic_io_object<SerialPortService>( : impl_(std::move(other.impl_))
ASIO_MOVE_CAST(basic_serial_port)(other))
{ {
} }
@@ -155,15 +279,79 @@ public:
* occur. * occur.
* *
* @note Following the move, the moved-from object is in the same state as if * @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(io_context&) constructor. * constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/ */
basic_serial_port& operator=(basic_serial_port&& other) basic_serial_port& operator=(basic_serial_port&& other)
{ {
basic_io_object<SerialPortService>::operator=( impl_ = std::move(other.impl_);
ASIO_MOVE_CAST(basic_serial_port)(other));
return *this; return *this;
} }
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
// All serial ports have access to each other's implementations.
template <typename Executor1>
friend class basic_serial_port;
/// Move-construct a basic_serial_port from a serial port of another executor
/// type.
/**
* This constructor moves a serial port from one object to another.
*
* @param other The other basic_serial_port object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_serial_port(basic_serial_port<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_serial_port from a serial port of another executor
/// type.
/**
* This assignment operator moves a serial port from one object to another.
*
* @param other The other basic_serial_port object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_serial_port&
> operator=(basic_serial_port<Executor1>&& other)
{
basic_serial_port tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this;
}
/// Destroys the serial port.
/**
* This function destroys the serial port, cancelling any outstanding
* asynchronous wait operations associated with the serial port as if by
* calling @c cancel.
*/
~basic_serial_port()
{
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer. /// Get a reference to the lowest layer.
/** /**
@@ -204,7 +392,7 @@ public:
void open(const std::string& device) void open(const std::string& device)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().open(this->get_implementation(), device, ec); impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open"); asio::detail::throw_error(ec, "open");
} }
@@ -220,7 +408,7 @@ public:
ASIO_SYNC_OP_VOID open(const std::string& device, ASIO_SYNC_OP_VOID open(const std::string& device,
asio::error_code& ec) asio::error_code& ec)
{ {
this->get_service().open(this->get_implementation(), device, ec); impl_.get_service().open(impl_.get_implementation(), device, ec);
ASIO_SYNC_OP_VOID_RETURN(ec); ASIO_SYNC_OP_VOID_RETURN(ec);
} }
@@ -235,7 +423,7 @@ public:
void assign(const native_handle_type& native_serial_port) void assign(const native_handle_type& native_serial_port)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().assign(this->get_implementation(), impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec); native_serial_port, ec);
asio::detail::throw_error(ec, "assign"); asio::detail::throw_error(ec, "assign");
} }
@@ -251,7 +439,7 @@ public:
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port, ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port,
asio::error_code& ec) asio::error_code& ec)
{ {
this->get_service().assign(this->get_implementation(), impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec); native_serial_port, ec);
ASIO_SYNC_OP_VOID_RETURN(ec); ASIO_SYNC_OP_VOID_RETURN(ec);
} }
@@ -259,7 +447,7 @@ public:
/// Determine whether the serial port is open. /// Determine whether the serial port is open.
bool is_open() const bool is_open() const
{ {
return this->get_service().is_open(this->get_implementation()); return impl_.get_service().is_open(impl_.get_implementation());
} }
/// Close the serial port. /// Close the serial port.
@@ -273,7 +461,7 @@ public:
void close() void close()
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().close(this->get_implementation(), ec); impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close"); asio::detail::throw_error(ec, "close");
} }
@@ -287,7 +475,7 @@ public:
*/ */
ASIO_SYNC_OP_VOID close(asio::error_code& ec) ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{ {
this->get_service().close(this->get_implementation(), ec); impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec); ASIO_SYNC_OP_VOID_RETURN(ec);
} }
@@ -299,7 +487,7 @@ public:
*/ */
native_handle_type native_handle() native_handle_type native_handle()
{ {
return this->get_service().native_handle(this->get_implementation()); return impl_.get_service().native_handle(impl_.get_implementation());
} }
/// Cancel all asynchronous operations associated with the serial port. /// Cancel all asynchronous operations associated with the serial port.
@@ -313,7 +501,7 @@ public:
void cancel() void cancel()
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().cancel(this->get_implementation(), ec); impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel"); asio::detail::throw_error(ec, "cancel");
} }
@@ -327,7 +515,7 @@ public:
*/ */
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{ {
this->get_service().cancel(this->get_implementation(), ec); impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec); ASIO_SYNC_OP_VOID_RETURN(ec);
} }
@@ -341,7 +529,7 @@ public:
void send_break() void send_break()
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().send_break(this->get_implementation(), ec); impl_.get_service().send_break(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "send_break"); asio::detail::throw_error(ec, "send_break");
} }
@@ -354,7 +542,7 @@ public:
*/ */
ASIO_SYNC_OP_VOID send_break(asio::error_code& ec) ASIO_SYNC_OP_VOID send_break(asio::error_code& ec)
{ {
this->get_service().send_break(this->get_implementation(), ec); impl_.get_service().send_break(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec); ASIO_SYNC_OP_VOID_RETURN(ec);
} }
@@ -377,7 +565,7 @@ public:
void set_option(const SettableSerialPortOption& option) void set_option(const SettableSerialPortOption& option)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().set_option(this->get_implementation(), option, ec); impl_.get_service().set_option(impl_.get_implementation(), option, ec);
asio::detail::throw_error(ec, "set_option"); asio::detail::throw_error(ec, "set_option");
} }
@@ -400,7 +588,7 @@ public:
ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option, ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option,
asio::error_code& ec) asio::error_code& ec)
{ {
this->get_service().set_option(this->get_implementation(), option, ec); impl_.get_service().set_option(impl_.get_implementation(), option, ec);
ASIO_SYNC_OP_VOID_RETURN(ec); ASIO_SYNC_OP_VOID_RETURN(ec);
} }
@@ -421,10 +609,10 @@ public:
* asio::serial_port_base::character_size * asio::serial_port_base::character_size
*/ */
template <typename GettableSerialPortOption> template <typename GettableSerialPortOption>
void get_option(GettableSerialPortOption& option) void get_option(GettableSerialPortOption& option) const
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().get_option(this->get_implementation(), option, ec); impl_.get_service().get_option(impl_.get_implementation(), option, ec);
asio::detail::throw_error(ec, "get_option"); asio::detail::throw_error(ec, "get_option");
} }
@@ -446,9 +634,9 @@ public:
*/ */
template <typename GettableSerialPortOption> template <typename GettableSerialPortOption>
ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option, ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option,
asio::error_code& ec) asio::error_code& ec) const
{ {
this->get_service().get_option(this->get_implementation(), option, ec); impl_.get_service().get_option(impl_.get_implementation(), option, ec);
ASIO_SYNC_OP_VOID_RETURN(ec); ASIO_SYNC_OP_VOID_RETURN(ec);
} }
@@ -473,7 +661,7 @@ public:
* @par Example * @par Example
* To write a single data buffer use the @ref buffer function as follows: * To write a single data buffer use the @ref buffer function as follows:
* @code * @code
* serial_port.write_some(asio::buffer(data, size)); * basic_serial_port.write_some(asio::buffer(data, size));
* @endcode * @endcode
* See the @ref buffer documentation for information on writing multiple * See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or * buffers in one go, and how to use it with arrays, boost::array or
@@ -483,8 +671,8 @@ public:
std::size_t write_some(const ConstBufferSequence& buffers) std::size_t write_some(const ConstBufferSequence& buffers)
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().write_some( std::size_t s = impl_.get_service().write_some(
this->get_implementation(), buffers, ec); impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "write_some"); asio::detail::throw_error(ec, "write_some");
return s; return s;
} }
@@ -509,31 +697,37 @@ public:
std::size_t write_some(const ConstBufferSequence& buffers, std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec) asio::error_code& ec)
{ {
return this->get_service().write_some( return impl_.get_service().write_some(
this->get_implementation(), buffers, ec); impl_.get_implementation(), buffers, ec);
} }
/// Start an asynchronous write. /// Start an asynchronous write.
/** /**
* This function is used to asynchronously write data to the serial port. * This function is used to asynchronously write data to the serial port.
* The function call always returns immediately. * It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
* *
* @param buffers One or more data buffers to be written to the serial port. * @param buffers One or more data buffers to be written to the serial port.
* Although the buffers object may be copied as necessary, ownership of the * Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee * underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called. * that they remain valid until the completion handler is called.
* *
* @param handler The handler to be called when the write operation completes. * @param token The @ref completion_token that will be used to produce a
* Copies will be made of the handler as required. The function signature of * completion handler, which will be called when the write completes.
* the handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* const asio::error_code& error, // Result of operation. * const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written. * std::size_t bytes_transferred // Number of bytes written.
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
* *
* @note The write operation may not transmit all of the data to the peer. * @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all * Consider using the @ref async_write function if you need to ensure that all
@@ -542,24 +736,36 @@ public:
* @par Example * @par Example
* To write a single data buffer use the @ref buffer function as follows: * To write a single data buffer use the @ref buffer function as follows:
* @code * @code
* serial_port.async_write_some(asio::buffer(data, size), handler); * basic_serial_port.async_write_some(
* asio::buffer(data, size), handler);
* @endcode * @endcode
* See the @ref buffer documentation for information on writing multiple * See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or * buffers in one go, and how to use it with arrays, boost::array or
* std::vector. * std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/ */
template <typename ConstBufferSequence, typename WriteHandler> template <typename ConstBufferSequence,
ASIO_INITFN_RESULT_TYPE(WriteHandler, ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
void (asio::error_code, std::size_t)) std::size_t)) WriteToken = default_completion_token_t<executor_type>>
async_write_some(const ConstBufferSequence& buffers, auto async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler) WriteToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
declval<initiate_async_write_some>(), token, buffers))
{ {
// If you get an error on the following line it means that your handler does return async_initiate<WriteToken,
// not meet the documented type requirements for a WriteHandler. void (asio::error_code, std::size_t)>(
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; initiate_async_write_some(this), token, buffers);
return this->get_service().async_write_some(this->get_implementation(),
buffers, ASIO_MOVE_CAST(WriteHandler)(handler));
} }
/// Read some data from the serial port. /// Read some data from the serial port.
@@ -584,7 +790,7 @@ public:
* @par Example * @par Example
* To read into a single data buffer use the @ref buffer function as follows: * To read into a single data buffer use the @ref buffer function as follows:
* @code * @code
* serial_port.read_some(asio::buffer(data, size)); * basic_serial_port.read_some(asio::buffer(data, size));
* @endcode * @endcode
* See the @ref buffer documentation for information on reading into multiple * See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or * buffers in one go, and how to use it with arrays, boost::array or
@@ -594,8 +800,8 @@ public:
std::size_t read_some(const MutableBufferSequence& buffers) std::size_t read_some(const MutableBufferSequence& buffers)
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().read_some( std::size_t s = impl_.get_service().read_some(
this->get_implementation(), buffers, ec); impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "read_some"); asio::detail::throw_error(ec, "read_some");
return s; return s;
} }
@@ -621,31 +827,37 @@ public:
std::size_t read_some(const MutableBufferSequence& buffers, std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec) asio::error_code& ec)
{ {
return this->get_service().read_some( return impl_.get_service().read_some(
this->get_implementation(), buffers, ec); impl_.get_implementation(), buffers, ec);
} }
/// Start an asynchronous read. /// Start an asynchronous read.
/** /**
* This function is used to asynchronously read data from the serial port. * This function is used to asynchronously read data from the serial port.
* The function call always returns immediately. * It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
* *
* @param buffers One or more buffers into which the data will be read. * @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the * Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee * underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called. * that they remain valid until the completion handler is called.
* *
* @param handler The handler to be called when the read operation completes. * @param token The @ref completion_token that will be used to produce a
* Copies will be made of the handler as required. The function signature of * completion handler, which will be called when the read completes.
* the handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* const asio::error_code& error, // Result of operation. * const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read. * std::size_t bytes_transferred // Number of bytes read.
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
* *
* @note The read operation may not read all of the requested number of bytes. * @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the * Consider using the @ref async_read function if you need to ensure that the
@@ -655,25 +867,114 @@ public:
* @par Example * @par Example
* To read into a single data buffer use the @ref buffer function as follows: * To read into a single data buffer use the @ref buffer function as follows:
* @code * @code
* serial_port.async_read_some(asio::buffer(data, size), handler); * basic_serial_port.async_read_some(
* asio::buffer(data, size), handler);
* @endcode * @endcode
* See the @ref buffer documentation for information on reading into multiple * See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or * buffers in one go, and how to use it with arrays, boost::array or
* std::vector. * std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/ */
template <typename MutableBufferSequence, typename ReadHandler> template <typename MutableBufferSequence,
ASIO_INITFN_RESULT_TYPE(ReadHandler, ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
void (asio::error_code, std::size_t)) std::size_t)) ReadToken = default_completion_token_t<executor_type>>
async_read_some(const MutableBufferSequence& buffers, auto async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler) ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
declval<initiate_async_read_some>(), token, buffers))
{ {
// If you get an error on the following line it means that your handler does return async_initiate<ReadToken,
// not meet the documented type requirements for a ReadHandler. void (asio::error_code, std::size_t)>(
initiate_async_read_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_serial_port(const basic_serial_port&) = delete;
basic_serial_port& operator=(const basic_serial_port&) = delete;
class initiate_async_write_some
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some(basic_serial_port* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(WriteHandler&& handler,
const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_serial_port* self_;
};
class initiate_async_read_some
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some(basic_serial_port* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ReadHandler&& handler,
const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
return this->get_service().async_read_some(this->get_implementation(), detail::non_const_lvalue<ReadHandler> handler2(handler);
buffers, ASIO_MOVE_CAST(ReadHandler)(handler)); self_->impl_.get_service().async_read_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
} }
private:
basic_serial_port* self_;
};
#if defined(ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_serial_port_service, Executor> impl_;
#else
detail::io_object_impl<detail::posix_serial_port_service, Executor> impl_;
#endif
}; };
} // namespace asio } // namespace asio
@@ -683,6 +984,4 @@ public:
#endif // defined(ASIO_HAS_SERIAL_PORT) #endif // defined(ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION) // || defined(GENERATING_DOCUMENTATION)
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
#endif // ASIO_BASIC_SERIAL_PORT_HPP #endif // ASIO_BASIC_SERIAL_PORT_HPP

View File

@@ -2,7 +2,7 @@
// basic_signal_set.hpp // basic_signal_set.hpp
// ~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -17,13 +17,17 @@
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#if defined(ASIO_ENABLE_OLD_SERVICES) #include "asio/any_io_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/detail/handler_type_requirements.hpp" #include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/signal_set_service.hpp"
#include "asio/detail/throw_error.hpp" #include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp" #include "asio/error.hpp"
#include "asio/signal_set_service.hpp" #include "asio/execution_context.hpp"
#include "asio/signal_set_base.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
@@ -31,10 +35,8 @@ namespace asio {
/// Provides signal functionality. /// Provides signal functionality.
/** /**
* The basic_signal_set class template provides the ability to perform an * The basic_signal_set class provides the ability to perform an asynchronous
* asynchronous wait for one or more signals to occur. * wait for one or more signals to occur.
*
* Most applications will use the asio::signal_set typedef.
* *
* @par Thread Safety * @par Thread Safety
* @e Distinct @e objects: Safe.@n * @e Distinct @e objects: Safe.@n
@@ -56,7 +58,7 @@ namespace asio {
* ... * ...
* *
* // Construct a signal set registered for process termination. * // Construct a signal set registered for process termination.
* asio::signal_set signals(io_context, SIGINT, SIGTERM); * asio::signal_set signals(my_context, SIGINT, SIGTERM);
* *
* // Start an asynchronous wait for one of the signals to occur. * // Start an asynchronous wait for one of the signals to occur.
* signals.async_wait(handler); * signals.async_wait(handler);
@@ -91,20 +93,52 @@ namespace asio {
* that any signals registered using signal_set objects are unblocked in at * that any signals registered using signal_set objects are unblocked in at
* least one thread. * least one thread.
*/ */
template <typename SignalSetService = signal_set_service> template <typename Executor = any_io_executor>
class basic_signal_set class basic_signal_set : public signal_set_base
: public basic_io_object<SignalSetService>
{ {
private:
class initiate_async_wait;
public: public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the signal set type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The signal set type when rebound to the specified executor.
typedef basic_signal_set<Executor1> other;
};
/// Construct a signal set without adding any signals. /// Construct a signal set without adding any signals.
/** /**
* This constructor creates a signal set without registering for any signals. * This constructor creates a signal set without registering for any signals.
* *
* @param io_context The io_context object that the signal set will use to * @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the set. * dispatch handlers for any asynchronous operations performed on the
* signal set.
*/ */
explicit basic_signal_set(asio::io_context& io_context) explicit basic_signal_set(const executor_type& ex)
: basic_io_object<SignalSetService>(io_context) : impl_(0, ex)
{
}
/// Construct a signal set without adding any signals.
/**
* This constructor creates a signal set without registering for any signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*/
template <typename ExecutionContext>
explicit basic_signal_set(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{ {
} }
@@ -112,20 +146,48 @@ public:
/** /**
* This constructor creates a signal set and registers for one signal. * This constructor creates a signal set and registers for one signal.
* *
* @param io_context The io_context object that the signal set will use to * @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the set. * dispatch handlers for any asynchronous operations performed on the
* signal set.
* *
* @param signal_number_1 The signal number to be added. * @param signal_number_1 The signal number to be added.
* *
* @note This constructor is equivalent to performing: * @note This constructor is equivalent to performing:
* @code asio::signal_set signals(io_context); * @code asio::signal_set signals(ex);
* signals.add(signal_number_1); @endcode * signals.add(signal_number_1); @endcode
*/ */
basic_signal_set(asio::io_context& io_context, int signal_number_1) basic_signal_set(const executor_type& ex, int signal_number_1)
: basic_io_object<SignalSetService>(io_context) : impl_(0, ex)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().add(this->get_implementation(), signal_number_1, ec); impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add one signal.
/**
* This constructor creates a signal set and registers for one signal.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(context);
* signals.add(signal_number_1); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add"); asio::detail::throw_error(ec, "add");
} }
@@ -133,26 +195,60 @@ public:
/** /**
* This constructor creates a signal set and registers for two signals. * This constructor creates a signal set and registers for two signals.
* *
* @param io_context The io_context object that the signal set will use to * @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the set. * dispatch handlers for any asynchronous operations performed on the
* signal set.
* *
* @param signal_number_1 The first signal number to be added. * @param signal_number_1 The first signal number to be added.
* *
* @param signal_number_2 The second signal number to be added. * @param signal_number_2 The second signal number to be added.
* *
* @note This constructor is equivalent to performing: * @note This constructor is equivalent to performing:
* @code asio::signal_set signals(io_context); * @code asio::signal_set signals(ex);
* signals.add(signal_number_1); * signals.add(signal_number_1);
* signals.add(signal_number_2); @endcode * signals.add(signal_number_2); @endcode
*/ */
basic_signal_set(asio::io_context& io_context, int signal_number_1, basic_signal_set(const executor_type& ex, int signal_number_1,
int signal_number_2) int signal_number_2)
: basic_io_object<SignalSetService>(io_context) : impl_(0, ex)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().add(this->get_implementation(), signal_number_1, ec); impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add"); asio::detail::throw_error(ec, "add");
this->get_service().add(this->get_implementation(), signal_number_2, ec); impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add two signals.
/**
* This constructor creates a signal set and registers for two signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(context);
* signals.add(signal_number_1);
* signals.add(signal_number_2); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
int signal_number_2,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add"); asio::detail::throw_error(ec, "add");
} }
@@ -160,8 +256,9 @@ public:
/** /**
* This constructor creates a signal set and registers for three signals. * This constructor creates a signal set and registers for three signals.
* *
* @param io_context The io_context object that the signal set will use to * @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the set. * dispatch handlers for any asynchronous operations performed on the
* signal set.
* *
* @param signal_number_1 The first signal number to be added. * @param signal_number_1 The first signal number to be added.
* *
@@ -170,24 +267,78 @@ public:
* @param signal_number_3 The third signal number to be added. * @param signal_number_3 The third signal number to be added.
* *
* @note This constructor is equivalent to performing: * @note This constructor is equivalent to performing:
* @code asio::signal_set signals(io_context); * @code asio::signal_set signals(ex);
* signals.add(signal_number_1); * signals.add(signal_number_1);
* signals.add(signal_number_2); * signals.add(signal_number_2);
* signals.add(signal_number_3); @endcode * signals.add(signal_number_3); @endcode
*/ */
basic_signal_set(asio::io_context& io_context, int signal_number_1, basic_signal_set(const executor_type& ex, int signal_number_1,
int signal_number_2, int signal_number_3) int signal_number_2, int signal_number_3)
: basic_io_object<SignalSetService>(io_context) : impl_(0, ex)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().add(this->get_implementation(), signal_number_1, ec); impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add"); asio::detail::throw_error(ec, "add");
this->get_service().add(this->get_implementation(), signal_number_2, ec); impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add"); asio::detail::throw_error(ec, "add");
this->get_service().add(this->get_implementation(), signal_number_3, ec); impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
asio::detail::throw_error(ec, "add"); asio::detail::throw_error(ec, "add");
} }
/// Construct a signal set and add three signals.
/**
* This constructor creates a signal set and registers for three signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @param signal_number_3 The third signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(context);
* signals.add(signal_number_1);
* signals.add(signal_number_2);
* signals.add(signal_number_3); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
int signal_number_2, int signal_number_3,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
asio::detail::throw_error(ec, "add");
}
/// Destroys the signal set.
/**
* This function destroys the signal set, cancelling any outstanding
* asynchronous wait operations associated with the signal set as if by
* calling @c cancel.
*/
~basic_signal_set()
{
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Add a signal to a signal_set. /// Add a signal to a signal_set.
/** /**
* This function adds the specified signal to the set. It has no effect if the * This function adds the specified signal to the set. It has no effect if the
@@ -200,7 +351,7 @@ public:
void add(int signal_number) void add(int signal_number)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().add(this->get_implementation(), signal_number, ec); impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
asio::detail::throw_error(ec, "add"); asio::detail::throw_error(ec, "add");
} }
@@ -213,9 +364,62 @@ public:
* *
* @param ec Set to indicate what error occurred, if any. * @param ec Set to indicate what error occurred, if any.
*/ */
ASIO_SYNC_OP_VOID add(int signal_number, asio::error_code& ec) ASIO_SYNC_OP_VOID add(int signal_number,
asio::error_code& ec)
{ {
this->get_service().add(this->get_implementation(), signal_number, ec); impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Add a signal to a signal_set with the specified flags.
/**
* This function adds the specified signal to the set. It has no effect if the
* signal is already in the set.
*
* Flags other than flags::dont_care require OS support for the @c sigaction
* call, and this function will fail with @c error::operation_not_supported if
* this is unavailable.
*
* The specified flags will conflict with a prior, active registration of the
* same signal, if either specified a flags value other than flags::dont_care.
* In this case, the @c add will fail with @c error::invalid_argument.
*
* @param signal_number The signal to be added to the set.
*
* @param f Flags to modify the behaviour of the specified signal.
*
* @throws asio::system_error Thrown on failure.
*/
void add(int signal_number, flags_t f)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number, f, ec);
asio::detail::throw_error(ec, "add");
}
/// Add a signal to a signal_set with the specified flags.
/**
* This function adds the specified signal to the set. It has no effect if the
* signal is already in the set.
*
* Flags other than flags::dont_care require OS support for the @c sigaction
* call, and this function will fail with @c error::operation_not_supported if
* this is unavailable.
*
* The specified flags will conflict with a prior, active registration of the
* same signal, if either specified a flags value other than flags::dont_care.
* In this case, the @c add will fail with @c error::invalid_argument.
*
* @param signal_number The signal to be added to the set.
*
* @param f Flags to modify the behaviour of the specified signal.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID add(int signal_number, flags_t f,
asio::error_code& ec)
{
impl_.get_service().add(impl_.get_implementation(), signal_number, f, ec);
ASIO_SYNC_OP_VOID_RETURN(ec); ASIO_SYNC_OP_VOID_RETURN(ec);
} }
@@ -234,7 +438,7 @@ public:
void remove(int signal_number) void remove(int signal_number)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().remove(this->get_implementation(), signal_number, ec); impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
asio::detail::throw_error(ec, "remove"); asio::detail::throw_error(ec, "remove");
} }
@@ -253,7 +457,7 @@ public:
ASIO_SYNC_OP_VOID remove(int signal_number, ASIO_SYNC_OP_VOID remove(int signal_number,
asio::error_code& ec) asio::error_code& ec)
{ {
this->get_service().remove(this->get_implementation(), signal_number, ec); impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
ASIO_SYNC_OP_VOID_RETURN(ec); ASIO_SYNC_OP_VOID_RETURN(ec);
} }
@@ -269,7 +473,7 @@ public:
void clear() void clear()
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().clear(this->get_implementation(), ec); impl_.get_service().clear(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "clear"); asio::detail::throw_error(ec, "clear");
} }
@@ -284,7 +488,7 @@ public:
*/ */
ASIO_SYNC_OP_VOID clear(asio::error_code& ec) ASIO_SYNC_OP_VOID clear(asio::error_code& ec)
{ {
this->get_service().clear(this->get_implementation(), ec); impl_.get_service().clear(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec); ASIO_SYNC_OP_VOID_RETURN(ec);
} }
@@ -312,7 +516,7 @@ public:
void cancel() void cancel()
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().cancel(this->get_implementation(), ec); impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel"); asio::detail::throw_error(ec, "cancel");
} }
@@ -339,53 +543,106 @@ public:
*/ */
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{ {
this->get_service().cancel(this->get_implementation(), ec); impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec); ASIO_SYNC_OP_VOID_RETURN(ec);
} }
/// Start an asynchronous operation to wait for a signal to be delivered. /// Start an asynchronous operation to wait for a signal to be delivered.
/** /**
* This function may be used to initiate an asynchronous wait against the * This function may be used to initiate an asynchronous wait against the
* signal set. It always returns immediately. * signal set. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
* *
* For each call to async_wait(), the supplied handler will be called exactly * For each call to async_wait(), the completion handler will be called
* once. The handler will be called when: * exactly once. The completion handler will be called when:
* *
* @li One of the registered signals in the signal set occurs; or * @li One of the registered signals in the signal set occurs; or
* *
* @li The signal set was cancelled, in which case the handler is passed the * @li The signal set was cancelled, in which case the handler is passed the
* error code asio::error::operation_aborted. * error code asio::error::operation_aborted.
* *
* @param handler The handler to be called when the signal occurs. Copies * @param token The @ref completion_token that will be used to produce a
* will be made of the handler as required. The function signature of the * completion handler, which will be called when the wait completes.
* handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* const asio::error_code& error, // Result of operation. * const asio::error_code& error, // Result of operation.
* int signal_number // Indicates which signal occurred. * int signal_number // Indicates which signal occurred.
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, int) @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/ */
template <typename SignalHandler> template <
ASIO_INITFN_RESULT_TYPE(SignalHandler, ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, int))
void (asio::error_code, int)) SignalToken = default_completion_token_t<executor_type>>
async_wait(ASIO_MOVE_ARG(SignalHandler) handler) auto async_wait(
SignalToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<SignalToken, void (asio::error_code, int)>(
declval<initiate_async_wait>(), token))
{ {
// If you get an error on the following line it means that your handler does return async_initiate<SignalToken, void (asio::error_code, int)>(
// not meet the documented type requirements for a SignalHandler. initiate_async_wait(this), token);
}
private:
// Disallow copying and assignment.
basic_signal_set(const basic_signal_set&) = delete;
basic_signal_set& operator=(const basic_signal_set&) = delete;
class initiate_async_wait
{
public:
typedef Executor executor_type;
explicit initiate_async_wait(basic_signal_set* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename SignalHandler>
void operator()(SignalHandler&& handler) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a SignalHandler.
ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check; ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check;
return this->get_service().async_wait(this->get_implementation(), detail::non_const_lvalue<SignalHandler> handler2(handler);
ASIO_MOVE_CAST(SignalHandler)(handler)); self_->impl_.get_service().async_wait(
self_->impl_.get_implementation(),
handler2.value, self_->impl_.get_executor());
} }
private:
basic_signal_set* self_;
};
detail::io_object_impl<detail::signal_set_service, Executor> impl_;
}; };
} // namespace asio } // namespace asio
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
#endif // ASIO_BASIC_SIGNAL_SET_HPP #endif // ASIO_BASIC_SIGNAL_SET_HPP

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// basic_socket_iostream.hpp // basic_socket_iostream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -23,61 +23,6 @@
#include <ostream> #include <ostream>
#include "asio/basic_socket_streambuf.hpp" #include "asio/basic_socket_streambuf.hpp"
#if defined(ASIO_ENABLE_OLD_SERVICES)
# include "asio/stream_socket_service.hpp"
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
# include "asio/detail/variadic_templates.hpp"
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// explicit basic_socket_iostream(T1 x1, ..., Tn xn)
// : std::basic_iostream<char>(
// &this->detail::socket_iostream_base<
// Protocol ASIO_SVC_TARG, Clock,
// WaitTraits ASIO_SVC_TARG1>::streambuf_)
// {
// if (rdbuf()->connect(x1, ..., xn) == 0)
// this->setstate(std::ios_base::failbit);
// }
// This macro should only persist within this file.
# define ASIO_PRIVATE_CTR_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
explicit basic_socket_iostream(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
: std::basic_iostream<char>( \
&this->detail::socket_iostream_base< \
Protocol ASIO_SVC_TARG, Clock, \
WaitTraits ASIO_SVC_TARG1>::streambuf_) \
{ \
this->setf(std::ios_base::unitbuf); \
if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \
this->setstate(std::ios_base::failbit); \
} \
/**/
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// void connect(T1 x1, ..., Tn xn)
// {
// if (rdbuf()->connect(x1, ..., xn) == 0)
// this->setstate(std::ios_base::failbit);
// }
// This macro should only persist within this file.
# define ASIO_PRIVATE_CONNECT_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
void connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
{ \
if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \
this->setstate(std::ios_base::failbit); \
} \
/**/
#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
namespace asio { namespace asio {
@@ -85,8 +30,7 @@ namespace detail {
// A separate base class is used to ensure that the streambuf is initialised // A separate base class is used to ensure that the streambuf is initialised
// prior to the basic_socket_iostream's basic_iostream base class. // prior to the basic_socket_iostream's basic_iostream base class.
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Clock, typename WaitTraits>
typename Clock, typename WaitTraits ASIO_SVC_TPARAM1>
class socket_iostream_base class socket_iostream_base
{ {
protected: protected:
@@ -94,7 +38,6 @@ protected:
{ {
} }
#if defined(ASIO_HAS_MOVE)
socket_iostream_base(socket_iostream_base&& other) socket_iostream_base(socket_iostream_base&& other)
: streambuf_(std::move(other.streambuf_)) : streambuf_(std::move(other.streambuf_))
{ {
@@ -110,10 +53,8 @@ protected:
streambuf_ = std::move(other.streambuf_); streambuf_ = std::move(other.streambuf_);
return *this; return *this;
} }
#endif // defined(ASIO_HAS_MOVE)
basic_socket_streambuf<Protocol ASIO_SVC_TARG, basic_socket_streambuf<Protocol, Clock, WaitTraits> streambuf_;
Clock, WaitTraits ASIO_SVC_TARG1> streambuf_;
}; };
} // namespace detail } // namespace detail
@@ -122,18 +63,15 @@ protected:
#define ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL #define ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL
// Forward declaration with defaulted arguments. // Forward declaration with defaulted arguments.
template <typename Protocol template <typename Protocol,
ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>),
#if defined(ASIO_HAS_BOOST_DATE_TIME) \ #if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = boost::posix_time::ptime, typename Clock = boost::posix_time::ptime,
typename WaitTraits = time_traits<Clock> typename WaitTraits = time_traits<Clock>>
ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)>
#else // defined(ASIO_HAS_BOOST_DATE_TIME) #else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = chrono::steady_clock, typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock> typename WaitTraits = wait_traits<Clock>>
ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)>
#endif // defined(ASIO_HAS_BOOST_DATE_TIME) #endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
class basic_socket_iostream; class basic_socket_iostream;
@@ -146,12 +84,10 @@ template <typename Protocol,
typename Clock = chrono::steady_clock, typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock>> typename WaitTraits = wait_traits<Clock>>
#else // defined(GENERATING_DOCUMENTATION) #else // defined(GENERATING_DOCUMENTATION)
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Clock, typename WaitTraits>
typename Clock, typename WaitTraits ASIO_SVC_TPARAM1>
#endif // defined(GENERATING_DOCUMENTATION) #endif // defined(GENERATING_DOCUMENTATION)
class basic_socket_iostream class basic_socket_iostream
: private detail::socket_iostream_base<Protocol : private detail::socket_iostream_base<Protocol, Clock, WaitTraits>,
ASIO_SVC_TARG, Clock, WaitTraits ASIO_SVC_TARG1>,
public std::basic_iostream<char> public std::basic_iostream<char>
{ {
private: private:
@@ -201,38 +137,30 @@ public:
basic_socket_iostream() basic_socket_iostream()
: std::basic_iostream<char>( : std::basic_iostream<char>(
&this->detail::socket_iostream_base< &this->detail::socket_iostream_base<
Protocol ASIO_SVC_TARG, Clock, Protocol, Clock, WaitTraits>::streambuf_)
WaitTraits ASIO_SVC_TARG1>::streambuf_)
{ {
this->setf(std::ios_base::unitbuf); this->setf(std::ios_base::unitbuf);
} }
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Construct a basic_socket_iostream from the supplied socket. /// Construct a basic_socket_iostream from the supplied socket.
explicit basic_socket_iostream(basic_stream_socket<protocol_type> s) explicit basic_socket_iostream(basic_stream_socket<protocol_type> s)
: detail::socket_iostream_base< : detail::socket_iostream_base<
Protocol ASIO_SVC_TARG, Clock, Protocol, Clock, WaitTraits>(std::move(s)),
WaitTraits ASIO_SVC_TARG1>(std::move(s)),
std::basic_iostream<char>( std::basic_iostream<char>(
&this->detail::socket_iostream_base< &this->detail::socket_iostream_base<
Protocol ASIO_SVC_TARG, Clock, Protocol, Clock, WaitTraits>::streambuf_)
WaitTraits ASIO_SVC_TARG1>::streambuf_)
{ {
this->setf(std::ios_base::unitbuf); this->setf(std::ios_base::unitbuf);
} }
#if defined(ASIO_HAS_STD_IOSTREAM_MOVE) \
|| defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_socket_iostream from another. /// Move-construct a basic_socket_iostream from another.
basic_socket_iostream(basic_socket_iostream&& other) basic_socket_iostream(basic_socket_iostream&& other)
: detail::socket_iostream_base< : detail::socket_iostream_base<
Protocol ASIO_SVC_TARG, Clock, Protocol, Clock, WaitTraits>(std::move(other)),
WaitTraits ASIO_SVC_TARG1>(std::move(other)),
std::basic_iostream<char>(std::move(other)) std::basic_iostream<char>(std::move(other))
{ {
this->set_rdbuf(&this->detail::socket_iostream_base< this->set_rdbuf(&this->detail::socket_iostream_base<
Protocol ASIO_SVC_TARG, Clock, Protocol, Clock, WaitTraits>::streambuf_);
WaitTraits ASIO_SVC_TARG1>::streambuf_);
} }
/// Move-assign a basic_socket_iostream from another. /// Move-assign a basic_socket_iostream from another.
@@ -240,58 +168,39 @@ public:
{ {
std::basic_iostream<char>::operator=(std::move(other)); std::basic_iostream<char>::operator=(std::move(other));
detail::socket_iostream_base< detail::socket_iostream_base<
Protocol ASIO_SVC_TARG, Clock, Protocol, Clock, WaitTraits>::operator=(std::move(other));
WaitTraits ASIO_SVC_TARG1>::operator=(std::move(other));
return *this; return *this;
} }
#endif // defined(ASIO_HAS_STD_IOSTREAM_MOVE)
// || defined(GENERATING_DOCUMENTATION)
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection to an endpoint corresponding to a resolver query. /// Establish a connection to an endpoint corresponding to a resolver query.
/** /**
* This constructor automatically establishes a connection based on the * This constructor automatically establishes a connection based on the
* supplied resolver query parameters. The arguments are used to construct * supplied resolver query parameters. The arguments are used to construct
* a resolver query object. * a resolver query object.
*/ */
template <typename T1, ..., typename TN>
explicit basic_socket_iostream(T1 t1, ..., TN tn);
#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename... T> template <typename... T>
explicit basic_socket_iostream(T... x) explicit basic_socket_iostream(T... x)
: std::basic_iostream<char>( : std::basic_iostream<char>(
&this->detail::socket_iostream_base< &this->detail::socket_iostream_base<
Protocol ASIO_SVC_TARG, Clock, Protocol, Clock, WaitTraits>::streambuf_)
WaitTraits ASIO_SVC_TARG1>::streambuf_)
{ {
this->setf(std::ios_base::unitbuf); this->setf(std::ios_base::unitbuf);
if (rdbuf()->connect(x...) == 0) if (rdbuf()->connect(x...) == 0)
this->setstate(std::ios_base::failbit); this->setstate(std::ios_base::failbit);
} }
#else
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CTR_DEF)
#endif
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection to an endpoint corresponding to a resolver query. /// Establish a connection to an endpoint corresponding to a resolver query.
/** /**
* This function automatically establishes a connection based on the supplied * This function automatically establishes a connection based on the supplied
* resolver query parameters. The arguments are used to construct a resolver * resolver query parameters. The arguments are used to construct a resolver
* query object. * query object.
*/ */
template <typename T1, ..., typename TN>
void connect(T1 t1, ..., TN tn);
#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename... T> template <typename... T>
void connect(T... x) void connect(T... x)
{ {
if (rdbuf()->connect(x...) == 0) if (rdbuf()->connect(x...) == 0)
this->setstate(std::ios_base::failbit); this->setstate(std::ios_base::failbit);
} }
#else
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF)
#endif
/// Close the connection. /// Close the connection.
void close() void close()
@@ -301,18 +210,15 @@ public:
} }
/// Return a pointer to the underlying streambuf. /// Return a pointer to the underlying streambuf.
basic_socket_streambuf<Protocol ASIO_SVC_TARG, basic_socket_streambuf<Protocol, Clock, WaitTraits>* rdbuf() const
Clock, WaitTraits ASIO_SVC_TARG1>* rdbuf() const
{ {
return const_cast<basic_socket_streambuf<Protocol ASIO_SVC_TARG, return const_cast<basic_socket_streambuf<Protocol, Clock, WaitTraits>*>(
Clock, WaitTraits ASIO_SVC_TARG1>*>(
&this->detail::socket_iostream_base< &this->detail::socket_iostream_base<
Protocol ASIO_SVC_TARG, Clock, Protocol, Clock, WaitTraits>::streambuf_);
WaitTraits ASIO_SVC_TARG1>::streambuf_);
} }
/// Get a reference to the underlying socket. /// Get a reference to the underlying socket.
basic_socket<Protocol ASIO_SVC_TARG>& socket() basic_socket<Protocol>& socket()
{ {
return rdbuf()->socket(); return rdbuf()->socket();
} }
@@ -411,20 +317,15 @@ public:
private: private:
// Disallow copying and assignment. // Disallow copying and assignment.
basic_socket_iostream(const basic_socket_iostream&) ASIO_DELETED; basic_socket_iostream(const basic_socket_iostream&) = delete;
basic_socket_iostream& operator=( basic_socket_iostream& operator=(
const basic_socket_iostream&) ASIO_DELETED; const basic_socket_iostream&) = delete;
}; };
} // namespace asio } // namespace asio
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
# undef ASIO_PRIVATE_CTR_DEF
# undef ASIO_PRIVATE_CONNECT_DEF
#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
#endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_IOSTREAM)
#endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP #endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP

View File

@@ -2,7 +2,7 @@
// basic_socket_streambuf.hpp // basic_socket_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -28,59 +28,15 @@
#include "asio/detail/throw_error.hpp" #include "asio/detail/throw_error.hpp"
#include "asio/io_context.hpp" #include "asio/io_context.hpp"
#if defined(ASIO_ENABLE_OLD_SERVICES)
# include "asio/stream_socket_service.hpp"
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
#if defined(ASIO_HAS_BOOST_DATE_TIME) \ #if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
# if defined(ASIO_ENABLE_OLD_SERVICES)
# include "asio/deadline_timer_service.hpp"
# else // defined(ASIO_ENABLE_OLD_SERVICES)
# include "asio/detail/deadline_timer_service.hpp" # include "asio/detail/deadline_timer_service.hpp"
# endif // defined(ASIO_ENABLE_OLD_SERVICES)
#else // defined(ASIO_HAS_BOOST_DATE_TIME) #else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
# include "asio/steady_timer.hpp" # include "asio/steady_timer.hpp"
#endif // defined(ASIO_HAS_BOOST_DATE_TIME) #endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
# include "asio/detail/variadic_templates.hpp"
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// basic_socket_streambuf* connect(T1 x1, ..., Tn xn)
// {
// init_buffers();
// typedef typename Protocol::resolver resolver_type;
// resolver_type resolver(socket().get_executor().context());
// connect_to_endpoints(
// resolver.resolve(x1, ..., xn, ec_));
// return !ec_ ? this : 0;
// }
// This macro should only persist within this file.
# define ASIO_PRIVATE_CONNECT_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
basic_socket_streambuf* connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
{ \
init_buffers(); \
typedef typename Protocol::resolver resolver_type; \
resolver_type resolver(socket().get_executor().context()); \
connect_to_endpoints( \
resolver.resolve(ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \
return !ec_ ? this : 0; \
} \
/**/
#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
#if !defined(ASIO_ENABLE_OLD_SERVICES)
# define ASIO_SVC_T1 detail::deadline_timer_service<traits_helper>
#endif // !defined(ASIO_ENABLE_OLD_SERVICES)
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
namespace asio { namespace asio {
@@ -124,18 +80,15 @@ protected:
#define ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL #define ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL
// Forward declaration with defaulted arguments. // Forward declaration with defaulted arguments.
template <typename Protocol template <typename Protocol,
ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>),
#if defined(ASIO_HAS_BOOST_DATE_TIME) \ #if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = boost::posix_time::ptime, typename Clock = boost::posix_time::ptime,
typename WaitTraits = time_traits<Clock> typename WaitTraits = time_traits<Clock>>
ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)>
#else // defined(ASIO_HAS_BOOST_DATE_TIME) #else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = chrono::steady_clock, typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock> typename WaitTraits = wait_traits<Clock>>
ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)>
#endif // defined(ASIO_HAS_BOOST_DATE_TIME) #endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
class basic_socket_streambuf; class basic_socket_streambuf;
@@ -148,17 +101,16 @@ template <typename Protocol,
typename Clock = chrono::steady_clock, typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock>> typename WaitTraits = wait_traits<Clock>>
#else // defined(GENERATING_DOCUMENTATION) #else // defined(GENERATING_DOCUMENTATION)
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Clock, typename WaitTraits>
typename Clock, typename WaitTraits ASIO_SVC_TPARAM1>
#endif // defined(GENERATING_DOCUMENTATION) #endif // defined(GENERATING_DOCUMENTATION)
class basic_socket_streambuf class basic_socket_streambuf
: public std::streambuf, : public std::streambuf,
private detail::socket_streambuf_io_context, private detail::socket_streambuf_io_context,
private detail::socket_streambuf_buffers, private detail::socket_streambuf_buffers,
#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) #if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
private basic_socket<Protocol ASIO_SVC_TARG> private basic_socket<Protocol>
#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) #else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
public basic_socket<Protocol ASIO_SVC_TARG> public basic_socket<Protocol>
#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) #endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
{ {
private: private:
@@ -207,17 +159,16 @@ public:
/// Construct a basic_socket_streambuf without establishing a connection. /// Construct a basic_socket_streambuf without establishing a connection.
basic_socket_streambuf() basic_socket_streambuf()
: detail::socket_streambuf_io_context(new io_context), : detail::socket_streambuf_io_context(new io_context),
basic_socket<Protocol ASIO_SVC_TARG>(*default_io_context_), basic_socket<Protocol>(*default_io_context_),
expiry_time_(max_expiry_time()) expiry_time_(max_expiry_time())
{ {
init_buffers(); init_buffers();
} }
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Construct a basic_socket_streambuf from the supplied socket. /// Construct a basic_socket_streambuf from the supplied socket.
explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s) explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s)
: detail::socket_streambuf_io_context(0), : detail::socket_streambuf_io_context(0),
basic_socket<Protocol ASIO_SVC_TARG>(std::move(s)), basic_socket<Protocol>(std::move(s)),
expiry_time_(max_expiry_time()) expiry_time_(max_expiry_time())
{ {
init_buffers(); init_buffers();
@@ -226,7 +177,7 @@ public:
/// Move-construct a basic_socket_streambuf from another. /// Move-construct a basic_socket_streambuf from another.
basic_socket_streambuf(basic_socket_streambuf&& other) basic_socket_streambuf(basic_socket_streambuf&& other)
: detail::socket_streambuf_io_context(other), : detail::socket_streambuf_io_context(other),
basic_socket<Protocol ASIO_SVC_TARG>(std::move(other.socket())), basic_socket<Protocol>(std::move(other.socket())),
ec_(other.ec_), ec_(other.ec_),
expiry_time_(other.expiry_time_) expiry_time_(other.expiry_time_)
{ {
@@ -257,7 +208,6 @@ public:
other.init_buffers(); other.init_buffers();
return *this; return *this;
} }
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destructor flushes buffered data. /// Destructor flushes buffered data.
virtual ~basic_socket_streambuf() virtual ~basic_socket_streambuf()
@@ -281,7 +231,6 @@ public:
return !ec_ ? this : 0; return !ec_ ? this : 0;
} }
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection. /// Establish a connection.
/** /**
* This function automatically establishes a connection based on the supplied * This function automatically establishes a connection based on the supplied
@@ -291,21 +240,15 @@ public:
* @return \c this if a connection was successfully established, a null * @return \c this if a connection was successfully established, a null
* pointer otherwise. * pointer otherwise.
*/ */
template <typename T1, ..., typename TN>
basic_socket_streambuf* connect(T1 t1, ..., TN tn);
#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename... T> template <typename... T>
basic_socket_streambuf* connect(T... x) basic_socket_streambuf* connect(T... x)
{ {
init_buffers(); init_buffers();
typedef typename Protocol::resolver resolver_type; typedef typename Protocol::resolver resolver_type;
resolver_type resolver(socket().get_executor().context()); resolver_type resolver(socket().get_executor());
connect_to_endpoints(resolver.resolve(x..., ec_)); connect_to_endpoints(resolver.resolve(x..., ec_));
return !ec_ ? this : 0; return !ec_ ? this : 0;
} }
#else
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF)
#endif
/// Close the connection. /// Close the connection.
/** /**
@@ -322,7 +265,7 @@ public:
} }
/// Get a reference to the underlying socket. /// Get a reference to the underlying socket.
basic_socket<Protocol ASIO_SVC_TARG>& socket() basic_socket<Protocol>& socket()
{ {
return *this; return *this;
} }
@@ -575,9 +518,9 @@ protected:
private: private:
// Disallow copying and assignment. // Disallow copying and assignment.
basic_socket_streambuf(const basic_socket_streambuf&) ASIO_DELETED; basic_socket_streambuf(const basic_socket_streambuf&) = delete;
basic_socket_streambuf& operator=( basic_socket_streambuf& operator=(
const basic_socket_streambuf&) ASIO_DELETED; const basic_socket_streambuf&) = delete;
void init_buffers() void init_buffers()
{ {
@@ -694,14 +637,6 @@ private:
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
#if !defined(ASIO_ENABLE_OLD_SERVICES)
# undef ASIO_SVC_T1
#endif // !defined(ASIO_ENABLE_OLD_SERVICES)
#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
# undef ASIO_PRIVATE_CONNECT_DEF
#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
#endif // !defined(ASIO_NO_IOSTREAM) #endif // !defined(ASIO_NO_IOSTREAM)
#endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP #endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP

View File

@@ -0,0 +1,744 @@
//
// basic_stream_file.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 ASIO_BASIC_STREAM_FILE_HPP
#define ASIO_BASIC_STREAM_FILE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_FILE) \
|| defined(GENERATING_DOCUMENTATION)
#include <cstddef>
#include "asio/async_result.hpp"
#include "asio/basic_file.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
#if !defined(ASIO_BASIC_STREAM_FILE_FWD_DECL)
#define ASIO_BASIC_STREAM_FILE_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Executor = any_io_executor>
class basic_stream_file;
#endif // !defined(ASIO_BASIC_STREAM_FILE_FWD_DECL)
/// Provides stream-oriented file functionality.
/**
* The basic_stream_file class template provides asynchronous and blocking
* stream-oriented file functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Executor>
class basic_stream_file
: public basic_file<Executor>
{
private:
class initiate_async_write_some;
class initiate_async_read_some;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the file type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The file type when rebound to the specified executor.
typedef basic_stream_file<Executor1> other;
};
/// The native representation of a file.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_file<Executor>::native_handle_type native_handle_type;
#endif
/// Construct a basic_stream_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*/
explicit basic_stream_file(const executor_type& ex)
: basic_file<Executor>(ex)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
/// Construct a basic_stream_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*/
template <typename ExecutionContext>
explicit basic_stream_file(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_file(const executor_type& ex,
const char* path, file_base::flags open_flags)
: basic_file<Executor>(ex)
{
asio::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path, open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_file(ExecutionContext& context,
const char* path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context)
{
asio::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path, open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_file(const executor_type& ex,
const std::string& path, file_base::flags open_flags)
: basic_file<Executor>(ex)
{
asio::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path.c_str(), open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_file(ExecutionContext& context,
const std::string& path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context)
{
asio::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path.c_str(), open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct a basic_stream_file on an existing native file.
/**
* This constructor initialises a stream file object to hold an existing
* native file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_file(const executor_type& ex,
const native_handle_type& native_file)
: basic_file<Executor>(ex, native_file)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
/// Construct a basic_stream_file on an existing native file.
/**
* This constructor initialises a stream file object to hold an existing
* native file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_file(ExecutionContext& context,
const native_handle_type& native_file,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context, native_file)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
/// Move-construct a basic_stream_file from another.
/**
* This constructor moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
basic_stream_file(basic_stream_file&& other) noexcept
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_stream_file from another.
/**
* This assignment operator moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
basic_stream_file& operator=(basic_stream_file&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
/// Move-construct a basic_stream_file from a file of another executor
/// type.
/**
* This constructor moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_stream_file(basic_stream_file<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_stream_file from a file of another executor type.
/**
* This assignment operator moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_stream_file&
> operator=(basic_stream_file<Executor1>&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
/// Destroys the file.
/**
* This function destroys the file, cancelling any outstanding asynchronous
* operations associated with the file as if by calling @c cancel.
*/
~basic_stream_file()
{
}
/// Seek to a position in the file.
/**
* This function updates the current position in the file.
*
* @param offset The requested position in the file, relative to @c whence.
*
* @param whence One of @c seek_set, @c seek_cur or @c seek_end.
*
* @returns The new position relative to the beginning of the file.
*
* @throws asio::system_error Thrown on failure.
*/
uint64_t seek(int64_t offset, file_base::seek_basis whence)
{
asio::error_code ec;
uint64_t n = this->impl_.get_service().seek(
this->impl_.get_implementation(), offset, whence, ec);
asio::detail::throw_error(ec, "seek");
return n;
}
/// Seek to a position in the file.
/**
* This function updates the current position in the file.
*
* @param offset The requested position in the file, relative to @c whence.
*
* @param whence One of @c seek_set, @c seek_cur or @c seek_end.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The new position relative to the beginning of the file.
*/
uint64_t seek(int64_t offset, file_base::seek_basis whence,
asio::error_code& ec)
{
return this->impl_.get_service().seek(
this->impl_.get_implementation(), offset, whence, ec);
}
/// Write some data to the file.
/**
* This function is used to write data to the stream file. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the file.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the end of the file was reached.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* file.write_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().write_some(
this->impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "write_some");
return s;
}
/// Write some data to the file.
/**
* This function is used to write data to the stream file. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the file.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return this->impl_.get_service().write_some(
this->impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the stream file.
* It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
*
* @param buffers One or more data buffers to be written to the file.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* file.async_write_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteToken = default_completion_token_t<executor_type>>
auto async_write_some(const ConstBufferSequence& buffers,
WriteToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
declval<initiate_async_write_some>(), token, buffers))
{
return async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
initiate_async_write_some(this), token, buffers);
}
/// Read some data from the file.
/**
* This function is used to read data from the stream file. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the end of the file was reached.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* file.read_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().read_some(
this->impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "read_some");
return s;
}
/// Read some data from the file.
/**
* This function is used to read data from the stream file. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return this->impl_.get_service().read_some(
this->impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the stream file.
* It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* file.async_read_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadToken = default_completion_token_t<executor_type>>
auto async_read_some(const MutableBufferSequence& buffers,
ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
declval<initiate_async_read_some>(), token, buffers))
{
return async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
initiate_async_read_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_stream_file(const basic_stream_file&) = delete;
basic_stream_file& operator=(const basic_stream_file&) = delete;
class initiate_async_write_some
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some(basic_stream_file* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(WriteHandler&& handler,
const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_stream_file* self_;
};
class initiate_async_read_some
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some(basic_stream_file* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ReadHandler&& handler,
const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_read_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_stream_file* self_;
};
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_FILE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_STREAM_FILE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// basic_streambuf.hpp // basic_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -155,7 +155,7 @@ public:
* } * }
* @endcode * @endcode
*/ */
std::size_t size() const ASIO_NOEXCEPT std::size_t size() const noexcept
{ {
return pptr() - gptr(); return pptr() - gptr();
} }
@@ -165,7 +165,7 @@ public:
* @returns The allowed maximum of the sum of the sizes of the input sequence * @returns The allowed maximum of the sum of the sizes of the input sequence
* and output sequence. * and output sequence.
*/ */
std::size_t max_size() const ASIO_NOEXCEPT std::size_t max_size() const noexcept
{ {
return max_size_; return max_size_;
} }
@@ -175,7 +175,7 @@ public:
* @returns The current total capacity of the streambuf, i.e. for both the * @returns The current total capacity of the streambuf, i.e. for both the
* input sequence and output sequence. * input sequence and output sequence.
*/ */
std::size_t capacity() const ASIO_NOEXCEPT std::size_t capacity() const noexcept
{ {
return buffer_.capacity(); return buffer_.capacity();
} }
@@ -189,7 +189,7 @@ public:
* @note The returned object is invalidated by any @c basic_streambuf member * @note The returned object is invalidated by any @c basic_streambuf member
* function that modifies the input sequence or output sequence. * function that modifies the input sequence or output sequence.
*/ */
const_buffers_type data() const ASIO_NOEXCEPT const_buffers_type data() const noexcept
{ {
return asio::buffer(asio::const_buffer(gptr(), return asio::buffer(asio::const_buffer(gptr(),
(pptr() - gptr()) * sizeof(char_type))); (pptr() - gptr()) * sizeof(char_type)));
@@ -383,39 +383,37 @@ public:
} }
/// Copy construct a basic_streambuf_ref. /// Copy construct a basic_streambuf_ref.
basic_streambuf_ref(const basic_streambuf_ref& other) ASIO_NOEXCEPT basic_streambuf_ref(const basic_streambuf_ref& other) noexcept
: sb_(other.sb_) : sb_(other.sb_)
{ {
} }
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move construct a basic_streambuf_ref. /// Move construct a basic_streambuf_ref.
basic_streambuf_ref(basic_streambuf_ref&& other) ASIO_NOEXCEPT basic_streambuf_ref(basic_streambuf_ref&& other) noexcept
: sb_(other.sb_) : sb_(other.sb_)
{ {
} }
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Get the size of the input sequence. /// Get the size of the input sequence.
std::size_t size() const ASIO_NOEXCEPT std::size_t size() const noexcept
{ {
return sb_.size(); return sb_.size();
} }
/// Get the maximum size of the dynamic buffer. /// Get the maximum size of the dynamic buffer.
std::size_t max_size() const ASIO_NOEXCEPT std::size_t max_size() const noexcept
{ {
return sb_.max_size(); return sb_.max_size();
} }
/// Get the current capacity of the dynamic buffer. /// Get the current capacity of the dynamic buffer.
std::size_t capacity() const ASIO_NOEXCEPT std::size_t capacity() const noexcept
{ {
return sb_.capacity(); return sb_.capacity();
} }
/// Get a list of buffers that represents the input sequence. /// Get a list of buffers that represents the input sequence.
const_buffers_type data() const ASIO_NOEXCEPT const_buffers_type data() const noexcept
{ {
return sb_.data(); return sb_.data();
} }

View File

@@ -2,7 +2,7 @@
// basic_streambuf_fwd.hpp // basic_streambuf_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// basic_waitable_timer.hpp // basic_waitable_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -17,26 +17,17 @@
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#include <cstddef> #include <cstddef>
#include "asio/basic_io_object.hpp" #include <utility>
#include "asio/any_io_executor.hpp"
#include "asio/detail/chrono_time_traits.hpp"
#include "asio/detail/deadline_timer_service.hpp"
#include "asio/detail/handler_type_requirements.hpp" #include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp" #include "asio/detail/throw_error.hpp"
#include "asio/error.hpp" #include "asio/error.hpp"
#include "asio/wait_traits.hpp" #include "asio/wait_traits.hpp"
#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)
#if defined(ASIO_ENABLE_OLD_SERVICES)
# include "asio/waitable_timer_service.hpp"
#else // defined(ASIO_ENABLE_OLD_SERVICES)
# include "asio/detail/chrono_time_traits.hpp"
# include "asio/detail/deadline_timer_service.hpp"
# define ASIO_SVC_T \
detail::deadline_timer_service< \
detail::chrono_time_traits<Clock, WaitTraits> >
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
namespace asio { namespace asio {
@@ -46,8 +37,8 @@ namespace asio {
// Forward declaration with defaulted arguments. // Forward declaration with defaulted arguments.
template <typename Clock, template <typename Clock,
typename WaitTraits = asio::wait_traits<Clock> typename WaitTraits = asio::wait_traits<Clock>,
ASIO_SVC_TPARAM_DEF2(= waitable_timer_service<Clock, WaitTraits>)> typename Executor = any_io_executor>
class basic_waitable_timer; class basic_waitable_timer;
#endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) #endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
@@ -75,7 +66,7 @@ class basic_waitable_timer;
* Performing a blocking wait (C++11): * Performing a blocking wait (C++11):
* @code * @code
* // Construct a timer without setting an expiry time. * // Construct a timer without setting an expiry time.
* asio::steady_timer timer(io_context); * asio::steady_timer timer(my_context);
* *
* // Set an expiry time relative to now. * // Set an expiry time relative to now.
* timer.expires_after(std::chrono::seconds(5)); * timer.expires_after(std::chrono::seconds(5));
@@ -98,7 +89,7 @@ class basic_waitable_timer;
* ... * ...
* *
* // Construct a timer with an absolute expiry time. * // Construct a timer with an absolute expiry time.
* asio::steady_timer timer(io_context, * asio::steady_timer timer(my_context,
* std::chrono::steady_clock::now() + std::chrono::seconds(60)); * std::chrono::steady_clock::now() + std::chrono::seconds(60));
* *
* // Start an asynchronous wait. * // Start an asynchronous wait.
@@ -144,13 +135,23 @@ class basic_waitable_timer;
* @li If a wait handler is cancelled, the asio::error_code passed to * @li If a wait handler is cancelled, the asio::error_code passed to
* it contains the value asio::error::operation_aborted. * it contains the value asio::error::operation_aborted.
*/ */
template <typename Clock, typename WaitTraits ASIO_SVC_TPARAM> template <typename Clock, typename WaitTraits, typename Executor>
class basic_waitable_timer class basic_waitable_timer
: ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T>
{ {
private:
class initiate_async_wait;
public: public:
/// The type of the executor associated with the object. /// The type of the executor associated with the object.
typedef io_context::executor_type executor_type; typedef Executor executor_type;
/// Rebinds the timer type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The timer type when rebound to the specified executor.
typedef basic_waitable_timer<Clock, WaitTraits, Executor1> other;
};
/// The clock type. /// The clock type.
typedef Clock clock_type; typedef Clock clock_type;
@@ -170,11 +171,30 @@ public:
* expires_at() or expires_after() functions must be called to set an expiry * expires_at() or expires_after() functions must be called to set an expiry
* time before the timer can be waited on. * time before the timer can be waited on.
* *
* @param io_context The io_context object that the timer will use to dispatch * @param ex The I/O executor that the timer will use, by default, to
* handlers for any asynchronous operations performed on the timer. * dispatch handlers for any asynchronous operations performed on the timer.
*/ */
explicit basic_waitable_timer(asio::io_context& io_context) explicit basic_waitable_timer(const executor_type& ex)
: basic_io_object<ASIO_SVC_T>(io_context) : impl_(0, ex)
{
}
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_after() functions must be called to set an expiry
* time before the timer can be waited on.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{ {
} }
@@ -182,18 +202,41 @@ public:
/** /**
* This constructor creates a timer and sets the expiry time. * This constructor creates a timer and sets the expiry time.
* *
* @param io_context The io_context object that the timer will use to dispatch * @param ex The I/O executor object that the timer will use, by default, to
* handlers for any asynchronous operations performed on the timer. * dispatch handlers for any asynchronous operations performed on the timer.
* *
* @param expiry_time The expiry time to be used for the timer, expressed * @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time. * as an absolute time.
*/ */
basic_waitable_timer(asio::io_context& io_context, basic_waitable_timer(const executor_type& ex, const time_point& expiry_time)
const time_point& expiry_time) : impl_(0, ex)
: basic_io_object<ASIO_SVC_T>(io_context)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().expires_at(this->get_implementation(), expiry_time, ec); impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
const time_point& expiry_time,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at"); asio::detail::throw_error(ec, "expires_at");
} }
@@ -201,23 +244,46 @@ public:
/** /**
* This constructor creates a timer and sets the expiry time. * This constructor creates a timer and sets the expiry time.
* *
* @param io_context The io_context object that the timer will use to dispatch * @param ex The I/O executor that the timer will use, by default, to
* handlers for any asynchronous operations performed on the timer. * dispatch handlers for any asynchronous operations performed on the timer.
* *
* @param expiry_time The expiry time to be used for the timer, relative to * @param expiry_time The expiry time to be used for the timer, relative to
* now. * now.
*/ */
basic_waitable_timer(asio::io_context& io_context, basic_waitable_timer(const executor_type& ex, const duration& expiry_time)
const duration& expiry_time) : impl_(0, ex)
: basic_io_object<ASIO_SVC_T>(io_context)
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().expires_after( impl_.get_service().expires_after(
this->get_implementation(), expiry_time, ec); impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
const duration& expiry_time,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().expires_after(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after"); asio::detail::throw_error(ec, "expires_after");
} }
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_waitable_timer from another. /// Move-construct a basic_waitable_timer from another.
/** /**
* This constructor moves a timer from one object to another. * This constructor moves a timer from one object to another.
@@ -226,10 +292,11 @@ public:
* occur. * occur.
* *
* @note Following the move, the moved-from object is in the same state as if * @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(io_context&) constructor. * constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/ */
basic_waitable_timer(basic_waitable_timer&& other) basic_waitable_timer(basic_waitable_timer&& other)
: basic_io_object<ASIO_SVC_T>(std::move(other)) : impl_(std::move(other.impl_))
{ {
} }
@@ -242,14 +309,62 @@ public:
* occur. * occur.
* *
* @note Following the move, the moved-from object is in the same state as if * @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(io_context&) constructor. * constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/ */
basic_waitable_timer& operator=(basic_waitable_timer&& other) basic_waitable_timer& operator=(basic_waitable_timer&& other)
{ {
basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); impl_ = std::move(other.impl_);
return *this;
}
// All timers have access to each other's implementations.
template <typename Clock1, typename WaitTraits1, typename Executor1>
friend class basic_waitable_timer;
/// Move-construct a basic_waitable_timer from another.
/**
* This constructor moves a timer from one object to another.
*
* @param other The other basic_waitable_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_waitable_timer(
basic_waitable_timer<Clock, WaitTraits, Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value
> = 0)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_waitable_timer from another.
/**
* This assignment operator moves a timer from one object to another. Cancels
* any outstanding asynchronous operations associated with the target object.
*
* @param other The other basic_waitable_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_waitable_timer&
> operator=(basic_waitable_timer<Clock, WaitTraits, Executor1>&& other)
{
basic_waitable_timer tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this; return *this;
} }
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the timer. /// Destroys the timer.
/** /**
@@ -260,45 +375,11 @@ public:
{ {
} }
#if defined(ASIO_ENABLE_OLD_SERVICES)
// These functions are provided by basic_io_object<>.
#else // defined(ASIO_ENABLE_OLD_SERVICES)
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
/**
* This function may be used to obtain the io_context object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_context object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_context& get_io_context()
{
return basic_io_object<ASIO_SVC_T>::get_io_context();
}
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
/**
* This function may be used to obtain the io_context object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_context object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_context& get_io_service()
{
return basic_io_object<ASIO_SVC_T>::get_io_service();
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// Get the executor associated with the object. /// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT const executor_type& get_executor() noexcept
{ {
return basic_io_object<ASIO_SVC_T>::get_executor(); return impl_.get_executor();
} }
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
/// Cancel any asynchronous operations that are waiting on the timer. /// Cancel any asynchronous operations that are waiting on the timer.
/** /**
@@ -325,7 +406,7 @@ public:
std::size_t cancel() std::size_t cancel()
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().cancel(this->get_implementation(), ec); std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel"); asio::detail::throw_error(ec, "cancel");
return s; return s;
} }
@@ -356,7 +437,7 @@ public:
*/ */
std::size_t cancel(asio::error_code& ec) std::size_t cancel(asio::error_code& ec)
{ {
return this->get_service().cancel(this->get_implementation(), ec); return impl_.get_service().cancel(impl_.get_implementation(), ec);
} }
#endif // !defined(ASIO_NO_DEPRECATED) #endif // !defined(ASIO_NO_DEPRECATED)
@@ -387,8 +468,8 @@ public:
std::size_t cancel_one() std::size_t cancel_one()
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().cancel_one( std::size_t s = impl_.get_service().cancel_one(
this->get_implementation(), ec); impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel_one"); asio::detail::throw_error(ec, "cancel_one");
return s; return s;
} }
@@ -421,7 +502,7 @@ public:
*/ */
std::size_t cancel_one(asio::error_code& ec) std::size_t cancel_one(asio::error_code& ec)
{ {
return this->get_service().cancel_one(this->get_implementation(), ec); return impl_.get_service().cancel_one(impl_.get_implementation(), ec);
} }
/// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute /// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute
@@ -432,7 +513,7 @@ public:
*/ */
time_point expires_at() const time_point expires_at() const
{ {
return this->get_service().expires_at(this->get_implementation()); return impl_.get_service().expires_at(impl_.get_implementation());
} }
#endif // !defined(ASIO_NO_DEPRECATED) #endif // !defined(ASIO_NO_DEPRECATED)
@@ -443,7 +524,7 @@ public:
*/ */
time_point expiry() const time_point expiry() const
{ {
return this->get_service().expiry(this->get_implementation()); return impl_.get_service().expiry(impl_.get_implementation());
} }
/// Set the timer's expiry time as an absolute time. /// Set the timer's expiry time as an absolute time.
@@ -471,8 +552,8 @@ public:
std::size_t expires_at(const time_point& expiry_time) std::size_t expires_at(const time_point& expiry_time)
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().expires_at( std::size_t s = impl_.get_service().expires_at(
this->get_implementation(), expiry_time, ec); impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at"); asio::detail::throw_error(ec, "expires_at");
return s; return s;
} }
@@ -504,8 +585,8 @@ public:
std::size_t expires_at(const time_point& expiry_time, std::size_t expires_at(const time_point& expiry_time,
asio::error_code& ec) asio::error_code& ec)
{ {
return this->get_service().expires_at( return impl_.get_service().expires_at(
this->get_implementation(), expiry_time, ec); impl_.get_implementation(), expiry_time, ec);
} }
#endif // !defined(ASIO_NO_DEPRECATED) #endif // !defined(ASIO_NO_DEPRECATED)
@@ -534,8 +615,8 @@ public:
std::size_t expires_after(const duration& expiry_time) std::size_t expires_after(const duration& expiry_time)
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().expires_after( std::size_t s = impl_.get_service().expires_after(
this->get_implementation(), expiry_time, ec); impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after"); asio::detail::throw_error(ec, "expires_after");
return s; return s;
} }
@@ -548,7 +629,7 @@ public:
*/ */
duration expires_from_now() const duration expires_from_now() const
{ {
return this->get_service().expires_from_now(this->get_implementation()); return impl_.get_service().expires_from_now(impl_.get_implementation());
} }
/// (Deprecated: Use expires_after().) Set the timer's expiry time relative /// (Deprecated: Use expires_after().) Set the timer's expiry time relative
@@ -577,8 +658,8 @@ public:
std::size_t expires_from_now(const duration& expiry_time) std::size_t expires_from_now(const duration& expiry_time)
{ {
asio::error_code ec; asio::error_code ec;
std::size_t s = this->get_service().expires_from_now( std::size_t s = impl_.get_service().expires_from_now(
this->get_implementation(), expiry_time, ec); impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now"); asio::detail::throw_error(ec, "expires_from_now");
return s; return s;
} }
@@ -609,8 +690,8 @@ public:
std::size_t expires_from_now(const duration& expiry_time, std::size_t expires_from_now(const duration& expiry_time,
asio::error_code& ec) asio::error_code& ec)
{ {
return this->get_service().expires_from_now( return impl_.get_service().expires_from_now(
this->get_implementation(), expiry_time, ec); impl_.get_implementation(), expiry_time, ec);
} }
#endif // !defined(ASIO_NO_DEPRECATED) #endif // !defined(ASIO_NO_DEPRECATED)
@@ -624,7 +705,7 @@ public:
void wait() void wait()
{ {
asio::error_code ec; asio::error_code ec;
this->get_service().wait(this->get_implementation(), ec); impl_.get_service().wait(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "wait"); asio::detail::throw_error(ec, "wait");
} }
@@ -637,69 +718,107 @@ public:
*/ */
void wait(asio::error_code& ec) void wait(asio::error_code& ec)
{ {
this->get_service().wait(this->get_implementation(), ec); impl_.get_service().wait(impl_.get_implementation(), ec);
} }
/// Start an asynchronous wait on the timer. /// Start an asynchronous wait on the timer.
/** /**
* This function may be used to initiate an asynchronous wait against the * This function may be used to initiate an asynchronous wait against the
* timer. It always returns immediately. * timer. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
* *
* For each call to async_wait(), the supplied handler will be called exactly * For each call to async_wait(), the completion handler will be called
* once. The handler will be called when: * exactly once. The completion handler will be called when:
* *
* @li The timer has expired. * @li The timer has expired.
* *
* @li The timer was cancelled, in which case the handler is passed the error * @li The timer was cancelled, in which case the handler is passed the error
* code asio::error::operation_aborted. * code asio::error::operation_aborted.
* *
* @param handler The handler to be called when the timer expires. Copies * @param token The @ref completion_token that will be used to produce a
* will be made of the handler as required. The function signature of the * completion handler, which will be called when the timer expires. Potential
* handler must be: * completion tokens include @ref use_future, @ref use_awaitable, @ref
* yield_context, or a function object with the correct completion signature.
* The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* const asio::error_code& error // Result of operation. * const asio::error_code& error // Result of operation.
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code) @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/ */
template <typename WaitHandler> template <
ASIO_INITFN_RESULT_TYPE(WaitHandler, ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
void (asio::error_code)) WaitToken = default_completion_token_t<executor_type>>
async_wait(ASIO_MOVE_ARG(WaitHandler) handler) auto async_wait(
WaitToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WaitToken, void (asio::error_code)>(
declval<initiate_async_wait>(), token))
{ {
// If you get an error on the following line it means that your handler does return async_initiate<WaitToken, void (asio::error_code)>(
// not meet the documented type requirements for a WaitHandler. initiate_async_wait(this), token);
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
#if defined(ASIO_ENABLE_OLD_SERVICES)
return this->get_service().async_wait(this->get_implementation(),
ASIO_MOVE_CAST(WaitHandler)(handler));
#else // defined(ASIO_ENABLE_OLD_SERVICES)
async_completion<WaitHandler,
void (asio::error_code)> init(handler);
this->get_service().async_wait(this->get_implementation(),
init.completion_handler);
return init.result.get();
#endif // defined(ASIO_ENABLE_OLD_SERVICES)
} }
private: private:
// Disallow copying and assignment. // Disallow copying and assignment.
basic_waitable_timer(const basic_waitable_timer&) ASIO_DELETED; basic_waitable_timer(const basic_waitable_timer&) = delete;
basic_waitable_timer& operator=( basic_waitable_timer& operator=(const basic_waitable_timer&) = delete;
const basic_waitable_timer&) ASIO_DELETED;
class initiate_async_wait
{
public:
typedef Executor executor_type;
explicit initiate_async_wait(basic_waitable_timer* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WaitHandler>
void operator()(WaitHandler&& handler) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WaitHandler.
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
detail::non_const_lvalue<WaitHandler> handler2(handler);
self_->impl_.get_service().async_wait(
self_->impl_.get_implementation(),
handler2.value, self_->impl_.get_executor());
}
private:
basic_waitable_timer* self_;
};
detail::io_object_impl<
detail::deadline_timer_service<
detail::chrono_time_traits<Clock, WaitTraits>>,
executor_type > impl_;
}; };
} // namespace asio } // namespace asio
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
#if !defined(ASIO_ENABLE_OLD_SERVICES)
# undef ASIO_SVC_T
#endif // !defined(ASIO_ENABLE_OLD_SERVICES)
#endif // ASIO_BASIC_WAITABLE_TIMER_HPP #endif // ASIO_BASIC_WAITABLE_TIMER_HPP

View File

@@ -0,0 +1,622 @@
//
// basic_writable_pipe.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 ASIO_BASIC_WRITABLE_PIPE_HPP
#define ASIO_BASIC_WRITABLE_PIPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_PIPE) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include <utility>
#include "asio/any_io_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_handle_service.hpp"
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
# include "asio/detail/io_uring_descriptor_service.hpp"
#else
# include "asio/detail/reactive_descriptor_service.hpp"
#endif
#include "asio/detail/push_options.hpp"
namespace asio {
/// Provides pipe functionality.
/**
* The basic_writable_pipe class provides a wrapper over pipe
* functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor = any_io_executor>
class basic_writable_pipe
{
private:
class initiate_async_write_some;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the pipe type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The pipe type when rebound to the specified executor.
typedef basic_writable_pipe<Executor1> other;
};
/// The native representation of a pipe.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_handle_service::native_handle_type
native_handle_type;
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
typedef detail::io_uring_descriptor_service::native_handle_type
native_handle_type;
#else
typedef detail::reactive_descriptor_service::native_handle_type
native_handle_type;
#endif
/// A basic_writable_pipe is always the lowest layer.
typedef basic_writable_pipe lowest_layer_type;
/// Construct a basic_writable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param ex The I/O executor that the pipe will use, by default, to dispatch
* handlers for any asynchronous operations performed on the pipe.
*/
explicit basic_writable_pipe(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a basic_writable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any asynchronous
* operations performed on the pipe.
*/
template <typename ExecutionContext>
explicit basic_writable_pipe(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct a basic_writable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param ex The I/O executor that the pipe will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
basic_writable_pipe(const executor_type& ex,
const native_handle_type& native_pipe)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_writable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any
* asynchronous operations performed on the pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_writable_pipe(ExecutionContext& context,
const native_handle_type& native_pipe,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
/// Move-construct a basic_writable_pipe from another.
/**
* This constructor moves a pipe from one object to another.
*
* @param other The other basic_writable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_writable_pipe(const executor_type&)
* constructor.
*/
basic_writable_pipe(basic_writable_pipe&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_writable_pipe from another.
/**
* This assignment operator moves a pipe from one object to another.
*
* @param other The other basic_writable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_writable_pipe(const executor_type&)
* constructor.
*/
basic_writable_pipe& operator=(basic_writable_pipe&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
// All pipes have access to each other's implementations.
template <typename Executor1>
friend class basic_writable_pipe;
/// Move-construct a basic_writable_pipe from a pipe of another executor type.
/**
* This constructor moves a pipe from one object to another.
*
* @param other The other basic_writable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_writable_pipe(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_writable_pipe(basic_writable_pipe<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_writable_pipe from a pipe of another executor type.
/**
* This assignment operator moves a pipe from one object to another.
*
* @param other The other basic_writable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_writable_pipe(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_writable_pipe&
> operator=(basic_writable_pipe<Executor1>&& other)
{
basic_writable_pipe tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this;
}
/// Destroys the pipe.
/**
* This function destroys the pipe, cancelling any outstanding
* asynchronous wait operations associated with the pipe as if by
* calling @c cancel.
*/
~basic_writable_pipe()
{
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_writable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_writable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_pipe)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_pipe,
asio::error_code& ec)
{
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the pipe is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous write operations
* will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void close()
{
asio::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous write operations
* will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Release ownership of the underlying native pipe.
/**
* This function causes all outstanding asynchronous write operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error. Ownership of the
* native pipe is then transferred to the caller.
*
* @throws asio::system_error Thrown on failure.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with asio::error::operation_not_supported on
* these platforms.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release()
{
asio::error_code ec;
native_handle_type s = impl_.get_service().release(
impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "release");
return s;
}
/// Release ownership of the underlying native pipe.
/**
* This function causes all outstanding asynchronous write operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error. Ownership of the
* native pipe is then transferred to the caller.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with asio::error::operation_not_supported on
* these platforms.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release(asio::error_code& ec)
{
return impl_.get_service().release(impl_.get_implementation(), ec);
}
/// Get the native pipe representation.
/**
* This function may be used to obtain the underlying representation of the
* pipe. This is intended to allow access to native pipe
* functionality that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous write operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous write operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Write some data to the pipe.
/**
* This function is used to write data to the pipe. The function call will
* block until one or more bytes of the data has been written successfully,
* or until an error occurs.
*
* @param buffers One or more data buffers to be written to the pipe.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* pipe.write_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "write_some");
return s;
}
/// Write some data to the pipe.
/**
* This function is used to write data to the pipe. The function call will
* block until one or more bytes of the data has been written successfully,
* or until an error occurs.
*
* @param buffers One or more data buffers to be written to the pipe.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the pipe. It is an
* initiating function for an @ref asynchronous_operation, and always returns
* immediately.
*
* @param buffers One or more data buffers to be written to the pipe.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* pipe.async_write_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteToken = default_completion_token_t<executor_type>>
auto async_write_some(const ConstBufferSequence& buffers,
WriteToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
declval<initiate_async_write_some>(), token, buffers))
{
return async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
initiate_async_write_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_writable_pipe(const basic_writable_pipe&) = delete;
basic_writable_pipe& operator=(const basic_writable_pipe&) = delete;
class initiate_async_write_some
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some(basic_writable_pipe* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(WriteHandler&& handler,
const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_writable_pipe* self_;
};
#if defined(ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_handle_service, Executor> impl_;
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_;
#else
detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;
#endif
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_PIPE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_WRITABLE_PIPE_HPP

View File

@@ -0,0 +1,530 @@
//
// bind_allocator.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 ASIO_BIND_ALLOCATOR_HPP
#define ASIO_BIND_ALLOCATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/associated_allocator.hpp"
#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
// Helper to automatically define nested typedef result_type.
template <typename T, typename = void>
struct allocator_binder_result_type
{
protected:
typedef void result_type_or_void;
};
template <typename T>
struct allocator_binder_result_type<T, void_t<typename T::result_type>>
{
typedef typename T::result_type result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct allocator_binder_result_type<R(*)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct allocator_binder_result_type<R(&)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct allocator_binder_result_type<R(*)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct allocator_binder_result_type<R(&)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_result_type<R(*)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_result_type<R(&)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
// Helper to automatically define nested typedef argument_type.
template <typename T, typename = void>
struct allocator_binder_argument_type {};
template <typename T>
struct allocator_binder_argument_type<T, void_t<typename T::argument_type>>
{
typedef typename T::argument_type argument_type;
};
template <typename R, typename A1>
struct allocator_binder_argument_type<R(*)(A1)>
{
typedef A1 argument_type;
};
template <typename R, typename A1>
struct allocator_binder_argument_type<R(&)(A1)>
{
typedef A1 argument_type;
};
// Helper to automatically define nested typedefs first_argument_type and
// second_argument_type.
template <typename T, typename = void>
struct allocator_binder_argument_types {};
template <typename T>
struct allocator_binder_argument_types<T,
void_t<typename T::first_argument_type>>
{
typedef typename T::first_argument_type first_argument_type;
typedef typename T::second_argument_type second_argument_type;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_argument_type<R(*)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_argument_type<R(&)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
} // namespace detail
/// A call wrapper type to bind an allocator of type @c Allocator
/// to an object of type @c T.
template <typename T, typename Allocator>
class allocator_binder
#if !defined(GENERATING_DOCUMENTATION)
: public detail::allocator_binder_result_type<T>,
public detail::allocator_binder_argument_type<T>,
public detail::allocator_binder_argument_types<T>
#endif // !defined(GENERATING_DOCUMENTATION)
{
public:
/// The type of the target object.
typedef T target_type;
/// The type of the associated allocator.
typedef Allocator allocator_type;
#if defined(GENERATING_DOCUMENTATION)
/// The return type if a function.
/**
* The type of @c result_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to function type, @c result_type is a synonym for
* the return type of @c T;
*
* @li if @c T is a class type with a member type @c result_type, then @c
* result_type is a synonym for @c T::result_type;
*
* @li otherwise @c result_type is not defined.
*/
typedef see_below result_type;
/// The type of the function's argument.
/**
* The type of @c argument_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to a function type accepting a single argument,
* @c argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c argument_type, then @c
* argument_type is a synonym for @c T::argument_type;
*
* @li otherwise @c argument_type is not defined.
*/
typedef see_below argument_type;
/// The type of the function's first argument.
/**
* The type of @c first_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* first_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c first_argument_type is a synonym for @c T::first_argument_type;
*
* @li otherwise @c first_argument_type is not defined.
*/
typedef see_below first_argument_type;
/// The type of the function's second argument.
/**
* The type of @c second_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* second_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c second_argument_type is a synonym for @c T::second_argument_type;
*
* @li otherwise @c second_argument_type is not defined.
*/
typedef see_below second_argument_type;
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct an allocator wrapper for the specified object.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U>
allocator_binder(const allocator_type& s, U&& u)
: allocator_(s),
target_(static_cast<U&&>(u))
{
}
/// Copy constructor.
allocator_binder(const allocator_binder& other)
: allocator_(other.get_allocator()),
target_(other.get())
{
}
/// Construct a copy, but specify a different allocator.
allocator_binder(const allocator_type& s, const allocator_binder& other)
: allocator_(s),
target_(other.get())
{
}
/// Construct a copy of a different allocator wrapper type.
/**
* This constructor is only valid if the @c Allocator type is
* constructible from type @c OtherAllocator, and the type @c T is
* constructible from type @c U.
*/
template <typename U, typename OtherAllocator>
allocator_binder(const allocator_binder<U, OtherAllocator>& other,
constraint_t<is_constructible<Allocator, OtherAllocator>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: allocator_(other.get_allocator()),
target_(other.get())
{
}
/// Construct a copy of a different allocator wrapper type, but
/// specify a different allocator.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherAllocator>
allocator_binder(const allocator_type& s,
const allocator_binder<U, OtherAllocator>& other,
constraint_t<is_constructible<T, U>::value> = 0)
: allocator_(s),
target_(other.get())
{
}
/// Move constructor.
allocator_binder(allocator_binder&& other)
: allocator_(static_cast<allocator_type&&>(
other.get_allocator())),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct the target object, but specify a different allocator.
allocator_binder(const allocator_type& s,
allocator_binder&& other)
: allocator_(s),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct from a different allocator wrapper type.
template <typename U, typename OtherAllocator>
allocator_binder(
allocator_binder<U, OtherAllocator>&& other,
constraint_t<is_constructible<Allocator, OtherAllocator>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: allocator_(static_cast<OtherAllocator&&>(
other.get_allocator())),
target_(static_cast<U&&>(other.get()))
{
}
/// Move construct from a different allocator wrapper type, but
/// specify a different allocator.
template <typename U, typename OtherAllocator>
allocator_binder(const allocator_type& s,
allocator_binder<U, OtherAllocator>&& other,
constraint_t<is_constructible<T, U>::value> = 0)
: allocator_(s),
target_(static_cast<U&&>(other.get()))
{
}
/// Destructor.
~allocator_binder()
{
}
/// Obtain a reference to the target object.
target_type& get() noexcept
{
return target_;
}
/// Obtain a reference to the target object.
const target_type& get() const noexcept
{
return target_;
}
/// Obtain the associated allocator.
allocator_type get_allocator() const noexcept
{
return allocator_;
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args)
{
return target_(static_cast<Args&&>(args)...);
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args) const
{
return target_(static_cast<Args&&>(args)...);
}
private:
Allocator allocator_;
T target_;
};
/// Associate an object of type @c T with an allocator of type
/// @c Allocator.
template <typename Allocator, typename T>
ASIO_NODISCARD inline allocator_binder<decay_t<T>, Allocator>
bind_allocator(const Allocator& s, T&& t)
{
return allocator_binder<decay_t<T>, Allocator>(s, static_cast<T&&>(t));
}
#if !defined(GENERATING_DOCUMENTATION)
namespace detail {
template <typename TargetAsyncResult, typename Allocator, typename = void>
class allocator_binder_completion_handler_async_result
{
public:
template <typename T>
explicit allocator_binder_completion_handler_async_result(T&)
{
}
};
template <typename TargetAsyncResult, typename Allocator>
class allocator_binder_completion_handler_async_result<
TargetAsyncResult, Allocator,
void_t<typename TargetAsyncResult::completion_handler_type>>
{
private:
TargetAsyncResult target_;
public:
typedef allocator_binder<
typename TargetAsyncResult::completion_handler_type, Allocator>
completion_handler_type;
explicit allocator_binder_completion_handler_async_result(
typename TargetAsyncResult::completion_handler_type& handler)
: target_(handler)
{
}
auto get() -> decltype(target_.get())
{
return target_.get();
}
};
template <typename TargetAsyncResult, typename = void>
struct allocator_binder_async_result_return_type
{
};
template <typename TargetAsyncResult>
struct allocator_binder_async_result_return_type<
TargetAsyncResult, void_type<typename TargetAsyncResult::return_type>>
{
typedef typename TargetAsyncResult::return_type return_type;
};
} // namespace detail
template <typename T, typename Allocator, typename Signature>
class async_result<allocator_binder<T, Allocator>, Signature> :
public detail::allocator_binder_completion_handler_async_result<
async_result<T, Signature>, Allocator>,
public detail::allocator_binder_async_result_return_type<
async_result<T, Signature>>
{
public:
explicit async_result(allocator_binder<T, Allocator>& b)
: detail::allocator_binder_completion_handler_async_result<
async_result<T, Signature>, Allocator>(b.get())
{
}
template <typename Initiation>
struct init_wrapper
{
template <typename Init>
init_wrapper(const Allocator& allocator, Init&& init)
: allocator_(allocator),
initiation_(static_cast<Init&&>(init))
{
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args)
{
static_cast<Initiation&&>(initiation_)(
allocator_binder<decay_t<Handler>, Allocator>(
allocator_, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) const
{
initiation_(
allocator_binder<decay_t<Handler>, Allocator>(
allocator_, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
Allocator allocator_;
Initiation initiation_;
};
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<T, Signature>(
declval<init_wrapper<decay_t<Initiation>>>(),
token.get(), static_cast<Args&&>(args)...))
{
return async_initiate<T, Signature>(
init_wrapper<decay_t<Initiation>>(token.get_allocator(),
static_cast<Initiation&&>(initiation)),
token.get(), static_cast<Args&&>(args)...);
}
private:
async_result(const async_result&) = delete;
async_result& operator=(const async_result&) = delete;
async_result<T, Signature> target_;
};
template <template <typename, typename> class Associator,
typename T, typename Allocator, typename DefaultCandidate>
struct associator<Associator, allocator_binder<T, Allocator>, DefaultCandidate>
: Associator<T, DefaultCandidate>
{
static typename Associator<T, DefaultCandidate>::type get(
const allocator_binder<T, Allocator>& b) noexcept
{
return Associator<T, DefaultCandidate>::get(b.get());
}
static auto get(const allocator_binder<T, Allocator>& b,
const DefaultCandidate& c) noexcept
-> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
{
return Associator<T, DefaultCandidate>::get(b.get(), c);
}
};
template <typename T, typename Allocator, typename Allocator1>
struct associated_allocator<allocator_binder<T, Allocator>, Allocator1>
{
typedef Allocator type;
static auto get(const allocator_binder<T, Allocator>& b,
const Allocator1& = Allocator1()) noexcept
-> decltype(b.get_allocator())
{
return b.get_allocator();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BIND_ALLOCATOR_HPP

View File

@@ -0,0 +1,544 @@
//
// bind_cancellation_slot.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 ASIO_BIND_CANCELLATION_SLOT_HPP
#define ASIO_BIND_CANCELLATION_SLOT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/associated_cancellation_slot.hpp"
#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
// Helper to automatically define nested typedef result_type.
template <typename T, typename = void>
struct cancellation_slot_binder_result_type
{
protected:
typedef void result_type_or_void;
};
template <typename T>
struct cancellation_slot_binder_result_type<T, void_t<typename T::result_type>>
{
typedef typename T::result_type result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct cancellation_slot_binder_result_type<R(*)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct cancellation_slot_binder_result_type<R(&)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct cancellation_slot_binder_result_type<R(*)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct cancellation_slot_binder_result_type<R(&)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_result_type<R(*)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_result_type<R(&)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
// Helper to automatically define nested typedef argument_type.
template <typename T, typename = void>
struct cancellation_slot_binder_argument_type {};
template <typename T>
struct cancellation_slot_binder_argument_type<T,
void_t<typename T::argument_type>>
{
typedef typename T::argument_type argument_type;
};
template <typename R, typename A1>
struct cancellation_slot_binder_argument_type<R(*)(A1)>
{
typedef A1 argument_type;
};
template <typename R, typename A1>
struct cancellation_slot_binder_argument_type<R(&)(A1)>
{
typedef A1 argument_type;
};
// Helper to automatically define nested typedefs first_argument_type and
// second_argument_type.
template <typename T, typename = void>
struct cancellation_slot_binder_argument_types {};
template <typename T>
struct cancellation_slot_binder_argument_types<T,
void_t<typename T::first_argument_type>>
{
typedef typename T::first_argument_type first_argument_type;
typedef typename T::second_argument_type second_argument_type;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_argument_type<R(*)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_argument_type<R(&)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
} // namespace detail
/// A call wrapper type to bind a cancellation slot of type @c CancellationSlot
/// to an object of type @c T.
template <typename T, typename CancellationSlot>
class cancellation_slot_binder
#if !defined(GENERATING_DOCUMENTATION)
: public detail::cancellation_slot_binder_result_type<T>,
public detail::cancellation_slot_binder_argument_type<T>,
public detail::cancellation_slot_binder_argument_types<T>
#endif // !defined(GENERATING_DOCUMENTATION)
{
public:
/// The type of the target object.
typedef T target_type;
/// The type of the associated cancellation slot.
typedef CancellationSlot cancellation_slot_type;
#if defined(GENERATING_DOCUMENTATION)
/// The return type if a function.
/**
* The type of @c result_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to function type, @c result_type is a synonym for
* the return type of @c T;
*
* @li if @c T is a class type with a member type @c result_type, then @c
* result_type is a synonym for @c T::result_type;
*
* @li otherwise @c result_type is not defined.
*/
typedef see_below result_type;
/// The type of the function's argument.
/**
* The type of @c argument_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to a function type accepting a single argument,
* @c argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c argument_type, then @c
* argument_type is a synonym for @c T::argument_type;
*
* @li otherwise @c argument_type is not defined.
*/
typedef see_below argument_type;
/// The type of the function's first argument.
/**
* The type of @c first_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* first_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c first_argument_type is a synonym for @c T::first_argument_type;
*
* @li otherwise @c first_argument_type is not defined.
*/
typedef see_below first_argument_type;
/// The type of the function's second argument.
/**
* The type of @c second_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* second_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c second_argument_type is a synonym for @c T::second_argument_type;
*
* @li otherwise @c second_argument_type is not defined.
*/
typedef see_below second_argument_type;
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct a cancellation slot wrapper for the specified object.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U>
cancellation_slot_binder(const cancellation_slot_type& s, U&& u)
: slot_(s),
target_(static_cast<U&&>(u))
{
}
/// Copy constructor.
cancellation_slot_binder(const cancellation_slot_binder& other)
: slot_(other.get_cancellation_slot()),
target_(other.get())
{
}
/// Construct a copy, but specify a different cancellation slot.
cancellation_slot_binder(const cancellation_slot_type& s,
const cancellation_slot_binder& other)
: slot_(s),
target_(other.get())
{
}
/// Construct a copy of a different cancellation slot wrapper type.
/**
* This constructor is only valid if the @c CancellationSlot type is
* constructible from type @c OtherCancellationSlot, and the type @c T is
* constructible from type @c U.
*/
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(
const cancellation_slot_binder<U, OtherCancellationSlot>& other,
constraint_t<is_constructible<CancellationSlot,
OtherCancellationSlot>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: slot_(other.get_cancellation_slot()),
target_(other.get())
{
}
/// Construct a copy of a different cancellation slot wrapper type, but
/// specify a different cancellation slot.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(const cancellation_slot_type& s,
const cancellation_slot_binder<U, OtherCancellationSlot>& other,
constraint_t<is_constructible<T, U>::value> = 0)
: slot_(s),
target_(other.get())
{
}
/// Move constructor.
cancellation_slot_binder(cancellation_slot_binder&& other)
: slot_(static_cast<cancellation_slot_type&&>(
other.get_cancellation_slot())),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct the target object, but specify a different cancellation
/// slot.
cancellation_slot_binder(const cancellation_slot_type& s,
cancellation_slot_binder&& other)
: slot_(s),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct from a different cancellation slot wrapper type.
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(
cancellation_slot_binder<U, OtherCancellationSlot>&& other,
constraint_t<is_constructible<CancellationSlot,
OtherCancellationSlot>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: slot_(static_cast<OtherCancellationSlot&&>(
other.get_cancellation_slot())),
target_(static_cast<U&&>(other.get()))
{
}
/// Move construct from a different cancellation slot wrapper type, but
/// specify a different cancellation slot.
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(const cancellation_slot_type& s,
cancellation_slot_binder<U, OtherCancellationSlot>&& other,
constraint_t<is_constructible<T, U>::value> = 0)
: slot_(s),
target_(static_cast<U&&>(other.get()))
{
}
/// Destructor.
~cancellation_slot_binder()
{
}
/// Obtain a reference to the target object.
target_type& get() noexcept
{
return target_;
}
/// Obtain a reference to the target object.
const target_type& get() const noexcept
{
return target_;
}
/// Obtain the associated cancellation slot.
cancellation_slot_type get_cancellation_slot() const noexcept
{
return slot_;
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args)
{
return target_(static_cast<Args&&>(args)...);
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args) const
{
return target_(static_cast<Args&&>(args)...);
}
private:
CancellationSlot slot_;
T target_;
};
/// Associate an object of type @c T with a cancellation slot of type
/// @c CancellationSlot.
template <typename CancellationSlot, typename T>
ASIO_NODISCARD inline
cancellation_slot_binder<decay_t<T>, CancellationSlot>
bind_cancellation_slot(const CancellationSlot& s, T&& t)
{
return cancellation_slot_binder<decay_t<T>, CancellationSlot>(
s, static_cast<T&&>(t));
}
#if !defined(GENERATING_DOCUMENTATION)
namespace detail {
template <typename TargetAsyncResult,
typename CancellationSlot, typename = void>
class cancellation_slot_binder_completion_handler_async_result
{
public:
template <typename T>
explicit cancellation_slot_binder_completion_handler_async_result(T&)
{
}
};
template <typename TargetAsyncResult, typename CancellationSlot>
class cancellation_slot_binder_completion_handler_async_result<
TargetAsyncResult, CancellationSlot,
void_t<typename TargetAsyncResult::completion_handler_type>>
{
private:
TargetAsyncResult target_;
public:
typedef cancellation_slot_binder<
typename TargetAsyncResult::completion_handler_type, CancellationSlot>
completion_handler_type;
explicit cancellation_slot_binder_completion_handler_async_result(
typename TargetAsyncResult::completion_handler_type& handler)
: target_(handler)
{
}
auto get() -> decltype(target_.get())
{
return target_.get();
}
};
template <typename TargetAsyncResult, typename = void>
struct cancellation_slot_binder_async_result_return_type
{
};
template <typename TargetAsyncResult>
struct cancellation_slot_binder_async_result_return_type<
TargetAsyncResult, void_t<typename TargetAsyncResult::return_type>>
{
typedef typename TargetAsyncResult::return_type return_type;
};
} // namespace detail
template <typename T, typename CancellationSlot, typename Signature>
class async_result<cancellation_slot_binder<T, CancellationSlot>, Signature> :
public detail::cancellation_slot_binder_completion_handler_async_result<
async_result<T, Signature>, CancellationSlot>,
public detail::cancellation_slot_binder_async_result_return_type<
async_result<T, Signature>>
{
public:
explicit async_result(cancellation_slot_binder<T, CancellationSlot>& b)
: detail::cancellation_slot_binder_completion_handler_async_result<
async_result<T, Signature>, CancellationSlot>(b.get())
{
}
template <typename Initiation>
struct init_wrapper
{
template <typename Init>
init_wrapper(const CancellationSlot& slot, Init&& init)
: slot_(slot),
initiation_(static_cast<Init&&>(init))
{
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args)
{
static_cast<Initiation&&>(initiation_)(
cancellation_slot_binder<decay_t<Handler>, CancellationSlot>(
slot_, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) const
{
initiation_(
cancellation_slot_binder<decay_t<Handler>, CancellationSlot>(
slot_, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
CancellationSlot slot_;
Initiation initiation_;
};
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<T, Signature>(
declval<init_wrapper<decay_t<Initiation>>>(),
token.get(), static_cast<Args&&>(args)...))
{
return async_initiate<T, Signature>(
init_wrapper<decay_t<Initiation>>(
token.get_cancellation_slot(),
static_cast<Initiation&&>(initiation)),
token.get(), static_cast<Args&&>(args)...);
}
private:
async_result(const async_result&) = delete;
async_result& operator=(const async_result&) = delete;
async_result<T, Signature> target_;
};
template <template <typename, typename> class Associator,
typename T, typename CancellationSlot, typename DefaultCandidate>
struct associator<Associator,
cancellation_slot_binder<T, CancellationSlot>,
DefaultCandidate>
: Associator<T, DefaultCandidate>
{
static typename Associator<T, DefaultCandidate>::type get(
const cancellation_slot_binder<T, CancellationSlot>& b) noexcept
{
return Associator<T, DefaultCandidate>::get(b.get());
}
static auto get(const cancellation_slot_binder<T, CancellationSlot>& b,
const DefaultCandidate& c) noexcept
-> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
{
return Associator<T, DefaultCandidate>::get(b.get(), c);
}
};
template <typename T, typename CancellationSlot, typename CancellationSlot1>
struct associated_cancellation_slot<
cancellation_slot_binder<T, CancellationSlot>,
CancellationSlot1>
{
typedef CancellationSlot type;
static auto get(const cancellation_slot_binder<T, CancellationSlot>& b,
const CancellationSlot1& = CancellationSlot1()) noexcept
-> decltype(b.get_cancellation_slot())
{
return b.get_cancellation_slot();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BIND_CANCELLATION_SLOT_HPP

View File

@@ -2,7 +2,7 @@
// bind_executor.hpp // bind_executor.hpp
// ~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -17,10 +17,10 @@
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp" #include "asio/detail/type_traits.hpp"
#include "asio/detail/variadic_templates.hpp"
#include "asio/associated_executor.hpp" #include "asio/associated_executor.hpp"
#include "asio/associated_allocator.hpp" #include "asio/associator.hpp"
#include "asio/async_result.hpp" #include "asio/async_result.hpp"
#include "asio/execution/executor.hpp"
#include "asio/execution_context.hpp" #include "asio/execution_context.hpp"
#include "asio/is_executor.hpp" #include "asio/is_executor.hpp"
#include "asio/uses_executor.hpp" #include "asio/uses_executor.hpp"
@@ -30,12 +30,6 @@
namespace asio { namespace asio {
namespace detail { namespace detail {
template <typename T>
struct executor_binder_check
{
typedef void type;
};
// Helper to automatically define nested typedef result_type. // Helper to automatically define nested typedef result_type.
template <typename T, typename = void> template <typename T, typename = void>
@@ -46,8 +40,7 @@ protected:
}; };
template <typename T> template <typename T>
struct executor_binder_result_type<T, struct executor_binder_result_type<T, void_t<typename T::result_type>>
typename executor_binder_check<typename T::result_type>::type>
{ {
typedef typename T::result_type result_type; typedef typename T::result_type result_type;
protected: protected:
@@ -108,8 +101,7 @@ template <typename T, typename = void>
struct executor_binder_argument_type {}; struct executor_binder_argument_type {};
template <typename T> template <typename T>
struct executor_binder_argument_type<T, struct executor_binder_argument_type<T, void_t<typename T::argument_type>>
typename executor_binder_check<typename T::argument_type>::type>
{ {
typedef typename T::argument_type argument_type; typedef typename T::argument_type argument_type;
}; };
@@ -134,7 +126,7 @@ struct executor_binder_argument_types {};
template <typename T> template <typename T>
struct executor_binder_argument_types<T, struct executor_binder_argument_types<T,
typename executor_binder_check<typename T::first_argument_type>::type> void_t<typename T::first_argument_type>>
{ {
typedef typename T::first_argument_type first_argument_type; typedef typename T::first_argument_type first_argument_type;
typedef typename T::second_argument_type second_argument_type; typedef typename T::second_argument_type second_argument_type;
@@ -154,22 +146,20 @@ struct executor_binder_argument_type<R(&)(A1, A2)>
typedef A2 second_argument_type; typedef A2 second_argument_type;
}; };
// Helper to: // Helper to perform uses_executor construction of the target type, if
// - Apply the empty base optimisation to the executor. // required.
// - Perform uses_executor construction of the target type, if required.
template <typename T, typename Executor, bool UsesExecutor> template <typename T, typename Executor, bool UsesExecutor>
class executor_binder_base; class executor_binder_base;
template <typename T, typename Executor> template <typename T, typename Executor>
class executor_binder_base<T, Executor, true> class executor_binder_base<T, Executor, true>
: protected Executor
{ {
protected: protected:
template <typename E, typename U> template <typename E, typename U>
executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u) executor_binder_base(E&& e, U&& u)
: executor_(ASIO_MOVE_CAST(E)(e)), : executor_(static_cast<E&&>(e)),
target_(executor_arg_t(), executor_, ASIO_MOVE_CAST(U)(u)) target_(executor_arg_t(), executor_, static_cast<U&&>(u))
{ {
} }
@@ -182,9 +172,9 @@ class executor_binder_base<T, Executor, false>
{ {
protected: protected:
template <typename E, typename U> template <typename E, typename U>
executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u) executor_binder_base(E&& e, U&& u)
: executor_(ASIO_MOVE_CAST(E)(e)), : executor_(static_cast<E&&>(e)),
target_(ASIO_MOVE_CAST(U)(u)) target_(static_cast<U&&>(u))
{ {
} }
@@ -192,21 +182,6 @@ protected:
T target_; T target_;
}; };
// Helper to enable SFINAE on zero-argument operator() below.
template <typename T, typename = void>
struct executor_binder_result_of0
{
typedef void type;
};
template <typename T>
struct executor_binder_result_of0<T,
typename executor_binder_check<typename result_of<T()>::type>::type>
{
typedef typename result_of<T()>::type type;
};
} // namespace detail } // namespace detail
/// A call wrapper type to bind an executor of type @c Executor to an object of /// A call wrapper type to bind an executor of type @c Executor to an object of
@@ -297,8 +272,8 @@ public:
*/ */
template <typename U> template <typename U>
executor_binder(executor_arg_t, const executor_type& e, executor_binder(executor_arg_t, const executor_type& e,
ASIO_MOVE_ARG(U) u) U&& u)
: base_type(e, ASIO_MOVE_CAST(U)(u)) : base_type(e, static_cast<U&&>(u))
{ {
} }
@@ -322,7 +297,9 @@ public:
* @c U. * @c U.
*/ */
template <typename U, typename OtherExecutor> template <typename U, typename OtherExecutor>
executor_binder(const executor_binder<U, OtherExecutor>& other) executor_binder(const executor_binder<U, OtherExecutor>& other,
constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: base_type(other.get_executor(), other.get()) : base_type(other.get_executor(), other.get())
{ {
} }
@@ -335,32 +312,33 @@ public:
*/ */
template <typename U, typename OtherExecutor> template <typename U, typename OtherExecutor>
executor_binder(executor_arg_t, const executor_type& e, executor_binder(executor_arg_t, const executor_type& e,
const executor_binder<U, OtherExecutor>& other) const executor_binder<U, OtherExecutor>& other,
constraint_t<is_constructible<T, U>::value> = 0)
: base_type(e, other.get()) : base_type(e, other.get())
{ {
} }
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move constructor. /// Move constructor.
executor_binder(executor_binder&& other) executor_binder(executor_binder&& other)
: base_type(ASIO_MOVE_CAST(executor_type)(other.get_executor()), : base_type(static_cast<executor_type&&>(other.get_executor()),
ASIO_MOVE_CAST(T)(other.get())) static_cast<T&&>(other.get()))
{ {
} }
/// Move construct the target object, but specify a different executor. /// Move construct the target object, but specify a different executor.
executor_binder(executor_arg_t, const executor_type& e, executor_binder(executor_arg_t, const executor_type& e,
executor_binder&& other) executor_binder&& other)
: base_type(e, ASIO_MOVE_CAST(T)(other.get())) : base_type(e, static_cast<T&&>(other.get()))
{ {
} }
/// Move construct from a different executor wrapper type. /// Move construct from a different executor wrapper type.
template <typename U, typename OtherExecutor> template <typename U, typename OtherExecutor>
executor_binder(executor_binder<U, OtherExecutor>&& other) executor_binder(executor_binder<U, OtherExecutor>&& other,
: base_type(ASIO_MOVE_CAST(OtherExecutor)(other.get_executor()), constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
ASIO_MOVE_CAST(U)(other.get())) constraint_t<is_constructible<T, U>::value> = 0)
: base_type(static_cast<OtherExecutor&&>(other.get_executor()),
static_cast<U&&>(other.get()))
{ {
} }
@@ -368,124 +346,49 @@ public:
/// different executor. /// different executor.
template <typename U, typename OtherExecutor> template <typename U, typename OtherExecutor>
executor_binder(executor_arg_t, const executor_type& e, executor_binder(executor_arg_t, const executor_type& e,
executor_binder<U, OtherExecutor>&& other) executor_binder<U, OtherExecutor>&& other,
: base_type(e, ASIO_MOVE_CAST(U)(other.get())) constraint_t<is_constructible<T, U>::value> = 0)
: base_type(e, static_cast<U&&>(other.get()))
{ {
} }
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destructor. /// Destructor.
~executor_binder() ~executor_binder()
{ {
} }
/// Obtain a reference to the target object. /// Obtain a reference to the target object.
target_type& get() ASIO_NOEXCEPT target_type& get() noexcept
{ {
return this->target_; return this->target_;
} }
/// Obtain a reference to the target object. /// Obtain a reference to the target object.
const target_type& get() const ASIO_NOEXCEPT const target_type& get() const noexcept
{ {
return this->target_; return this->target_;
} }
/// Obtain the associated executor. /// Obtain the associated executor.
executor_type get_executor() const ASIO_NOEXCEPT executor_type get_executor() const noexcept
{ {
return this->executor_; return this->executor_;
} }
#if defined(GENERATING_DOCUMENTATION)
template <typename... Args> auto operator()(Args&& ...);
template <typename... Args> auto operator()(Args&& ...) const;
#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
/// Forwarding function call operator. /// Forwarding function call operator.
template <typename... Args> template <typename... Args>
typename result_of<T(Args...)>::type operator()( result_of_t<T(Args...)> operator()(Args&&... args)
ASIO_MOVE_ARG(Args)... args)
{ {
return this->target_(ASIO_MOVE_CAST(Args)(args)...); return this->target_(static_cast<Args&&>(args)...);
} }
/// Forwarding function call operator. /// Forwarding function call operator.
template <typename... Args> template <typename... Args>
typename result_of<T(Args...)>::type operator()( result_of_t<T(Args...)> operator()(Args&&... args) const
ASIO_MOVE_ARG(Args)... args) const
{ {
return this->target_(ASIO_MOVE_CAST(Args)(args)...); return this->target_(static_cast<Args&&>(args)...);
} }
#elif defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
typename detail::executor_binder_result_of0<T>::type operator()()
{
return this->target_();
}
typename detail::executor_binder_result_of0<T>::type operator()() const
{
return this->target_();
}
#define ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <ASIO_VARIADIC_TPARAMS(n)> \
typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) const \
{ \
return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF)
#undef ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF
#else // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
typedef typename detail::executor_binder_result_type<T>::result_type_or_void
result_type_or_void;
result_type_or_void operator()()
{
return this->target_();
}
result_type_or_void operator()() const
{
return this->target_();
}
#define ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
result_type_or_void operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <ASIO_VARIADIC_TPARAMS(n)> \
result_type_or_void operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) const \
{ \
return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF)
#undef ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF
#endif // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
private: private:
typedef detail::executor_binder_base<T, Executor, typedef detail::executor_binder_base<T, Executor,
uses_executor<T, Executor>::value> base_type; uses_executor<T, Executor>::value> base_type;
@@ -493,25 +396,27 @@ private:
/// Associate an object of type @c T with an executor of type @c Executor. /// Associate an object of type @c T with an executor of type @c Executor.
template <typename Executor, typename T> template <typename Executor, typename T>
inline executor_binder<typename decay<T>::type, Executor> ASIO_NODISCARD inline executor_binder<decay_t<T>, Executor>
bind_executor(const Executor& ex, ASIO_MOVE_ARG(T) t, bind_executor(const Executor& ex, T&& t,
typename enable_if<is_executor<Executor>::value>::type* = 0) constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
{ {
return executor_binder<typename decay<T>::type, Executor>( return executor_binder<decay_t<T>, Executor>(
executor_arg_t(), ex, ASIO_MOVE_CAST(T)(t)); executor_arg_t(), ex, static_cast<T&&>(t));
} }
/// Associate an object of type @c T with an execution context's executor. /// Associate an object of type @c T with an execution context's executor.
template <typename ExecutionContext, typename T> template <typename ExecutionContext, typename T>
inline executor_binder<typename decay<T>::type, ASIO_NODISCARD inline executor_binder<decay_t<T>,
typename ExecutionContext::executor_type> typename ExecutionContext::executor_type>
bind_executor(ExecutionContext& ctx, ASIO_MOVE_ARG(T) t, bind_executor(ExecutionContext& ctx, T&& t,
typename enable_if<is_convertible< constraint_t<
ExecutionContext&, execution_context&>::value>::type* = 0) is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
{ {
return executor_binder<typename decay<T>::type, return executor_binder<decay_t<T>, typename ExecutionContext::executor_type>(
typename ExecutionContext::executor_type>( executor_arg_t(), ctx.get_executor(), static_cast<T&&>(t));
executor_arg_t(), ctx.get_executor(), ASIO_MOVE_CAST(T)(t));
} }
#if !defined(GENERATING_DOCUMENTATION) #if !defined(GENERATING_DOCUMENTATION)
@@ -520,73 +425,138 @@ template <typename T, typename Executor>
struct uses_executor<executor_binder<T, Executor>, Executor> struct uses_executor<executor_binder<T, Executor>, Executor>
: true_type {}; : true_type {};
template <typename T, typename Executor, typename Signature> namespace detail {
class async_result<executor_binder<T, Executor>, Signature>
template <typename TargetAsyncResult, typename Executor, typename = void>
class executor_binder_completion_handler_async_result
{ {
public:
template <typename T>
explicit executor_binder_completion_handler_async_result(T&)
{
}
};
template <typename TargetAsyncResult, typename Executor>
class executor_binder_completion_handler_async_result<
TargetAsyncResult, Executor,
void_t<typename TargetAsyncResult::completion_handler_type >>
{
private:
TargetAsyncResult target_;
public: public:
typedef executor_binder< typedef executor_binder<
typename async_result<T, Signature>::completion_handler_type, Executor> typename TargetAsyncResult::completion_handler_type, Executor>
completion_handler_type; completion_handler_type;
typedef typename async_result<T, Signature>::return_type return_type; explicit executor_binder_completion_handler_async_result(
typename TargetAsyncResult::completion_handler_type& handler)
explicit async_result(executor_binder<T, Executor>& b) : target_(handler)
: target_(b.get())
{ {
} }
return_type get() auto get() -> decltype(target_.get())
{ {
return target_.get(); return target_.get();
} }
private:
async_result(const async_result&) ASIO_DELETED;
async_result& operator=(const async_result&) ASIO_DELETED;
async_result<T, Signature> target_;
}; };
#if !defined(ASIO_NO_DEPRECATED) template <typename TargetAsyncResult, typename = void>
struct executor_binder_async_result_return_type
{
};
template <typename TargetAsyncResult>
struct executor_binder_async_result_return_type<TargetAsyncResult,
void_t<typename TargetAsyncResult::return_type>>
{
typedef typename TargetAsyncResult::return_type return_type;
};
} // namespace detail
template <typename T, typename Executor, typename Signature> template <typename T, typename Executor, typename Signature>
struct handler_type<executor_binder<T, Executor>, Signature> class async_result<executor_binder<T, Executor>, Signature> :
{ public detail::executor_binder_completion_handler_async_result<
typedef executor_binder< async_result<T, Signature>, Executor>,
typename handler_type<T, Signature>::type, Executor> type; public detail::executor_binder_async_result_return_type<
}; async_result<T, Signature>>
template <typename T, typename Executor>
class async_result<executor_binder<T, Executor> >
{ {
public: public:
typedef typename async_result<T>::type type;
explicit async_result(executor_binder<T, Executor>& b) explicit async_result(executor_binder<T, Executor>& b)
: target_(b.get()) : detail::executor_binder_completion_handler_async_result<
async_result<T, Signature>, Executor>(b.get())
{ {
} }
type get() template <typename Initiation>
struct init_wrapper
{ {
return target_.get(); template <typename Init>
init_wrapper(const Executor& ex, Init&& init)
: ex_(ex),
initiation_(static_cast<Init&&>(init))
{
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args)
{
static_cast<Initiation&&>(initiation_)(
executor_binder<decay_t<Handler>, Executor>(
executor_arg_t(), ex_, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) const
{
initiation_(
executor_binder<decay_t<Handler>, Executor>(
executor_arg_t(), ex_, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
Executor ex_;
Initiation initiation_;
};
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<T, Signature>(
declval<init_wrapper<decay_t<Initiation>>>(),
token.get(), static_cast<Args&&>(args)...))
{
return async_initiate<T, Signature>(
init_wrapper<decay_t<Initiation>>(
token.get_executor(), static_cast<Initiation&&>(initiation)),
token.get(), static_cast<Args&&>(args)...);
} }
private: private:
async_result<T> target_; async_result(const async_result&) = delete;
async_result& operator=(const async_result&) = delete;
}; };
#endif // !defined(ASIO_NO_DEPRECATED) template <template <typename, typename> class Associator,
typename T, typename Executor, typename DefaultCandidate>
template <typename T, typename Executor, typename Allocator> struct associator<Associator, executor_binder<T, Executor>, DefaultCandidate>
struct associated_allocator<executor_binder<T, Executor>, Allocator> : Associator<T, DefaultCandidate>
{ {
typedef typename associated_allocator<T, Allocator>::type type; static typename Associator<T, DefaultCandidate>::type get(
const executor_binder<T, Executor>& b) noexcept
static type get(const executor_binder<T, Executor>& b,
const Allocator& a = Allocator()) ASIO_NOEXCEPT
{ {
return associated_allocator<T, Allocator>::get(b.get(), a); return Associator<T, DefaultCandidate>::get(b.get());
}
static auto get(const executor_binder<T, Executor>& b,
const DefaultCandidate& c) noexcept
-> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
{
return Associator<T, DefaultCandidate>::get(b.get(), c);
} }
}; };
@@ -595,8 +565,9 @@ struct associated_executor<executor_binder<T, Executor>, Executor1>
{ {
typedef Executor type; typedef Executor type;
static type get(const executor_binder<T, Executor>& b, static auto get(const executor_binder<T, Executor>& b,
const Executor1& = Executor1()) ASIO_NOEXCEPT const Executor1& = Executor1()) noexcept
-> decltype(b.get_executor())
{ {
return b.get_executor(); return b.get_executor();
} }

View File

@@ -0,0 +1,549 @@
//
// bind_immediate_executor.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 ASIO_BIND_IMMEDIATE_EXECUTOR_HPP
#define ASIO_BIND_IMMEDIATE_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/associated_immediate_executor.hpp"
#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
// Helper to automatically define nested typedef result_type.
template <typename T, typename = void>
struct immediate_executor_binder_result_type
{
protected:
typedef void result_type_or_void;
};
template <typename T>
struct immediate_executor_binder_result_type<T, void_t<typename T::result_type>>
{
typedef typename T::result_type result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct immediate_executor_binder_result_type<R(*)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct immediate_executor_binder_result_type<R(&)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct immediate_executor_binder_result_type<R(*)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct immediate_executor_binder_result_type<R(&)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct immediate_executor_binder_result_type<R(*)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct immediate_executor_binder_result_type<R(&)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
// Helper to automatically define nested typedef argument_type.
template <typename T, typename = void>
struct immediate_executor_binder_argument_type {};
template <typename T>
struct immediate_executor_binder_argument_type<T,
void_t<typename T::argument_type>>
{
typedef typename T::argument_type argument_type;
};
template <typename R, typename A1>
struct immediate_executor_binder_argument_type<R(*)(A1)>
{
typedef A1 argument_type;
};
template <typename R, typename A1>
struct immediate_executor_binder_argument_type<R(&)(A1)>
{
typedef A1 argument_type;
};
// Helper to automatically define nested typedefs first_argument_type and
// second_argument_type.
template <typename T, typename = void>
struct immediate_executor_binder_argument_types {};
template <typename T>
struct immediate_executor_binder_argument_types<T,
void_t<typename T::first_argument_type>>
{
typedef typename T::first_argument_type first_argument_type;
typedef typename T::second_argument_type second_argument_type;
};
template <typename R, typename A1, typename A2>
struct immediate_executor_binder_argument_type<R(*)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
template <typename R, typename A1, typename A2>
struct immediate_executor_binder_argument_type<R(&)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
} // namespace detail
/// A call wrapper type to bind a immediate executor of type @c Executor
/// to an object of type @c T.
template <typename T, typename Executor>
class immediate_executor_binder
#if !defined(GENERATING_DOCUMENTATION)
: public detail::immediate_executor_binder_result_type<T>,
public detail::immediate_executor_binder_argument_type<T>,
public detail::immediate_executor_binder_argument_types<T>
#endif // !defined(GENERATING_DOCUMENTATION)
{
public:
/// The type of the target object.
typedef T target_type;
/// The type of the associated immediate executor.
typedef Executor immediate_executor_type;
#if defined(GENERATING_DOCUMENTATION)
/// The return type if a function.
/**
* The type of @c result_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to function type, @c result_type is a synonym for
* the return type of @c T;
*
* @li if @c T is a class type with a member type @c result_type, then @c
* result_type is a synonym for @c T::result_type;
*
* @li otherwise @c result_type is not defined.
*/
typedef see_below result_type;
/// The type of the function's argument.
/**
* The type of @c argument_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to a function type accepting a single argument,
* @c argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c argument_type, then @c
* argument_type is a synonym for @c T::argument_type;
*
* @li otherwise @c argument_type is not defined.
*/
typedef see_below argument_type;
/// The type of the function's first argument.
/**
* The type of @c first_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* first_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c first_argument_type is a synonym for @c T::first_argument_type;
*
* @li otherwise @c first_argument_type is not defined.
*/
typedef see_below first_argument_type;
/// The type of the function's second argument.
/**
* The type of @c second_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* second_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c second_argument_type is a synonym for @c T::second_argument_type;
*
* @li otherwise @c second_argument_type is not defined.
*/
typedef see_below second_argument_type;
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct a immediate executor wrapper for the specified object.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U>
immediate_executor_binder(const immediate_executor_type& e,
U&& u)
: executor_(e),
target_(static_cast<U&&>(u))
{
}
/// Copy constructor.
immediate_executor_binder(const immediate_executor_binder& other)
: executor_(other.get_immediate_executor()),
target_(other.get())
{
}
/// Construct a copy, but specify a different immediate executor.
immediate_executor_binder(const immediate_executor_type& e,
const immediate_executor_binder& other)
: executor_(e),
target_(other.get())
{
}
/// Construct a copy of a different immediate executor wrapper type.
/**
* This constructor is only valid if the @c Executor type is
* constructible from type @c OtherExecutor, and the type @c T is
* constructible from type @c U.
*/
template <typename U, typename OtherExecutor>
immediate_executor_binder(
const immediate_executor_binder<U, OtherExecutor>& other,
constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: executor_(other.get_immediate_executor()),
target_(other.get())
{
}
/// Construct a copy of a different immediate executor wrapper type, but
/// specify a different immediate executor.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherExecutor>
immediate_executor_binder(const immediate_executor_type& e,
const immediate_executor_binder<U, OtherExecutor>& other,
constraint_t<is_constructible<T, U>::value> = 0)
: executor_(e),
target_(other.get())
{
}
/// Move constructor.
immediate_executor_binder(immediate_executor_binder&& other)
: executor_(static_cast<immediate_executor_type&&>(
other.get_immediate_executor())),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct the target object, but specify a different immediate
/// executor.
immediate_executor_binder(const immediate_executor_type& e,
immediate_executor_binder&& other)
: executor_(e),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct from a different immediate executor wrapper type.
template <typename U, typename OtherExecutor>
immediate_executor_binder(
immediate_executor_binder<U, OtherExecutor>&& other,
constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: executor_(static_cast<OtherExecutor&&>(
other.get_immediate_executor())),
target_(static_cast<U&&>(other.get()))
{
}
/// Move construct from a different immediate executor wrapper type, but
/// specify a different immediate executor.
template <typename U, typename OtherExecutor>
immediate_executor_binder(const immediate_executor_type& e,
immediate_executor_binder<U, OtherExecutor>&& other,
constraint_t<is_constructible<T, U>::value> = 0)
: executor_(e),
target_(static_cast<U&&>(other.get()))
{
}
/// Destructor.
~immediate_executor_binder()
{
}
/// Obtain a reference to the target object.
target_type& get() noexcept
{
return target_;
}
/// Obtain a reference to the target object.
const target_type& get() const noexcept
{
return target_;
}
/// Obtain the associated immediate executor.
immediate_executor_type get_immediate_executor() const noexcept
{
return executor_;
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args)
{
return target_(static_cast<Args&&>(args)...);
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args) const
{
return target_(static_cast<Args&&>(args)...);
}
private:
Executor executor_;
T target_;
};
/// Associate an object of type @c T with a immediate executor of type
/// @c Executor.
template <typename Executor, typename T>
ASIO_NODISCARD inline immediate_executor_binder<decay_t<T>, Executor>
bind_immediate_executor(const Executor& e, T&& t)
{
return immediate_executor_binder<
decay_t<T>, Executor>(
e, static_cast<T&&>(t));
}
#if !defined(GENERATING_DOCUMENTATION)
namespace detail {
template <typename TargetAsyncResult, typename Executor, typename = void>
class immediate_executor_binder_completion_handler_async_result
{
public:
template <typename T>
explicit immediate_executor_binder_completion_handler_async_result(T&)
{
}
};
template <typename TargetAsyncResult, typename Executor>
class immediate_executor_binder_completion_handler_async_result<
TargetAsyncResult, Executor,
void_t<
typename TargetAsyncResult::completion_handler_type
>>
{
private:
TargetAsyncResult target_;
public:
typedef immediate_executor_binder<
typename TargetAsyncResult::completion_handler_type, Executor>
completion_handler_type;
explicit immediate_executor_binder_completion_handler_async_result(
typename TargetAsyncResult::completion_handler_type& handler)
: target_(handler)
{
}
auto get() -> decltype(target_.get())
{
return target_.get();
}
};
template <typename TargetAsyncResult, typename = void>
struct immediate_executor_binder_async_result_return_type
{
};
template <typename TargetAsyncResult>
struct immediate_executor_binder_async_result_return_type<
TargetAsyncResult,
void_t<
typename TargetAsyncResult::return_type
>>
{
typedef typename TargetAsyncResult::return_type return_type;
};
} // namespace detail
template <typename T, typename Executor, typename Signature>
class async_result<immediate_executor_binder<T, Executor>, Signature> :
public detail::immediate_executor_binder_completion_handler_async_result<
async_result<T, Signature>, Executor>,
public detail::immediate_executor_binder_async_result_return_type<
async_result<T, Signature>>
{
public:
explicit async_result(immediate_executor_binder<T, Executor>& b)
: detail::immediate_executor_binder_completion_handler_async_result<
async_result<T, Signature>, Executor>(b.get())
{
}
template <typename Initiation>
struct init_wrapper
{
template <typename Init>
init_wrapper(const Executor& e, Init&& init)
: executor_(e),
initiation_(static_cast<Init&&>(init))
{
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args)
{
static_cast<Initiation&&>(initiation_)(
immediate_executor_binder<
decay_t<Handler>, Executor>(
executor_, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) const
{
initiation_(
immediate_executor_binder<
decay_t<Handler>, Executor>(
executor_, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
Executor executor_;
Initiation initiation_;
};
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<T, Signature>(
declval<init_wrapper<decay_t<Initiation>>>(),
token.get(), static_cast<Args&&>(args)...))
{
return async_initiate<T, Signature>(
init_wrapper<decay_t<Initiation>>(
token.get_immediate_executor(),
static_cast<Initiation&&>(initiation)),
token.get(), static_cast<Args&&>(args)...);
}
private:
async_result(const async_result&) = delete;
async_result& operator=(const async_result&) = delete;
async_result<T, Signature> target_;
};
template <template <typename, typename> class Associator,
typename T, typename Executor, typename DefaultCandidate>
struct associator<Associator,
immediate_executor_binder<T, Executor>,
DefaultCandidate>
: Associator<T, DefaultCandidate>
{
static typename Associator<T, DefaultCandidate>::type get(
const immediate_executor_binder<T, Executor>& b) noexcept
{
return Associator<T, DefaultCandidate>::get(b.get());
}
static auto get(const immediate_executor_binder<T, Executor>& b,
const DefaultCandidate& c) noexcept
-> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
{
return Associator<T, DefaultCandidate>::get(b.get(), c);
}
};
template <typename T, typename Executor, typename Executor1>
struct associated_immediate_executor<
immediate_executor_binder<T, Executor>,
Executor1>
{
typedef Executor type;
static auto get(const immediate_executor_binder<T, Executor>& b,
const Executor1& = Executor1()) noexcept
-> decltype(b.get_immediate_executor())
{
return b.get_immediate_executor();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BIND_IMMEDIATE_EXECUTOR_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,318 @@
//
// buffer_registration.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 ASIO_BUFFER_REGISTRATION_HPP
#define ASIO_BUFFER_REGISTRATION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <iterator>
#include <utility>
#include <vector>
#include "asio/detail/memory.hpp"
#include "asio/execution/context.hpp"
#include "asio/execution/executor.hpp"
#include "asio/execution_context.hpp"
#include "asio/is_executor.hpp"
#include "asio/query.hpp"
#include "asio/registered_buffer.hpp"
#if defined(ASIO_HAS_IO_URING)
# include "asio/detail/scheduler.hpp"
# include "asio/detail/io_uring_service.hpp"
#endif // defined(ASIO_HAS_IO_URING)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class buffer_registration_base
{
protected:
static mutable_registered_buffer make_buffer(const mutable_buffer& b,
const void* scope, int index) noexcept
{
return mutable_registered_buffer(b, registered_buffer_id(scope, index));
}
};
} // namespace detail
/// Automatically registers and unregistered buffers with an execution context.
/**
* For portability, applications should assume that only one registration is
* permitted per execution context.
*/
template <typename MutableBufferSequence,
typename Allocator = std::allocator<void>>
class buffer_registration
: detail::buffer_registration_base
{
public:
/// The allocator type used for allocating storage for the buffers container.
typedef Allocator allocator_type;
#if defined(GENERATING_DOCUMENTATION)
/// The type of an iterator over the registered buffers.
typedef unspecified iterator;
/// The type of a const iterator over the registered buffers.
typedef unspecified const_iterator;
#else // defined(GENERATING_DOCUMENTATION)
typedef std::vector<mutable_registered_buffer>::const_iterator iterator;
typedef std::vector<mutable_registered_buffer>::const_iterator const_iterator;
#endif // defined(GENERATING_DOCUMENTATION)
/// Register buffers with an executor's execution context.
template <typename Executor>
buffer_registration(const Executor& ex,
const MutableBufferSequence& buffer_sequence,
const allocator_type& alloc = allocator_type(),
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
: buffer_sequence_(buffer_sequence),
buffers_(
ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)(alloc))
{
init_buffers(buffer_registration::get_context(ex),
asio::buffer_sequence_begin(buffer_sequence_),
asio::buffer_sequence_end(buffer_sequence_));
}
/// Register buffers with an execution context.
template <typename ExecutionContext>
buffer_registration(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence,
const allocator_type& alloc = allocator_type(),
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: buffer_sequence_(buffer_sequence),
buffers_(
ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)(alloc))
{
init_buffers(ctx,
asio::buffer_sequence_begin(buffer_sequence_),
asio::buffer_sequence_end(buffer_sequence_));
}
/// Move constructor.
buffer_registration(buffer_registration&& other) noexcept
: buffer_sequence_(std::move(other.buffer_sequence_)),
buffers_(std::move(other.buffers_))
{
#if defined(ASIO_HAS_IO_URING)
service_ = other.service_;
other.service_ = 0;
#endif // defined(ASIO_HAS_IO_URING)
}
/// Unregisters the buffers.
~buffer_registration()
{
#if defined(ASIO_HAS_IO_URING)
if (service_)
service_->unregister_buffers();
#endif // defined(ASIO_HAS_IO_URING)
}
/// Move assignment.
buffer_registration& operator=(buffer_registration&& other) noexcept
{
if (this != &other)
{
buffer_sequence_ = std::move(other.buffer_sequence_);
buffers_ = std::move(other.buffers_);
#if defined(ASIO_HAS_IO_URING)
if (service_)
service_->unregister_buffers();
service_ = other.service_;
other.service_ = 0;
#endif // defined(ASIO_HAS_IO_URING)
}
return *this;
}
/// Get the number of registered buffers.
std::size_t size() const noexcept
{
return buffers_.size();
}
/// Get the begin iterator for the sequence of registered buffers.
const_iterator begin() const noexcept
{
return buffers_.begin();
}
/// Get the begin iterator for the sequence of registered buffers.
const_iterator cbegin() const noexcept
{
return buffers_.cbegin();
}
/// Get the end iterator for the sequence of registered buffers.
const_iterator end() const noexcept
{
return buffers_.end();
}
/// Get the end iterator for the sequence of registered buffers.
const_iterator cend() const noexcept
{
return buffers_.cend();
}
/// Get the buffer at the specified index.
const mutable_registered_buffer& operator[](std::size_t i) noexcept
{
return buffers_[i];
}
/// Get the buffer at the specified index.
const mutable_registered_buffer& at(std::size_t i) noexcept
{
return buffers_.at(i);
}
private:
// Disallow copying and assignment.
buffer_registration(const buffer_registration&) = delete;
buffer_registration& operator=(const buffer_registration&) = delete;
// Helper function to get an executor's context.
template <typename T>
static execution_context& get_context(const T& t,
enable_if_t<execution::is_executor<T>::value>* = 0)
{
return asio::query(t, execution::context);
}
// Helper function to get an executor's context.
template <typename T>
static execution_context& get_context(const T& t,
enable_if_t<!execution::is_executor<T>::value>* = 0)
{
return t.context();
}
// Helper function to initialise the container of buffers.
template <typename Iterator>
void init_buffers(execution_context& ctx, Iterator begin, Iterator end)
{
std::size_t n = std::distance(begin, end);
buffers_.resize(n);
#if defined(ASIO_HAS_IO_URING)
service_ = &use_service<detail::io_uring_service>(ctx);
std::vector<iovec,
ASIO_REBIND_ALLOC(allocator_type, iovec)> iovecs(n,
ASIO_REBIND_ALLOC(allocator_type, iovec)(
buffers_.get_allocator()));
#endif // defined(ASIO_HAS_IO_URING)
Iterator iter = begin;
for (int index = 0; iter != end; ++index, ++iter)
{
mutable_buffer b(*iter);
std::size_t i = static_cast<std::size_t>(index);
buffers_[i] = this->make_buffer(b, &ctx, index);
#if defined(ASIO_HAS_IO_URING)
iovecs[i].iov_base = buffers_[i].data();
iovecs[i].iov_len = buffers_[i].size();
#endif // defined(ASIO_HAS_IO_URING)
}
#if defined(ASIO_HAS_IO_URING)
if (n > 0)
{
service_->register_buffers(&iovecs[0],
static_cast<unsigned>(iovecs.size()));
}
#endif // defined(ASIO_HAS_IO_URING)
}
MutableBufferSequence buffer_sequence_;
std::vector<mutable_registered_buffer,
ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)> buffers_;
#if defined(ASIO_HAS_IO_URING)
detail::io_uring_service* service_;
#endif // defined(ASIO_HAS_IO_URING)
};
/// Register buffers with an execution context.
template <typename Executor, typename MutableBufferSequence>
ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence>
register_buffers(const Executor& ex,
const MutableBufferSequence& buffer_sequence,
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
{
return buffer_registration<MutableBufferSequence>(ex, buffer_sequence);
}
/// Register buffers with an execution context.
template <typename Executor, typename MutableBufferSequence, typename Allocator>
ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence, Allocator>
register_buffers(const Executor& ex,
const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
{
return buffer_registration<MutableBufferSequence, Allocator>(
ex, buffer_sequence, alloc);
}
/// Register buffers with an execution context.
template <typename ExecutionContext, typename MutableBufferSequence>
ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence>
register_buffers(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
{
return buffer_registration<MutableBufferSequence>(ctx, buffer_sequence);
}
/// Register buffers with an execution context.
template <typename ExecutionContext,
typename MutableBufferSequence, typename Allocator>
ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence, Allocator>
register_buffers(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
{
return buffer_registration<MutableBufferSequence, Allocator>(
ctx, buffer_sequence, alloc);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFER_REGISTRATION_HPP

View File

@@ -2,7 +2,7 @@
// buffered_read_stream.hpp // buffered_read_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -26,11 +26,16 @@
#include "asio/detail/noncopyable.hpp" #include "asio/detail/noncopyable.hpp"
#include "asio/detail/type_traits.hpp" #include "asio/detail/type_traits.hpp"
#include "asio/error.hpp" #include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
namespace asio { namespace asio {
namespace detail {
template <typename> class initiate_async_buffered_fill;
template <typename> class initiate_async_buffered_read_some;
} // namespace detail
/// Adds buffering to the read-related operations of a stream. /// Adds buffering to the read-related operations of a stream.
/** /**
@@ -50,7 +55,7 @@ class buffered_read_stream
{ {
public: public:
/// The type of the next layer. /// The type of the next layer.
typedef typename remove_reference<Stream>::type next_layer_type; typedef remove_reference_t<Stream> next_layer_type;
/// The type of the lowest layer. /// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type; typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
@@ -67,16 +72,17 @@ public:
/// Construct, passing the specified argument to initialise the next layer. /// Construct, passing the specified argument to initialise the next layer.
template <typename Arg> template <typename Arg>
explicit buffered_read_stream(Arg& a) explicit buffered_read_stream(Arg&& a)
: next_layer_(a), : next_layer_(static_cast<Arg&&>(a)),
storage_(default_buffer_size) storage_(default_buffer_size)
{ {
} }
/// Construct, passing the specified argument to initialise the next layer. /// Construct, passing the specified argument to initialise the next layer.
template <typename Arg> template <typename Arg>
buffered_read_stream(Arg& a, std::size_t buffer_size) buffered_read_stream(Arg&& a,
: next_layer_(a), std::size_t buffer_size)
: next_layer_(static_cast<Arg&&>(a)),
storage_(buffer_size) storage_(buffer_size)
{ {
} }
@@ -100,27 +106,11 @@ public:
} }
/// Get the executor associated with the object. /// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT executor_type get_executor() noexcept
{ {
return next_layer_.lowest_layer().get_executor(); return next_layer_.lowest_layer().get_executor();
} }
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_context()
{
return next_layer_.get_io_context();
}
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_service()
{
return next_layer_.get_io_service();
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// Close the stream. /// Close the stream.
void close() void close()
{ {
@@ -153,14 +143,21 @@ public:
/// Start an asynchronous write. The data being written must be valid for the /// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation. /// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename WriteHandler> /**
ASIO_INITFN_RESULT_TYPE(WriteHandler, * @par Completion Signature
void (asio::error_code, std::size_t)) * @code void(asio::error_code, std::size_t) @endcode
async_write_some(const ConstBufferSequence& buffers, */
ASIO_MOVE_ARG(WriteHandler) handler) template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteHandler = default_completion_token_t<executor_type>>
auto async_write_some(const ConstBufferSequence& buffers,
WriteHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<conditional_t<true, Stream&, WriteHandler>>().async_write_some(
buffers, static_cast<WriteHandler&&>(handler)))
{ {
return next_layer_.async_write_some(buffers, return next_layer_.async_write_some(buffers,
ASIO_MOVE_CAST(WriteHandler)(handler)); static_cast<WriteHandler&&>(handler));
} }
/// Fill the buffer with some data. Returns the number of bytes placed in the /// Fill the buffer with some data. Returns the number of bytes placed in the
@@ -172,10 +169,20 @@ public:
std::size_t fill(asio::error_code& ec); std::size_t fill(asio::error_code& ec);
/// Start an asynchronous fill. /// Start an asynchronous fill.
template <typename ReadHandler> /**
ASIO_INITFN_RESULT_TYPE(ReadHandler, * @par Completion Signature
void (asio::error_code, std::size_t)) * @code void(asio::error_code, std::size_t) @endcode
async_fill(ASIO_MOVE_ARG(ReadHandler) handler); */
template <
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadHandler = default_completion_token_t<executor_type>>
auto async_fill(
ReadHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
declval<detail::initiate_async_buffered_fill<Stream>>(),
handler, declval<detail::buffered_stream_storage*>()));
/// Read some data from the stream. Returns the number of bytes read. Throws /// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure. /// an exception on failure.
@@ -190,11 +197,20 @@ public:
/// Start an asynchronous read. The buffer into which the data will be read /// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation. /// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename ReadHandler> /**
ASIO_INITFN_RESULT_TYPE(ReadHandler, * @par Completion Signature
void (asio::error_code, std::size_t)) * @code void(asio::error_code, std::size_t) @endcode
async_read_some(const MutableBufferSequence& buffers, */
ASIO_MOVE_ARG(ReadHandler) handler); template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadHandler = default_completion_token_t<executor_type>>
auto async_read_some(const MutableBufferSequence& buffers,
ReadHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
declval<detail::initiate_async_buffered_read_some<Stream>>(),
handler, declval<detail::buffered_stream_storage*>(), buffers));
/// Peek at the incoming data on the stream. Returns the number of bytes read. /// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure. /// Throws an exception on failure.

View File

@@ -2,7 +2,7 @@
// buffered_read_stream_fwd.hpp // buffered_read_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// buffered_stream.hpp // buffered_stream.hpp
// ~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -23,7 +23,6 @@
#include "asio/buffered_stream_fwd.hpp" #include "asio/buffered_stream_fwd.hpp"
#include "asio/detail/noncopyable.hpp" #include "asio/detail/noncopyable.hpp"
#include "asio/error.hpp" #include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
@@ -47,7 +46,7 @@ class buffered_stream
{ {
public: public:
/// The type of the next layer. /// The type of the next layer.
typedef typename remove_reference<Stream>::type next_layer_type; typedef remove_reference_t<Stream> next_layer_type;
/// The type of the lowest layer. /// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type; typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
@@ -57,17 +56,17 @@ public:
/// Construct, passing the specified argument to initialise the next layer. /// Construct, passing the specified argument to initialise the next layer.
template <typename Arg> template <typename Arg>
explicit buffered_stream(Arg& a) explicit buffered_stream(Arg&& a)
: inner_stream_impl_(a), : inner_stream_impl_(static_cast<Arg&&>(a)),
stream_impl_(inner_stream_impl_) stream_impl_(inner_stream_impl_)
{ {
} }
/// Construct, passing the specified argument to initialise the next layer. /// Construct, passing the specified argument to initialise the next layer.
template <typename Arg> template <typename Arg>
explicit buffered_stream(Arg& a, std::size_t read_buffer_size, explicit buffered_stream(Arg&& a,
std::size_t write_buffer_size) std::size_t read_buffer_size, std::size_t write_buffer_size)
: inner_stream_impl_(a, write_buffer_size), : inner_stream_impl_(static_cast<Arg&&>(a), write_buffer_size),
stream_impl_(inner_stream_impl_, read_buffer_size) stream_impl_(inner_stream_impl_, read_buffer_size)
{ {
} }
@@ -91,27 +90,11 @@ public:
} }
/// Get the executor associated with the object. /// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT executor_type get_executor() noexcept
{ {
return stream_impl_.lowest_layer().get_executor(); return stream_impl_.lowest_layer().get_executor();
} }
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_context()
{
return stream_impl_.get_io_context();
}
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_service()
{
return stream_impl_.get_io_service();
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// Close the stream. /// Close the stream.
void close() void close()
{ {
@@ -142,13 +125,21 @@ public:
} }
/// Start an asynchronous flush. /// Start an asynchronous flush.
template <typename WriteHandler> /**
ASIO_INITFN_RESULT_TYPE(WriteHandler, * @par Completion Signature
void (asio::error_code, std::size_t)) * @code void(asio::error_code, std::size_t) @endcode
async_flush(ASIO_MOVE_ARG(WriteHandler) handler) */
template <
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteHandler = default_completion_token_t<executor_type>>
auto async_flush(
WriteHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<buffered_write_stream<Stream>&>().async_flush(
static_cast<WriteHandler&&>(handler)))
{ {
return stream_impl_.next_layer().async_flush( return stream_impl_.next_layer().async_flush(
ASIO_MOVE_CAST(WriteHandler)(handler)); static_cast<WriteHandler&&>(handler));
} }
/// Write the given data to the stream. Returns the number of bytes written. /// Write the given data to the stream. Returns the number of bytes written.
@@ -170,14 +161,21 @@ public:
/// Start an asynchronous write. The data being written must be valid for the /// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation. /// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename WriteHandler> /**
ASIO_INITFN_RESULT_TYPE(WriteHandler, * @par Completion Signature
void (asio::error_code, std::size_t)) * @code void(asio::error_code, std::size_t) @endcode
async_write_some(const ConstBufferSequence& buffers, */
ASIO_MOVE_ARG(WriteHandler) handler) template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteHandler = default_completion_token_t<executor_type>>
auto async_write_some(const ConstBufferSequence& buffers,
WriteHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<Stream&>().async_write_some(buffers,
static_cast<WriteHandler&&>(handler)))
{ {
return stream_impl_.async_write_some(buffers, return stream_impl_.async_write_some(buffers,
ASIO_MOVE_CAST(WriteHandler)(handler)); static_cast<WriteHandler&&>(handler));
} }
/// Fill the buffer with some data. Returns the number of bytes placed in the /// Fill the buffer with some data. Returns the number of bytes placed in the
@@ -195,12 +193,21 @@ public:
} }
/// Start an asynchronous fill. /// Start an asynchronous fill.
template <typename ReadHandler> /**
ASIO_INITFN_RESULT_TYPE(ReadHandler, * @par Completion Signature
void (asio::error_code, std::size_t)) * @code void(asio::error_code, std::size_t) @endcode
async_fill(ASIO_MOVE_ARG(ReadHandler) handler) */
template <
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadHandler = default_completion_token_t<executor_type>>
auto async_fill(
ReadHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<buffered_read_stream<
buffered_write_stream<Stream>>&>().async_fill(
static_cast<ReadHandler&&>(handler)))
{ {
return stream_impl_.async_fill(ASIO_MOVE_CAST(ReadHandler)(handler)); return stream_impl_.async_fill(static_cast<ReadHandler&&>(handler));
} }
/// Read some data from the stream. Returns the number of bytes read. Throws /// Read some data from the stream. Returns the number of bytes read. Throws
@@ -222,14 +229,21 @@ public:
/// Start an asynchronous read. The buffer into which the data will be read /// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation. /// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename ReadHandler> /**
ASIO_INITFN_RESULT_TYPE(ReadHandler, * @par Completion Signature
void (asio::error_code, std::size_t)) * @code void(asio::error_code, std::size_t) @endcode
async_read_some(const MutableBufferSequence& buffers, */
ASIO_MOVE_ARG(ReadHandler) handler) template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadHandler = default_completion_token_t<executor_type>>
auto async_read_some(const MutableBufferSequence& buffers,
ReadHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<Stream&>().async_read_some(buffers,
static_cast<ReadHandler&&>(handler)))
{ {
return stream_impl_.async_read_some(buffers, return stream_impl_.async_read_some(buffers,
ASIO_MOVE_CAST(ReadHandler)(handler)); static_cast<ReadHandler&&>(handler));
} }
/// Peek at the incoming data on the stream. Returns the number of bytes read. /// Peek at the incoming data on the stream. Returns the number of bytes read.

View File

@@ -2,7 +2,7 @@
// buffered_stream_fwd.hpp // buffered_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// buffered_write_stream.hpp // buffered_write_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -25,12 +25,17 @@
#include "asio/detail/noncopyable.hpp" #include "asio/detail/noncopyable.hpp"
#include "asio/detail/type_traits.hpp" #include "asio/detail/type_traits.hpp"
#include "asio/error.hpp" #include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/write.hpp" #include "asio/write.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
namespace asio { namespace asio {
namespace detail {
template <typename> class initiate_async_buffered_flush;
template <typename> class initiate_async_buffered_write_some;
} // namespace detail
/// Adds buffering to the write-related operations of a stream. /// Adds buffering to the write-related operations of a stream.
/** /**
@@ -50,7 +55,7 @@ class buffered_write_stream
{ {
public: public:
/// The type of the next layer. /// The type of the next layer.
typedef typename remove_reference<Stream>::type next_layer_type; typedef remove_reference_t<Stream> next_layer_type;
/// The type of the lowest layer. /// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type; typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
@@ -67,16 +72,17 @@ public:
/// Construct, passing the specified argument to initialise the next layer. /// Construct, passing the specified argument to initialise the next layer.
template <typename Arg> template <typename Arg>
explicit buffered_write_stream(Arg& a) explicit buffered_write_stream(Arg&& a)
: next_layer_(a), : next_layer_(static_cast<Arg&&>(a)),
storage_(default_buffer_size) storage_(default_buffer_size)
{ {
} }
/// Construct, passing the specified argument to initialise the next layer. /// Construct, passing the specified argument to initialise the next layer.
template <typename Arg> template <typename Arg>
buffered_write_stream(Arg& a, std::size_t buffer_size) buffered_write_stream(Arg&& a,
: next_layer_(a), std::size_t buffer_size)
: next_layer_(static_cast<Arg&&>(a)),
storage_(buffer_size) storage_(buffer_size)
{ {
} }
@@ -100,27 +106,11 @@ public:
} }
/// Get the executor associated with the object. /// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT executor_type get_executor() noexcept
{ {
return next_layer_.lowest_layer().get_executor(); return next_layer_.lowest_layer().get_executor();
} }
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_context()
{
return next_layer_.get_io_context();
}
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_service()
{
return next_layer_.get_io_service();
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// Close the stream. /// Close the stream.
void close() void close()
{ {
@@ -145,10 +135,20 @@ public:
std::size_t flush(asio::error_code& ec); std::size_t flush(asio::error_code& ec);
/// Start an asynchronous flush. /// Start an asynchronous flush.
template <typename WriteHandler> /**
ASIO_INITFN_RESULT_TYPE(WriteHandler, * @par Completion Signature
void (asio::error_code, std::size_t)) * @code void(asio::error_code, std::size_t) @endcode
async_flush(ASIO_MOVE_ARG(WriteHandler) handler); */
template <
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteHandler = default_completion_token_t<executor_type>>
auto async_flush(
WriteHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
declval<detail::initiate_async_buffered_flush<Stream>>(),
handler, declval<detail::buffered_stream_storage*>()));
/// Write the given data to the stream. Returns the number of bytes written. /// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure. /// Throws an exception on failure.
@@ -163,11 +163,20 @@ public:
/// Start an asynchronous write. The data being written must be valid for the /// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation. /// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename WriteHandler> /**
ASIO_INITFN_RESULT_TYPE(WriteHandler, * @par Completion Signature
void (asio::error_code, std::size_t)) * @code void(asio::error_code, std::size_t) @endcode
async_write_some(const ConstBufferSequence& buffers, */
ASIO_MOVE_ARG(WriteHandler) handler); template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteHandler = default_completion_token_t<executor_type>>
auto async_write_some(const ConstBufferSequence& buffers,
WriteHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
declval<detail::initiate_async_buffered_write_some<Stream>>(),
handler, declval<detail::buffered_stream_storage*>(), buffers));
/// Read some data from the stream. Returns the number of bytes read. Throws /// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure. /// an exception on failure.
@@ -188,14 +197,21 @@ public:
/// Start an asynchronous read. The buffer into which the data will be read /// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation. /// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename ReadHandler> /**
ASIO_INITFN_RESULT_TYPE(ReadHandler, * @par Completion Signature
void (asio::error_code, std::size_t)) * @code void(asio::error_code, std::size_t) @endcode
async_read_some(const MutableBufferSequence& buffers, */
ASIO_MOVE_ARG(ReadHandler) handler) template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadHandler = default_completion_token_t<executor_type>>
auto async_read_some(const MutableBufferSequence& buffers,
ReadHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<conditional_t<true, Stream&, ReadHandler>>().async_read_some(
buffers, static_cast<ReadHandler&&>(handler)))
{ {
return next_layer_.async_read_some(buffers, return next_layer_.async_read_some(buffers,
ASIO_MOVE_CAST(ReadHandler)(handler)); static_cast<ReadHandler&&>(handler));
} }
/// Peek at the incoming data on the stream. Returns the number of bytes read. /// Peek at the incoming data on the stream. Returns the number of bytes read.

View File

@@ -2,7 +2,7 @@
// buffered_write_stream_fwd.hpp // buffered_write_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// buffers_iterator.hpp // buffers_iterator.hpp
// ~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -38,7 +38,7 @@ namespace detail
template <typename ByteType> template <typename ByteType>
struct byte_type struct byte_type
{ {
typedef typename add_const<ByteType>::type type; typedef add_const_t<ByteType> type;
}; };
}; };
@@ -80,7 +80,7 @@ namespace detail
struct buffers_iterator_types<const_buffer, ByteType> struct buffers_iterator_types<const_buffer, ByteType>
{ {
typedef const_buffer buffer_type; typedef const_buffer buffer_type;
typedef typename add_const<ByteType>::type byte_type; typedef add_const_t<ByteType> byte_type;
typedef const const_buffer* const_iterator; typedef const const_buffer* const_iterator;
}; };
@@ -98,7 +98,7 @@ namespace detail
struct buffers_iterator_types<const_buffers_1, ByteType> struct buffers_iterator_types<const_buffers_1, ByteType>
{ {
typedef const_buffer buffer_type; typedef const_buffer buffer_type;
typedef typename add_const<ByteType>::type byte_type; typedef add_const_t<ByteType> byte_type;
typedef const const_buffer* const_iterator; typedef const const_buffer* const_iterator;
}; };

View File

@@ -0,0 +1,245 @@
//
// cancellation_signal.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 ASIO_CANCELLATION_SIGNAL_HPP
#define ASIO_CANCELLATION_SIGNAL_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cassert>
#include <new>
#include <utility>
#include "asio/cancellation_type.hpp"
#include "asio/detail/cstddef.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class cancellation_handler_base
{
public:
virtual void call(cancellation_type_t) = 0;
virtual std::pair<void*, std::size_t> destroy() noexcept = 0;
protected:
~cancellation_handler_base() {}
};
template <typename Handler>
class cancellation_handler
: public cancellation_handler_base
{
public:
template <typename... Args>
cancellation_handler(std::size_t size, Args&&... args)
: handler_(static_cast<Args&&>(args)...),
size_(size)
{
}
void call(cancellation_type_t type)
{
handler_(type);
}
std::pair<void*, std::size_t> destroy() noexcept
{
std::pair<void*, std::size_t> mem(this, size_);
this->cancellation_handler::~cancellation_handler();
return mem;
}
Handler& handler() noexcept
{
return handler_;
}
private:
~cancellation_handler()
{
}
Handler handler_;
std::size_t size_;
};
} // namespace detail
class cancellation_slot;
/// A cancellation signal with a single slot.
class cancellation_signal
{
public:
constexpr cancellation_signal()
: handler_(0)
{
}
ASIO_DECL ~cancellation_signal();
/// Emits the signal and causes invocation of the slot's handler, if any.
void emit(cancellation_type_t type)
{
if (handler_)
handler_->call(type);
}
/// Returns the single slot associated with the signal.
/**
* The signal object must remain valid for as long the slot may be used.
* Destruction of the signal invalidates the slot.
*/
cancellation_slot slot() noexcept;
private:
cancellation_signal(const cancellation_signal&) = delete;
cancellation_signal& operator=(const cancellation_signal&) = delete;
detail::cancellation_handler_base* handler_;
};
/// A slot associated with a cancellation signal.
class cancellation_slot
{
public:
/// Creates a slot that is not connected to any cancellation signal.
constexpr cancellation_slot()
: handler_(0)
{
}
/// Installs a handler into the slot, constructing the new object directly.
/**
* Destroys any existing handler in the slot, then installs the new handler,
* constructing it with the supplied @c args.
*
* The handler is a function object to be called when the signal is emitted.
* The signature of the handler must be
* @code void handler(asio::cancellation_type_t); @endcode
*
* @param args Arguments to be passed to the @c CancellationHandler object's
* constructor.
*
* @returns A reference to the newly installed handler.
*
* @note Handlers installed into the slot via @c emplace are not required to
* be copy constructible or move constructible.
*/
template <typename CancellationHandler, typename... Args>
CancellationHandler& emplace(Args&&... args)
{
typedef detail::cancellation_handler<CancellationHandler>
cancellation_handler_type;
auto_delete_helper del = { prepare_memory(
sizeof(cancellation_handler_type),
alignof(CancellationHandler)) };
cancellation_handler_type* handler_obj =
new (del.mem.first) cancellation_handler_type(
del.mem.second, static_cast<Args&&>(args)...);
del.mem.first = 0;
*handler_ = handler_obj;
return handler_obj->handler();
}
/// Installs a handler into the slot.
/**
* Destroys any existing handler in the slot, then installs the new handler,
* constructing it as a decay-copy of the supplied handler.
*
* The handler is a function object to be called when the signal is emitted.
* The signature of the handler must be
* @code void handler(asio::cancellation_type_t); @endcode
*
* @param handler The handler to be installed.
*
* @returns A reference to the newly installed handler.
*/
template <typename CancellationHandler>
decay_t<CancellationHandler>& assign(CancellationHandler&& handler)
{
return this->emplace<decay_t<CancellationHandler>>(
static_cast<CancellationHandler&&>(handler));
}
/// Clears the slot.
/**
* Destroys any existing handler in the slot.
*/
ASIO_DECL void clear();
/// Returns whether the slot is connected to a signal.
constexpr bool is_connected() const noexcept
{
return handler_ != 0;
}
/// Returns whether the slot is connected and has an installed handler.
constexpr bool has_handler() const noexcept
{
return handler_ != 0 && *handler_ != 0;
}
/// Compare two slots for equality.
friend constexpr bool operator==(const cancellation_slot& lhs,
const cancellation_slot& rhs) noexcept
{
return lhs.handler_ == rhs.handler_;
}
/// Compare two slots for inequality.
friend constexpr bool operator!=(const cancellation_slot& lhs,
const cancellation_slot& rhs) noexcept
{
return lhs.handler_ != rhs.handler_;
}
private:
friend class cancellation_signal;
constexpr cancellation_slot(int,
detail::cancellation_handler_base** handler)
: handler_(handler)
{
}
ASIO_DECL std::pair<void*, std::size_t> prepare_memory(
std::size_t size, std::size_t align);
struct auto_delete_helper
{
std::pair<void*, std::size_t> mem;
ASIO_DECL ~auto_delete_helper();
};
detail::cancellation_handler_base** handler_;
};
inline cancellation_slot cancellation_signal::slot() noexcept
{
return cancellation_slot(0, &handler_);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#if defined(ASIO_HEADER_ONLY)
# include "asio/impl/cancellation_signal.ipp"
#endif // defined(ASIO_HEADER_ONLY)
#endif // ASIO_CANCELLATION_SIGNAL_HPP

View File

@@ -0,0 +1,235 @@
//
// cancellation_state.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 ASIO_CANCELLATION_STATE_HPP
#define ASIO_CANCELLATION_STATE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cassert>
#include <new>
#include <utility>
#include "asio/cancellation_signal.hpp"
#include "asio/detail/cstddef.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// A simple cancellation signal propagation filter.
template <cancellation_type_t Mask>
struct cancellation_filter
{
/// Returns <tt>type & Mask</tt>.
cancellation_type_t operator()(
cancellation_type_t type) const noexcept
{
return type & Mask;
}
};
/// A cancellation filter that disables cancellation.
typedef cancellation_filter<cancellation_type::none>
disable_cancellation;
/// A cancellation filter that enables terminal cancellation only.
typedef cancellation_filter<cancellation_type::terminal>
enable_terminal_cancellation;
#if defined(GENERATING_DOCUMENTATION)
/// A cancellation filter that enables terminal and partial cancellation.
typedef cancellation_filter<
cancellation_type::terminal | cancellation_type::partial>
enable_partial_cancellation;
/// A cancellation filter that enables terminal, partial and total cancellation.
typedef cancellation_filter<cancellation_type::terminal
| cancellation_type::partial | cancellation_type::total>
enable_total_cancellation;
#else // defined(GENERATING_DOCUMENTATION)
typedef cancellation_filter<
static_cast<cancellation_type_t>(
static_cast<unsigned int>(cancellation_type::terminal)
| static_cast<unsigned int>(cancellation_type::partial))>
enable_partial_cancellation;
typedef cancellation_filter<
static_cast<cancellation_type_t>(
static_cast<unsigned int>(cancellation_type::terminal)
| static_cast<unsigned int>(cancellation_type::partial)
| static_cast<unsigned int>(cancellation_type::total))>
enable_total_cancellation;
#endif // defined(GENERATING_DOCUMENTATION)
/// A cancellation state is used for chaining signals and slots in compositions.
class cancellation_state
{
public:
/// Construct a disconnected cancellation state.
constexpr cancellation_state() noexcept
: impl_(0)
{
}
/// Construct and attach to a parent slot to create a new child slot.
/**
* Initialises the cancellation state so that it allows terminal cancellation
* only. Equivalent to <tt>cancellation_state(slot,
* enable_terminal_cancellation())</tt>.
*
* @param slot The parent cancellation slot to which the state will be
* attached.
*/
template <typename CancellationSlot>
constexpr explicit cancellation_state(CancellationSlot slot)
: impl_(slot.is_connected() ? &slot.template emplace<impl<>>() : 0)
{
}
/// Construct and attach to a parent slot to create a new child slot.
/**
* @param slot The parent cancellation slot to which the state will be
* attached.
*
* @param filter A function object that is used to transform incoming
* cancellation signals as they are received from the parent slot. This
* function object must have the signature:
* @code asio::cancellation_type_t filter(
* asio::cancellation_type_t); @endcode
*
* The library provides the following pre-defined cancellation filters:
*
* @li asio::disable_cancellation
* @li asio::enable_terminal_cancellation
* @li asio::enable_partial_cancellation
* @li asio::enable_total_cancellation
*/
template <typename CancellationSlot, typename Filter>
constexpr cancellation_state(CancellationSlot slot, Filter filter)
: impl_(slot.is_connected()
? &slot.template emplace<impl<Filter, Filter>>(filter, filter)
: 0)
{
}
/// Construct and attach to a parent slot to create a new child slot.
/**
* @param slot The parent cancellation slot to which the state will be
* attached.
*
* @param in_filter A function object that is used to transform incoming
* cancellation signals as they are received from the parent slot. This
* function object must have the signature:
* @code asio::cancellation_type_t in_filter(
* asio::cancellation_type_t); @endcode
*
* @param out_filter A function object that is used to transform outcoming
* cancellation signals as they are relayed to the child slot. This function
* object must have the signature:
* @code asio::cancellation_type_t out_filter(
* asio::cancellation_type_t); @endcode
*
* The library provides the following pre-defined cancellation filters:
*
* @li asio::disable_cancellation
* @li asio::enable_terminal_cancellation
* @li asio::enable_partial_cancellation
* @li asio::enable_total_cancellation
*/
template <typename CancellationSlot, typename InFilter, typename OutFilter>
constexpr cancellation_state(CancellationSlot slot,
InFilter in_filter, OutFilter out_filter)
: impl_(slot.is_connected()
? &slot.template emplace<impl<InFilter, OutFilter>>(
static_cast<InFilter&&>(in_filter),
static_cast<OutFilter&&>(out_filter))
: 0)
{
}
/// Returns the single child slot associated with the state.
/**
* This sub-slot is used with the operations that are being composed.
*/
constexpr cancellation_slot slot() const noexcept
{
return impl_ ? impl_->signal_.slot() : cancellation_slot();
}
/// Returns the cancellation types that have been triggered.
cancellation_type_t cancelled() const noexcept
{
return impl_ ? impl_->cancelled_ : cancellation_type_t();
}
/// Clears the specified cancellation types, if they have been triggered.
void clear(cancellation_type_t mask = cancellation_type::all)
noexcept
{
if (impl_)
impl_->cancelled_ &= ~mask;
}
private:
struct impl_base
{
impl_base()
: cancelled_()
{
}
cancellation_signal signal_;
cancellation_type_t cancelled_;
};
template <
typename InFilter = enable_terminal_cancellation,
typename OutFilter = InFilter>
struct impl : impl_base
{
impl()
: in_filter_(),
out_filter_()
{
}
impl(InFilter in_filter, OutFilter out_filter)
: in_filter_(static_cast<InFilter&&>(in_filter)),
out_filter_(static_cast<OutFilter&&>(out_filter))
{
}
void operator()(cancellation_type_t in)
{
this->cancelled_ = in_filter_(in);
cancellation_type_t out = out_filter_(this->cancelled_);
if (out != cancellation_type::none)
this->signal_.emit(out);
}
InFilter in_filter_;
OutFilter out_filter_;
};
impl_base* impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_CANCELLATION_STATE_HPP

View File

@@ -0,0 +1,157 @@
//
// cancellation_type.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 ASIO_CANCELLATION_TYPE_HPP
#define ASIO_CANCELLATION_TYPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
# if defined(GENERATING_DOCUMENTATION)
/// Enumeration representing the different types of cancellation that may
/// be requested from or implemented by an asynchronous operation.
enum cancellation_type
{
/// Bitmask representing no types of cancellation.
none = 0,
/// Requests cancellation where, following a successful cancellation, the only
/// safe operations on the I/O object are closure or destruction.
terminal = 1,
/// Requests cancellation where a successful cancellation may result in
/// partial side effects or no side effects. Following cancellation, the I/O
/// object is in a well-known state, and may be used for further operations.
partial = 2,
/// Requests cancellation where a successful cancellation results in no
/// apparent side effects. Following cancellation, the I/O object is in the
/// same observable state as it was prior to the operation.
total = 4,
/// Bitmask representing all types of cancellation.
all = 0xFFFFFFFF
};
/// Portability typedef.
typedef cancellation_type cancellation_type_t;
#else // defined(GENERATING_DOCUMENTATION)
enum class cancellation_type : unsigned int
{
none = 0,
terminal = 1,
partial = 2,
total = 4,
all = 0xFFFFFFFF
};
typedef cancellation_type cancellation_type_t;
#endif // defined(GENERATING_DOCUMENTATION)
/// Negation operator.
/**
* @relates cancellation_type
*/
inline constexpr bool operator!(cancellation_type_t x)
{
return static_cast<unsigned int>(x) == 0;
}
/// Bitwise and operator.
/**
* @relates cancellation_type
*/
inline constexpr cancellation_type_t operator&(
cancellation_type_t x, cancellation_type_t y)
{
return static_cast<cancellation_type_t>(
static_cast<unsigned int>(x) & static_cast<unsigned int>(y));
}
/// Bitwise or operator.
/**
* @relates cancellation_type
*/
inline constexpr cancellation_type_t operator|(
cancellation_type_t x, cancellation_type_t y)
{
return static_cast<cancellation_type_t>(
static_cast<unsigned int>(x) | static_cast<unsigned int>(y));
}
/// Bitwise xor operator.
/**
* @relates cancellation_type
*/
inline constexpr cancellation_type_t operator^(
cancellation_type_t x, cancellation_type_t y)
{
return static_cast<cancellation_type_t>(
static_cast<unsigned int>(x) ^ static_cast<unsigned int>(y));
}
/// Bitwise negation operator.
/**
* @relates cancellation_type
*/
inline constexpr cancellation_type_t operator~(cancellation_type_t x)
{
return static_cast<cancellation_type_t>(~static_cast<unsigned int>(x));
}
/// Bitwise and-assignment operator.
/**
* @relates cancellation_type
*/
inline cancellation_type_t& operator&=(
cancellation_type_t& x, cancellation_type_t y)
{
x = x & y;
return x;
}
/// Bitwise or-assignment operator.
/**
* @relates cancellation_type
*/
inline cancellation_type_t& operator|=(
cancellation_type_t& x, cancellation_type_t y)
{
x = x | y;
return x;
}
/// Bitwise xor-assignment operator.
/**
* @relates cancellation_type
*/
inline cancellation_type_t& operator^=(
cancellation_type_t& x, cancellation_type_t y)
{
x = x ^ y;
return x;
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_CANCELLATION_TYPE_HPP

View File

@@ -0,0 +1,523 @@
//
// co_spawn.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 ASIO_CO_SPAWN_HPP
#define ASIO_CO_SPAWN_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#include "asio/awaitable.hpp"
#include "asio/execution/executor.hpp"
#include "asio/execution_context.hpp"
#include "asio/is_executor.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename T>
struct awaitable_signature;
template <typename T, typename Executor>
struct awaitable_signature<awaitable<T, Executor>>
{
typedef void type(std::exception_ptr, T);
};
template <typename Executor>
struct awaitable_signature<awaitable<void, Executor>>
{
typedef void type(std::exception_ptr);
};
} // namespace detail
/// Spawn a new coroutined-based thread of execution.
/**
* @param ex The executor that will be used to schedule the new thread of
* execution.
*
* @param a The asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr, T); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, T) @endcode
*
* @par Example
* @code
* asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* asio::co_spawn(my_executor,
* echo(std::move(my_tcp_socket)),
* [](std::exception_ptr e, std::size_t n)
* {
* std::cout << "transferred " << n << "\n";
* });
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename Executor, typename T, typename AwaitableExecutor,
ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr, T)) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
inline ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr, T))
co_spawn(const Executor& ex, awaitable<T, AwaitableExecutor> a,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
constraint_t<
(is_executor<Executor>::value || execution::is_executor<Executor>::value)
&& is_convertible<Executor, AwaitableExecutor>::value
> = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ex The executor that will be used to schedule the new thread of
* execution.
*
* @param a The asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr) @endcode
*
* @par Example
* @code
* asio::awaitable<void> echo(tcp::socket socket)
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }
*
* // ...
*
* asio::co_spawn(my_executor,
* echo(std::move(my_tcp_socket)),
* asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename Executor, typename AwaitableExecutor,
ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr)) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
inline ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr))
co_spawn(const Executor& ex, awaitable<void, AwaitableExecutor> a,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
constraint_t<
(is_executor<Executor>::value || execution::is_executor<Executor>::value)
&& is_convertible<Executor, AwaitableExecutor>::value
> = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ctx An execution context that will provide the executor to be used to
* schedule the new thread of execution.
*
* @param a The asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, T) @endcode
*
* @par Example
* @code
* asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* asio::co_spawn(my_io_context,
* echo(std::move(my_tcp_socket)),
* [](std::exception_ptr e, std::size_t n)
* {
* std::cout << "transferred " << n << "\n";
* });
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename ExecutionContext, typename T, typename AwaitableExecutor,
ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr, T)) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
typename ExecutionContext::executor_type)>
inline ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr, T))
co_spawn(ExecutionContext& ctx, awaitable<T, AwaitableExecutor> a,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(
typename ExecutionContext::executor_type),
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
&& is_convertible<typename ExecutionContext::executor_type,
AwaitableExecutor>::value
> = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ctx An execution context that will provide the executor to be used to
* schedule the new thread of execution.
*
* @param a The asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr) @endcode
*
* @par Example
* @code
* asio::awaitable<void> echo(tcp::socket socket)
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }
*
* // ...
*
* asio::co_spawn(my_io_context,
* echo(std::move(my_tcp_socket)),
* asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename ExecutionContext, typename AwaitableExecutor,
ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr)) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
typename ExecutionContext::executor_type)>
inline ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr))
co_spawn(ExecutionContext& ctx, awaitable<void, AwaitableExecutor> a,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(
typename ExecutionContext::executor_type),
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
&& is_convertible<typename ExecutionContext::executor_type,
AwaitableExecutor>::value
> = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ex The executor that will be used to schedule the new thread of
* execution.
*
* @param f A nullary function object with a return type of the form
* @c asio::awaitable<R,E> that will be used as the coroutine's entry
* point.
*
* @param token The @ref completion_token that will handle the notification
* that the thread of execution has completed. If @c R is @c void, the function
* signature of the completion handler must be:
*
* @code void handler(std::exception_ptr); @endcode
* Otherwise, the function signature of the completion handler must be:
* @code void handler(std::exception_ptr, R); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, R) @endcode
* where @c R is the first template argument to the @c awaitable returned by the
* supplied function object @c F:
* @code asio::awaitable<R, AwaitableExecutor> F() @endcode
*
* @par Example
* @code
* asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* asio::co_spawn(my_executor,
* [socket = std::move(my_tcp_socket)]() mutable
* -> asio::awaitable<void>
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }, asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename Executor, typename F,
ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
result_of_t<F()>>::type) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
typename detail::awaitable_signature<result_of_t<F()>>::type)
co_spawn(const Executor& ex, F&& f,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ctx An execution context that will provide the executor to be used to
* schedule the new thread of execution.
*
* @param f A nullary function object with a return type of the form
* @c asio::awaitable<R,E> that will be used as the coroutine's entry
* point.
*
* @param token The @ref completion_token that will handle the notification
* that the thread of execution has completed. If @c R is @c void, the function
* signature of the completion handler must be:
*
* @code void handler(std::exception_ptr); @endcode
* Otherwise, the function signature of the completion handler must be:
* @code void handler(std::exception_ptr, R); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, R) @endcode
* where @c R is the first template argument to the @c awaitable returned by the
* supplied function object @c F:
* @code asio::awaitable<R, AwaitableExecutor> F() @endcode
*
* @par Example
* @code
* asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* asio::co_spawn(my_io_context,
* [socket = std::move(my_tcp_socket)]() mutable
* -> asio::awaitable<void>
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }, asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename ExecutionContext, typename F,
ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
result_of_t<F()>>::type) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
typename ExecutionContext::executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
typename detail::awaitable_signature<result_of_t<F()>>::type)
co_spawn(ExecutionContext& ctx, F&& f,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(
typename ExecutionContext::executor_type),
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0);
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/co_spawn.hpp"
#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_CO_SPAWN_HPP

View File

@@ -2,7 +2,7 @@
// completion_condition.hpp // completion_condition.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -0,0 +1,319 @@
//
// compose.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 ASIO_COMPOSE_HPP
#define ASIO_COMPOSE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/associated_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/base_from_cancellation_state.hpp"
#include "asio/detail/composed_work.hpp"
#include "asio/detail/handler_cont_helpers.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Impl, typename Work, typename Handler, typename Signature>
class composed_op;
template <typename Impl, typename Work, typename Handler,
typename R, typename... Args>
class composed_op<Impl, Work, Handler, R(Args...)>
: public base_from_cancellation_state<Handler>
{
public:
template <typename I, typename W, typename H>
composed_op(I&& impl,
W&& work,
H&& handler)
: base_from_cancellation_state<Handler>(
handler, enable_terminal_cancellation()),
impl_(static_cast<I&&>(impl)),
work_(static_cast<W&&>(work)),
handler_(static_cast<H&&>(handler)),
invocations_(0)
{
}
composed_op(composed_op&& other)
: base_from_cancellation_state<Handler>(
static_cast<base_from_cancellation_state<Handler>&&>(other)),
impl_(static_cast<Impl&&>(other.impl_)),
work_(static_cast<Work&&>(other.work_)),
handler_(static_cast<Handler&&>(other.handler_)),
invocations_(other.invocations_)
{
}
typedef typename composed_work_guard<
typename Work::head_type>::executor_type io_executor_type;
io_executor_type get_io_executor() const noexcept
{
return work_.head_.get_executor();
}
typedef associated_executor_t<Handler, io_executor_type> executor_type;
executor_type get_executor() const noexcept
{
return (get_associated_executor)(handler_, work_.head_.get_executor());
}
typedef associated_allocator_t<Handler, std::allocator<void>> allocator_type;
allocator_type get_allocator() const noexcept
{
return (get_associated_allocator)(handler_, std::allocator<void>());
}
template<typename... T>
void operator()(T&&... t)
{
if (invocations_ < ~0u)
++invocations_;
this->get_cancellation_state().slot().clear();
impl_(*this, static_cast<T&&>(t)...);
}
void complete(Args... args)
{
this->work_.reset();
static_cast<Handler&&>(this->handler_)(static_cast<Args&&>(args)...);
}
void reset_cancellation_state()
{
base_from_cancellation_state<Handler>::reset_cancellation_state(handler_);
}
template <typename Filter>
void reset_cancellation_state(Filter&& filter)
{
base_from_cancellation_state<Handler>::reset_cancellation_state(handler_,
static_cast<Filter&&>(filter));
}
template <typename InFilter, typename OutFilter>
void reset_cancellation_state(InFilter&& in_filter,
OutFilter&& out_filter)
{
base_from_cancellation_state<Handler>::reset_cancellation_state(handler_,
static_cast<InFilter&&>(in_filter),
static_cast<OutFilter&&>(out_filter));
}
cancellation_type_t cancelled() const noexcept
{
return base_from_cancellation_state<Handler>::cancelled();
}
//private:
Impl impl_;
Work work_;
Handler handler_;
unsigned invocations_;
};
template <typename Impl, typename Work, typename Handler, typename Signature>
inline bool asio_handler_is_continuation(
composed_op<Impl, Work, Handler, Signature>* this_handler)
{
return this_handler->invocations_ > 1 ? true
: asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Signature, typename Executors>
class initiate_composed_op
{
public:
typedef typename composed_io_executors<Executors>::head_type executor_type;
template <typename T>
explicit initiate_composed_op(int, T&& executors)
: executors_(static_cast<T&&>(executors))
{
}
executor_type get_executor() const noexcept
{
return executors_.head_;
}
template <typename Handler, typename Impl>
void operator()(Handler&& handler,
Impl&& impl) const
{
composed_op<decay_t<Impl>, composed_work<Executors>,
decay_t<Handler>, Signature>(
static_cast<Impl&&>(impl),
composed_work<Executors>(executors_),
static_cast<Handler&&>(handler))();
}
private:
composed_io_executors<Executors> executors_;
};
template <typename Signature, typename Executors>
inline initiate_composed_op<Signature, Executors> make_initiate_composed_op(
composed_io_executors<Executors>&& executors)
{
return initiate_composed_op<Signature, Executors>(0,
static_cast<composed_io_executors<Executors>&&>(executors));
}
} // namespace detail
#if !defined(GENERATING_DOCUMENTATION)
template <template <typename, typename> class Associator,
typename Impl, typename Work, typename Handler,
typename Signature, typename DefaultCandidate>
struct associator<Associator,
detail::composed_op<Impl, Work, Handler, Signature>,
DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const detail::composed_op<Impl, Work, Handler, Signature>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::composed_op<Impl, Work, Handler, Signature>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Launch an asynchronous operation with a stateful implementation.
/**
* The async_compose function simplifies the implementation of composed
* asynchronous operations automatically wrapping a stateful function object
* with a conforming intermediate completion handler.
*
* @param implementation A function object that contains the implementation of
* the composed asynchronous operation. The first argument to the function
* object is a non-const reference to the enclosing intermediate completion
* handler. The remaining arguments are any arguments that originate from the
* completion handlers of any asynchronous operations performed by the
* implementation.
*
* @param token The completion token.
*
* @param io_objects_or_executors Zero or more I/O objects or I/O executors for
* which outstanding work must be maintained.
*
* @par Per-Operation Cancellation
* By default, terminal per-operation cancellation is enabled for
* composed operations that are implemented using @c async_compose. To
* disable cancellation for the composed operation, or to alter its
* supported cancellation types, call the @c self object's @c
* reset_cancellation_state function.
*
* @par Example:
*
* @code struct async_echo_implementation
* {
* tcp::socket& socket_;
* asio::mutable_buffer buffer_;
* enum { starting, reading, writing } state_;
*
* template <typename Self>
* void operator()(Self& self,
* asio::error_code error = {},
* std::size_t n = 0)
* {
* switch (state_)
* {
* case starting:
* state_ = reading;
* socket_.async_read_some(
* buffer_, std::move(self));
* break;
* case reading:
* if (error)
* {
* self.complete(error, 0);
* }
* else
* {
* state_ = writing;
* asio::async_write(socket_, buffer_,
* asio::transfer_exactly(n),
* std::move(self));
* }
* break;
* case writing:
* self.complete(error, n);
* break;
* }
* }
* };
*
* template <typename CompletionToken>
* auto async_echo(tcp::socket& socket,
* asio::mutable_buffer buffer,
* CompletionToken&& token) ->
* decltype(
* asio::async_compose<CompletionToken,
* void(asio::error_code, std::size_t)>(
* std::declval<async_echo_implementation>(),
* token, socket))
* {
* return asio::async_compose<CompletionToken,
* void(asio::error_code, std::size_t)>(
* async_echo_implementation{socket, buffer,
* async_echo_implementation::starting},
* token, socket);
* } @endcode
*/
template <typename CompletionToken, typename Signature,
typename Implementation, typename... IoObjectsOrExecutors>
auto async_compose(Implementation&& implementation,
type_identity_t<CompletionToken>& token,
IoObjectsOrExecutors&&... io_objects_or_executors)
-> decltype(
async_initiate<CompletionToken, Signature>(
detail::make_initiate_composed_op<Signature>(
detail::make_composed_io_executors(
detail::get_composed_io_executor(
static_cast<IoObjectsOrExecutors&&>(
io_objects_or_executors))...)),
token, static_cast<Implementation&&>(implementation)))
{
return async_initiate<CompletionToken, Signature>(
detail::make_initiate_composed_op<Signature>(
detail::make_composed_io_executors(
detail::get_composed_io_executor(
static_cast<IoObjectsOrExecutors&&>(
io_objects_or_executors))...)),
token, static_cast<Implementation&&>(implementation));
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_COMPOSE_HPP

View File

@@ -2,7 +2,7 @@
// connect.hpp // connect.hpp
// ~~~~~~~~~~~ // ~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -27,6 +27,10 @@ namespace asio {
namespace detail namespace detail
{ {
struct default_connect_condition;
template <typename, typename> class initiate_async_range_connect;
template <typename, typename> class initiate_async_iterator_connect;
char (&has_iterator_helper(...))[2]; char (&has_iterator_helper(...))[2];
template <typename T> template <typename T>
@@ -82,17 +86,15 @@ struct is_endpoint_sequence
* Otherwise, contains the error from the last connection attempt. * Otherwise, contains the error from the last connection attempt.
* *
* @par Example * @par Example
* @code tcp::resolver r(io_context); * @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service"); * tcp::resolver::query q("host", "service");
* tcp::socket s(io_context); * tcp::socket s(my_context);
* asio::connect(s, r.resolve(q)); @endcode * asio::connect(s, r.resolve(q)); @endcode
*/ */
template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence> template <typename Protocol, typename Executor, typename EndpointSequence>
typename Protocol::endpoint connect( typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
basic_socket<Protocol ASIO_SVC_TARG>& s,
const EndpointSequence& endpoints, const EndpointSequence& endpoints,
typename enable_if<is_endpoint_sequence< constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0);
EndpointSequence>::value>::type* = 0);
/// Establishes a socket connection by trying each endpoint in a sequence. /// Establishes a socket connection by trying each endpoint in a sequence.
/** /**
@@ -114,9 +116,9 @@ typename Protocol::endpoint connect(
* default-constructed endpoint. * default-constructed endpoint.
* *
* @par Example * @par Example
* @code tcp::resolver r(io_context); * @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service"); * tcp::resolver::query q("host", "service");
* tcp::socket s(io_context); * tcp::socket s(my_context);
* asio::error_code ec; * asio::error_code ec;
* asio::connect(s, r.resolve(q), ec); * asio::connect(s, r.resolve(q), ec);
* if (ec) * if (ec)
@@ -124,12 +126,10 @@ typename Protocol::endpoint connect(
* // An error occurred. * // An error occurred.
* } @endcode * } @endcode
*/ */
template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence> template <typename Protocol, typename Executor, typename EndpointSequence>
typename Protocol::endpoint connect( typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
basic_socket<Protocol ASIO_SVC_TARG>& s,
const EndpointSequence& endpoints, asio::error_code& ec, const EndpointSequence& endpoints, asio::error_code& ec,
typename enable_if<is_endpoint_sequence< constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0);
EndpointSequence>::value>::type* = 0);
#if !defined(ASIO_NO_DEPRECATED) #if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use range overload.) Establishes a socket connection by trying /// (Deprecated: Use range overload.) Establishes a socket connection by trying
@@ -156,9 +156,9 @@ typename Protocol::endpoint connect(
* Iterator represents the end of the sequence. This is a valid assumption for * Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator. * iterator types such as @c asio::ip::tcp::resolver::iterator.
*/ */
template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); constraint_t<!is_endpoint_sequence<Iterator>::value> = 0);
/// (Deprecated: Use range overload.) Establishes a socket connection by trying /// (Deprecated: Use range overload.) Establishes a socket connection by trying
/// each endpoint in a sequence. /// each endpoint in a sequence.
@@ -184,10 +184,10 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin,
* Iterator represents the end of the sequence. This is a valid assumption for * Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator. * iterator types such as @c asio::ip::tcp::resolver::iterator.
*/ */
template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, asio::error_code& ec, Iterator begin, asio::error_code& ec,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); constraint_t<!is_endpoint_sequence<Iterator>::value> = 0);
#endif // !defined(ASIO_NO_DEPRECATED) #endif // !defined(ASIO_NO_DEPRECATED)
/// Establishes a socket connection by trying each endpoint in a sequence. /// Establishes a socket connection by trying each endpoint in a sequence.
@@ -211,14 +211,14 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* Otherwise, contains the error from the last connection attempt. * Otherwise, contains the error from the last connection attempt.
* *
* @par Example * @par Example
* @code tcp::resolver r(io_context); * @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service"); * tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q); * tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context); * tcp::socket s(my_context);
* asio::connect(s, e.begin(), e.end()); @endcode * asio::connect(s, e.begin(), e.end()); @endcode
*/ */
template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end); Iterator begin, Iterator end);
/// Establishes a socket connection by trying each endpoint in a sequence. /// Establishes a socket connection by trying each endpoint in a sequence.
@@ -243,10 +243,10 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* endpoint. Otherwise, the end iterator. * endpoint. Otherwise, the end iterator.
* *
* @par Example * @par Example
* @code tcp::resolver r(io_context); * @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service"); * tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q); * tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context); * tcp::socket s(my_context);
* asio::error_code ec; * asio::error_code ec;
* asio::connect(s, e.begin(), e.end(), ec); * asio::connect(s, e.begin(), e.end(), ec);
* if (ec) * if (ec)
@@ -254,8 +254,8 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* // An error occurred. * // An error occurred.
* } @endcode * } @endcode
*/ */
template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end, asio::error_code& ec); Iterator begin, Iterator end, asio::error_code& ec);
/// Establishes a socket connection by trying each endpoint in a sequence. /// Establishes a socket connection by trying each endpoint in a sequence.
@@ -302,20 +302,18 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* } * }
* }; @endcode * }; @endcode
* It would be used with the asio::connect function as follows: * It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context); * @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service"); * tcp::resolver::query q("host", "service");
* tcp::socket s(io_context); * tcp::socket s(my_context);
* tcp::endpoint e = asio::connect(s, * tcp::endpoint e = asio::connect(s,
* r.resolve(q), my_connect_condition()); * r.resolve(q), my_connect_condition());
* std::cout << "Connected to: " << e << std::endl; @endcode * std::cout << "Connected to: " << e << std::endl; @endcode
*/ */
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Executor,
typename EndpointSequence, typename ConnectCondition> typename EndpointSequence, typename ConnectCondition>
typename Protocol::endpoint connect( typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
basic_socket<Protocol ASIO_SVC_TARG>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition, const EndpointSequence& endpoints, ConnectCondition connect_condition,
typename enable_if<is_endpoint_sequence< constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0);
EndpointSequence>::value>::type* = 0);
/// Establishes a socket connection by trying each endpoint in a sequence. /// Establishes a socket connection by trying each endpoint in a sequence.
/** /**
@@ -362,9 +360,9 @@ typename Protocol::endpoint connect(
* } * }
* }; @endcode * }; @endcode
* It would be used with the asio::connect function as follows: * It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context); * @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service"); * tcp::resolver::query q("host", "service");
* tcp::socket s(io_context); * tcp::socket s(my_context);
* asio::error_code ec; * asio::error_code ec;
* tcp::endpoint e = asio::connect(s, * tcp::endpoint e = asio::connect(s,
* r.resolve(q), my_connect_condition(), ec); * r.resolve(q), my_connect_condition(), ec);
@@ -377,14 +375,12 @@ typename Protocol::endpoint connect(
* std::cout << "Connected to: " << e << std::endl; * std::cout << "Connected to: " << e << std::endl;
* } @endcode * } @endcode
*/ */
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Executor,
typename EndpointSequence, typename ConnectCondition> typename EndpointSequence, typename ConnectCondition>
typename Protocol::endpoint connect( typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
basic_socket<Protocol ASIO_SVC_TARG>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition, const EndpointSequence& endpoints, ConnectCondition connect_condition,
asio::error_code& ec, asio::error_code& ec,
typename enable_if<is_endpoint_sequence< constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0);
EndpointSequence>::value>::type* = 0);
#if !defined(ASIO_NO_DEPRECATED) #if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use range overload.) Establishes a socket connection by trying /// (Deprecated: Use range overload.) Establishes a socket connection by trying
@@ -422,11 +418,11 @@ typename Protocol::endpoint connect(
* Iterator represents the end of the sequence. This is a valid assumption for * Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator. * iterator types such as @c asio::ip::tcp::resolver::iterator.
*/ */
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition> typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, ConnectCondition connect_condition, Iterator begin, ConnectCondition connect_condition,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); constraint_t<!is_endpoint_sequence<Iterator>::value> = 0);
/// (Deprecated: Use range overload.) Establishes a socket connection by trying /// (Deprecated: Use range overload.) Establishes a socket connection by trying
/// each endpoint in a sequence. /// each endpoint in a sequence.
@@ -463,11 +459,11 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* Iterator represents the end of the sequence. This is a valid assumption for * Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator. * iterator types such as @c asio::ip::tcp::resolver::iterator.
*/ */
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition> typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
ConnectCondition connect_condition, asio::error_code& ec, ConnectCondition connect_condition, asio::error_code& ec,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); constraint_t<!is_endpoint_sequence<Iterator>::value> = 0);
#endif // !defined(ASIO_NO_DEPRECATED) #endif // !defined(ASIO_NO_DEPRECATED)
/// Establishes a socket connection by trying each endpoint in a sequence. /// Establishes a socket connection by trying each endpoint in a sequence.
@@ -516,17 +512,17 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin,
* } * }
* }; @endcode * }; @endcode
* It would be used with the asio::connect function as follows: * It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context); * @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service"); * tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q); * tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context); * tcp::socket s(my_context);
* tcp::resolver::results_type::iterator i = asio::connect( * tcp::resolver::results_type::iterator i = asio::connect(
* s, e.begin(), e.end(), my_connect_condition()); * s, e.begin(), e.end(), my_connect_condition());
* std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode * std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode
*/ */
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition> typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
Iterator end, ConnectCondition connect_condition); Iterator end, ConnectCondition connect_condition);
/// Establishes a socket connection by trying each endpoint in a sequence. /// Establishes a socket connection by trying each endpoint in a sequence.
@@ -576,10 +572,10 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin,
* } * }
* }; @endcode * }; @endcode
* It would be used with the asio::connect function as follows: * It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context); * @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service"); * tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q); * tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context); * tcp::socket s(my_context);
* asio::error_code ec; * asio::error_code ec;
* tcp::resolver::results_type::iterator i = asio::connect( * tcp::resolver::results_type::iterator i = asio::connect(
* s, e.begin(), e.end(), my_connect_condition()); * s, e.begin(), e.end(), my_connect_condition());
@@ -592,9 +588,9 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin,
* std::cout << "Connected to: " << i->endpoint() << std::endl; * std::cout << "Connected to: " << i->endpoint() << std::endl;
* } @endcode * } @endcode
*/ */
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition> typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end, ConnectCondition connect_condition, Iterator begin, Iterator end, ConnectCondition connect_condition,
asio::error_code& ec); asio::error_code& ec);
@@ -614,16 +610,19 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* This function attempts to connect a socket to one of a sequence of * This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect * endpoints. It does this by repeated calls to the socket's @c async_connect
* member function, once for each endpoint in the sequence, until a connection * member function, once for each endpoint in the sequence, until a connection
* is successfully established. * is successfully established. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
* *
* @param s The socket to be connected. If the socket is already open, it will * @param s The socket to be connected. If the socket is already open, it will
* be closed. * be closed.
* *
* @param endpoints A sequence of endpoints. * @param endpoints A sequence of endpoints.
* *
* @param handler The handler to be called when the connect operation * @param token The @ref completion_token that will be used to produce a
* completes. Copies will be made of the handler as required. The function * completion handler, which will be called when the connect completes.
* signature of the handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* // Result of operation. if the sequence is empty, set to * // Result of operation. if the sequence is empty, set to
* // asio::error::not_found. Otherwise, contains the * // asio::error::not_found. Otherwise, contains the
@@ -635,14 +634,17 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* const typename Protocol::endpoint& endpoint * const typename Protocol::endpoint& endpoint
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, typename Protocol::endpoint) @endcode
* *
* @par Example * @par Example
* @code tcp::resolver r(io_context); * @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service"); * tcp::resolver::query q("host", "service");
* tcp::socket s(io_context); * tcp::socket s(my_context);
* *
* // ... * // ...
* *
@@ -668,16 +670,30 @@ Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* { * {
* // ... * // ...
* } @endcode * } @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* if they are also supported by the socket's @c async_connect operation.
*/ */
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Executor, typename EndpointSequence,
typename EndpointSequence, typename RangeConnectHandler> ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, typename Protocol::endpoint)) RangeConnectToken
void (asio::error_code, typename Protocol::endpoint)) = default_completion_token_t<Executor>>
async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, auto async_connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, const EndpointSequence& endpoints,
ASIO_MOVE_ARG(RangeConnectHandler) handler, RangeConnectToken&& token = default_completion_token_t<Executor>(),
typename enable_if<is_endpoint_sequence< constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0)
EndpointSequence>::value>::type* = 0); -> decltype(
async_initiate<RangeConnectToken,
void (asio::error_code, typename Protocol::endpoint)>(
declval<detail::initiate_async_range_connect<Protocol, Executor>>(),
token, endpoints, declval<detail::default_connect_condition>()));
#if !defined(ASIO_NO_DEPRECATED) #if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use range overload.) Asynchronously establishes a socket /// (Deprecated: Use range overload.) Asynchronously establishes a socket
@@ -686,16 +702,19 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* This function attempts to connect a socket to one of a sequence of * This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect * endpoints. It does this by repeated calls to the socket's @c async_connect
* member function, once for each endpoint in the sequence, until a connection * member function, once for each endpoint in the sequence, until a connection
* is successfully established. * is successfully established. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
* *
* @param s The socket to be connected. If the socket is already open, it will * @param s The socket to be connected. If the socket is already open, it will
* be closed. * be closed.
* *
* @param begin An iterator pointing to the start of a sequence of endpoints. * @param begin An iterator pointing to the start of a sequence of endpoints.
* *
* @param handler The handler to be called when the connect operation * @param token The @ref completion_token that will be used to produce a
* completes. Copies will be made of the handler as required. The function * completion handler, which will be called when the connect completes.
* signature of the handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* // Result of operation. if the sequence is empty, set to * // Result of operation. if the sequence is empty, set to
* // asio::error::not_found. Otherwise, contains the * // asio::error::not_found. Otherwise, contains the
@@ -707,21 +726,39 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* Iterator iterator * Iterator iterator
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, Iterator) @endcode
* *
* @note This overload assumes that a default constructed object of type @c * @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for * Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator. * iterator types such as @c asio::ip::tcp::resolver::iterator.
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* if they are also supported by the socket's @c async_connect operation.
*/ */
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Executor, typename Iterator,
typename Iterator, typename IteratorConnectHandler> ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, Iterator)) IteratorConnectToken = default_completion_token_t<Executor>>
void (asio::error_code, Iterator)) auto async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, IteratorConnectToken&& token = default_completion_token_t<Executor>(),
Iterator begin, ASIO_MOVE_ARG(IteratorConnectHandler) handler, constraint_t<!is_endpoint_sequence<Iterator>::value> = 0)
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); -> decltype(
async_initiate<IteratorConnectToken,
void (asio::error_code, Iterator)>(
declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(),
token, begin, Iterator(),
declval<detail::default_connect_condition>()));
#endif // !defined(ASIO_NO_DEPRECATED) #endif // !defined(ASIO_NO_DEPRECATED)
/// Asynchronously establishes a socket connection by trying each endpoint in a /// Asynchronously establishes a socket connection by trying each endpoint in a
@@ -730,7 +767,8 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* This function attempts to connect a socket to one of a sequence of * This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect * endpoints. It does this by repeated calls to the socket's @c async_connect
* member function, once for each endpoint in the sequence, until a connection * member function, once for each endpoint in the sequence, until a connection
* is successfully established. * is successfully established. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
* *
* @param s The socket to be connected. If the socket is already open, it will * @param s The socket to be connected. If the socket is already open, it will
* be closed. * be closed.
@@ -739,9 +777,11 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* *
* @param end An iterator pointing to the end of a sequence of endpoints. * @param end An iterator pointing to the end of a sequence of endpoints.
* *
* @param handler The handler to be called when the connect operation * @param token The @ref completion_token that will be used to produce a
* completes. Copies will be made of the handler as required. The function * completion handler, which will be called when the connect completes.
* signature of the handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* // Result of operation. if the sequence is empty, set to * // Result of operation. if the sequence is empty, set to
* // asio::error::not_found. Otherwise, contains the * // asio::error::not_found. Otherwise, contains the
@@ -753,13 +793,16 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* Iterator iterator * Iterator iterator
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, Iterator) @endcode
* *
* @par Example * @par Example
* @code std::vector<tcp::endpoint> endpoints = ...; * @code std::vector<tcp::endpoint> endpoints = ...;
* tcp::socket s(io_context); * tcp::socket s(my_context);
* asio::async_connect(s, * asio::async_connect(s,
* endpoints.begin(), endpoints.end(), * endpoints.begin(), endpoints.end(),
* connect_handler); * connect_handler);
@@ -772,14 +815,28 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* { * {
* // ... * // ...
* } @endcode * } @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* if they are also supported by the socket's @c async_connect operation.
*/ */
template <typename Protocol ASIO_SVC_TPARAM, template <typename Protocol, typename Executor, typename Iterator,
typename Iterator, typename IteratorConnectHandler> ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, Iterator)) IteratorConnectToken = default_completion_token_t<Executor>>
void (asio::error_code, Iterator)) auto async_connect(
async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end,
Iterator begin, Iterator end, IteratorConnectToken&& token = default_completion_token_t<Executor>())
ASIO_MOVE_ARG(IteratorConnectHandler) handler); -> decltype(
async_initiate<IteratorConnectToken,
void (asio::error_code, Iterator)>(
declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(),
token, begin, end, declval<detail::default_connect_condition>()));
/// Asynchronously establishes a socket connection by trying each endpoint in a /// Asynchronously establishes a socket connection by trying each endpoint in a
/// sequence. /// sequence.
@@ -787,7 +844,8 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* This function attempts to connect a socket to one of a sequence of * This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect * endpoints. It does this by repeated calls to the socket's @c async_connect
* member function, once for each endpoint in the sequence, until a connection * member function, once for each endpoint in the sequence, until a connection
* is successfully established. * is successfully established. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
* *
* @param s The socket to be connected. If the socket is already open, it will * @param s The socket to be connected. If the socket is already open, it will
* be closed. * be closed.
@@ -805,9 +863,11 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* The function object should return true if the next endpoint should be tried, * The function object should return true if the next endpoint should be tried,
* and false if it should be skipped. * and false if it should be skipped.
* *
* @param handler The handler to be called when the connect operation * @param token The @ref completion_token that will be used to produce a
* completes. Copies will be made of the handler as required. The function * completion handler, which will be called when the connect completes.
* signature of the handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* // Result of operation. if the sequence is empty, set to * // Result of operation. if the sequence is empty, set to
* // asio::error::not_found. Otherwise, contains the * // asio::error::not_found. Otherwise, contains the
@@ -819,9 +879,12 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* Iterator iterator * Iterator iterator
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, typename Protocol::endpoint) @endcode
* *
* @par Example * @par Example
* The following connect condition function object can be used to output * The following connect condition function object can be used to output
@@ -838,9 +901,9 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* } * }
* }; @endcode * }; @endcode
* It would be used with the asio::connect function as follows: * It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context); * @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service"); * tcp::resolver::query q("host", "service");
* tcp::socket s(io_context); * tcp::socket s(my_context);
* *
* // ... * // ...
* *
@@ -875,16 +938,31 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* std::cout << "Connected to: " << endpoint << std::endl; * std::cout << "Connected to: " << endpoint << std::endl;
* } * }
* } @endcode * } @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* if they are also supported by the socket's @c async_connect operation.
*/ */
template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence, template <typename Protocol, typename Executor,
typename ConnectCondition, typename RangeConnectHandler> typename EndpointSequence, typename ConnectCondition,
ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
void (asio::error_code, typename Protocol::endpoint)) typename Protocol::endpoint)) RangeConnectToken
async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, = default_completion_token_t<Executor>>
auto async_connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition, const EndpointSequence& endpoints, ConnectCondition connect_condition,
ASIO_MOVE_ARG(RangeConnectHandler) handler, RangeConnectToken&& token = default_completion_token_t<Executor>(),
typename enable_if<is_endpoint_sequence< constraint_t<is_endpoint_sequence<EndpointSequence>::value> = 0)
EndpointSequence>::value>::type* = 0); -> decltype(
async_initiate<RangeConnectToken,
void (asio::error_code, typename Protocol::endpoint)>(
declval<detail::initiate_async_range_connect<Protocol, Executor>>(),
token, endpoints, connect_condition));
#if !defined(ASIO_NO_DEPRECATED) #if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use range overload.) Asynchronously establishes a socket /// (Deprecated: Use range overload.) Asynchronously establishes a socket
@@ -893,7 +971,8 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* This function attempts to connect a socket to one of a sequence of * This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect * endpoints. It does this by repeated calls to the socket's @c async_connect
* member function, once for each endpoint in the sequence, until a connection * member function, once for each endpoint in the sequence, until a connection
* is successfully established. * is successfully established. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
* *
* @param s The socket to be connected. If the socket is already open, it will * @param s The socket to be connected. If the socket is already open, it will
* be closed. * be closed.
@@ -911,9 +990,11 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* The function object should return true if the next endpoint should be tried, * The function object should return true if the next endpoint should be tried,
* and false if it should be skipped. * and false if it should be skipped.
* *
* @param handler The handler to be called when the connect operation * @param token The @ref completion_token that will be used to produce a
* completes. Copies will be made of the handler as required. The function * completion handler, which will be called when the connect completes.
* signature of the handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* // Result of operation. if the sequence is empty, set to * // Result of operation. if the sequence is empty, set to
* // asio::error::not_found. Otherwise, contains the * // asio::error::not_found. Otherwise, contains the
@@ -925,22 +1006,40 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s,
* Iterator iterator * Iterator iterator
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, Iterator) @endcode
* *
* @note This overload assumes that a default constructed object of type @c * @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for * Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator. * iterator types such as @c asio::ip::tcp::resolver::iterator.
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* if they are also supported by the socket's @c async_connect operation.
*/ */
template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, template <typename Protocol, typename Executor,
typename ConnectCondition, typename IteratorConnectHandler> typename Iterator, typename ConnectCondition,
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
void (asio::error_code, Iterator)) Iterator)) IteratorConnectToken = default_completion_token_t<Executor>>
async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, auto async_connect(basic_socket<Protocol, Executor>& s,
ConnectCondition connect_condition, Iterator begin, ConnectCondition connect_condition,
ASIO_MOVE_ARG(IteratorConnectHandler) handler, IteratorConnectToken&& token = default_completion_token_t<Executor>(),
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); constraint_t<!is_endpoint_sequence<Iterator>::value> = 0)
-> decltype(
async_initiate<IteratorConnectToken,
void (asio::error_code, Iterator)>(
declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(),
token, begin, Iterator(), connect_condition));
#endif // !defined(ASIO_NO_DEPRECATED) #endif // !defined(ASIO_NO_DEPRECATED)
/// Asynchronously establishes a socket connection by trying each endpoint in a /// Asynchronously establishes a socket connection by trying each endpoint in a
@@ -949,7 +1048,8 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin,
* This function attempts to connect a socket to one of a sequence of * This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect * endpoints. It does this by repeated calls to the socket's @c async_connect
* member function, once for each endpoint in the sequence, until a connection * member function, once for each endpoint in the sequence, until a connection
* is successfully established. * is successfully established. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
* *
* @param s The socket to be connected. If the socket is already open, it will * @param s The socket to be connected. If the socket is already open, it will
* be closed. * be closed.
@@ -969,9 +1069,11 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin,
* The function object should return true if the next endpoint should be tried, * The function object should return true if the next endpoint should be tried,
* and false if it should be skipped. * and false if it should be skipped.
* *
* @param handler The handler to be called when the connect operation * @param token The @ref completion_token that will be used to produce a
* completes. Copies will be made of the handler as required. The function * completion handler, which will be called when the connect completes.
* signature of the handler must be: * Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler( * @code void handler(
* // Result of operation. if the sequence is empty, set to * // Result of operation. if the sequence is empty, set to
* // asio::error::not_found. Otherwise, contains the * // asio::error::not_found. Otherwise, contains the
@@ -983,9 +1085,12 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin,
* Iterator iterator * Iterator iterator
* ); @endcode * ); @endcode
* Regardless of whether the asynchronous operation completes immediately or * Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation * not, the completion handler will not be invoked from within this function.
* of the handler will be performed in a manner equivalent to using * On immediate completion, invocation of the handler will be performed in a
* asio::io_context::post(). * manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, Iterator) @endcode
* *
* @par Example * @par Example
* The following connect condition function object can be used to output * The following connect condition function object can be used to output
@@ -1002,9 +1107,9 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin,
* } * }
* }; @endcode * }; @endcode
* It would be used with the asio::connect function as follows: * It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context); * @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service"); * tcp::resolver::query q("host", "service");
* tcp::socket s(io_context); * tcp::socket s(my_context);
* *
* // ... * // ...
* *
@@ -1040,14 +1145,29 @@ async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin,
* std::cout << "Connected to: " << i->endpoint() << std::endl; * std::cout << "Connected to: " << i->endpoint() << std::endl;
* } * }
* } @endcode * } @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* if they are also supported by the socket's @c async_connect operation.
*/ */
template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, template <typename Protocol, typename Executor,
typename ConnectCondition, typename IteratorConnectHandler> typename Iterator, typename ConnectCondition,
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
void (asio::error_code, Iterator)) Iterator)) IteratorConnectToken = default_completion_token_t<Executor>>
async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, auto async_connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end, ConnectCondition connect_condition, Iterator begin, Iterator end, ConnectCondition connect_condition,
ASIO_MOVE_ARG(IteratorConnectHandler) handler); IteratorConnectToken&& token = default_completion_token_t<Executor>())
-> decltype(
async_initiate<IteratorConnectToken,
void (asio::error_code, Iterator)>(
declval<detail::initiate_async_iterator_connect<Protocol, Executor>>(),
token, begin, end, connect_condition));
/*@}*/ /*@}*/

View File

@@ -0,0 +1,83 @@
//
// connect_pipe.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 ASIO_CONNECT_PIPE_HPP
#define ASIO_CONNECT_PIPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_PIPE) \
|| defined(GENERATING_DOCUMENTATION)
#include "asio/basic_readable_pipe.hpp"
#include "asio/basic_writable_pipe.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
#if defined(ASIO_HAS_IOCP)
typedef HANDLE native_pipe_handle;
#else // defined(ASIO_HAS_IOCP)
typedef int native_pipe_handle;
#endif // defined(ASIO_HAS_IOCP)
ASIO_DECL void create_pipe(native_pipe_handle p[2],
asio::error_code& ec);
ASIO_DECL void close_pipe(native_pipe_handle p);
} // namespace detail
/// Connect two pipe ends using an anonymous pipe.
/**
* @param read_end The read end of the pipe.
*
* @param write_end The write end of the pipe.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename Executor1, typename Executor2>
void connect_pipe(basic_readable_pipe<Executor1>& read_end,
basic_writable_pipe<Executor2>& write_end);
/// Connect two pipe ends using an anonymous pipe.
/**
* @param read_end The read end of the pipe.
*
* @param write_end The write end of the pipe.
*
* @throws asio::system_error Thrown on failure.
*
* @param ec Set to indicate what error occurred, if any.
*/
template <typename Executor1, typename Executor2>
ASIO_SYNC_OP_VOID connect_pipe(basic_readable_pipe<Executor1>& read_end,
basic_writable_pipe<Executor2>& write_end, asio::error_code& ec);
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/connect_pipe.hpp"
#if defined(ASIO_HEADER_ONLY)
# include "asio/impl/connect_pipe.ipp"
#endif // defined(ASIO_HEADER_ONLY)
#endif // defined(ASIO_HAS_PIPE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_CONNECT_PIPE_HPP

View File

@@ -0,0 +1,75 @@
//
// consign.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 ASIO_CONSIGN_HPP
#define ASIO_CONSIGN_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <tuple>
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Completion token type used to specify that the completion handler should
/// carry additional values along with it.
/**
* This completion token adapter is typically used to keep at least one copy of
* an object, such as a smart pointer, alive until the completion handler is
* called.
*/
template <typename CompletionToken, typename... Values>
class consign_t
{
public:
/// Constructor.
template <typename T, typename... V>
constexpr explicit consign_t(T&& completion_token, V&&... values)
: token_(static_cast<T&&>(completion_token)),
values_(static_cast<V&&>(values)...)
{
}
#if defined(GENERATING_DOCUMENTATION)
private:
#endif // defined(GENERATING_DOCUMENTATION)
CompletionToken token_;
std::tuple<Values...> values_;
};
/// Completion token adapter used to specify that the completion handler should
/// carry additional values along with it.
/**
* This completion token adapter is typically used to keep at least one copy of
* an object, such as a smart pointer, alive until the completion handler is
* called.
*/
template <typename CompletionToken, typename... Values>
ASIO_NODISCARD inline constexpr
consign_t<decay_t<CompletionToken>, decay_t<Values>...>
consign(CompletionToken&& completion_token, Values&&... values)
{
return consign_t<decay_t<CompletionToken>, decay_t<Values>...>(
static_cast<CompletionToken&&>(completion_token),
static_cast<Values&&>(values)...);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/consign.hpp"
#endif // ASIO_CONSIGN_HPP

View File

@@ -2,7 +2,7 @@
// coroutine.hpp // coroutine.hpp
// ~~~~~~~~~~~~~ // ~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -205,7 +205,7 @@ class coroutine_ref;
* { * {
* do * do
* { * {
* socket_.reset(new tcp::socket(io_context_)); * socket_.reset(new tcp::socket(my_context_));
* yield acceptor->async_accept(*socket_, *this); * yield acceptor->async_accept(*socket_, *this);
* fork server(*this)(); * fork server(*this)();
* } while (is_parent()); * } while (is_parent());
@@ -227,7 +227,7 @@ class coroutine_ref;
* Note that @c fork doesn't do the actual forking by itself. It is the * Note that @c fork doesn't do the actual forking by itself. It is the
* application's responsibility to create a clone of the coroutine and call it. * application's responsibility to create a clone of the coroutine and call it.
* The clone can be called immediately, as above, or scheduled for delayed * The clone can be called immediately, as above, or scheduled for delayed
* execution using something like io_context::post(). * execution using something like asio::post().
* *
* @par Alternate macro names * @par Alternate macro names
* *
@@ -266,6 +266,7 @@ class coroutine_ref
public: public:
coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {} coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {} coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
coroutine_ref(const coroutine_ref&) = default;
~coroutine_ref() { if (!modified_) value_ = -1; } ~coroutine_ref() { if (!modified_) value_ = -1; }
operator int() const { return value_; } operator int() const { return value_; }
int& operator=(int v) { modified_ = true; return value_ = v; } int& operator=(int v) { modified_ = true; return value_ = v; }

View File

@@ -2,7 +2,7 @@
// deadline_timer.hpp // deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// defer.hpp // defer.hpp
// ~~~~~~~~~ // ~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -17,9 +17,13 @@
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#include "asio/async_result.hpp" #include "asio/async_result.hpp"
#include "asio/detail/initiate_defer.hpp"
#include "asio/detail/type_traits.hpp" #include "asio/detail/type_traits.hpp"
#include "asio/execution_context.hpp" #include "asio/execution_context.hpp"
#include "asio/execution/blocking.hpp"
#include "asio/execution/executor.hpp"
#include "asio/is_executor.hpp" #include "asio/is_executor.hpp"
#include "asio/require.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
@@ -31,27 +35,58 @@ namespace asio {
* executor. The function object is queued for execution, and is never called * executor. The function object is queued for execution, and is never called
* from the current thread prior to returning from <tt>defer()</tt>. * from the current thread prior to returning from <tt>defer()</tt>.
* *
* This function has the following effects: * The use of @c defer(), rather than @ref post(), indicates the caller's
* preference that the executor defer the queueing of the function object. This
* may allow the executor to optimise queueing for cases when the function
* object represents a continuation of the current call context.
* *
* @li Constructs a function object handler of type @c Handler, initialized * @param token The @ref completion_token that will be used to produce a
* with <tt>handler(forward<CompletionToken>(token))</tt>. * completion handler. The function signature of the completion handler must be:
* @code void handler(); @endcode
* *
* @li Constructs an object @c result of type <tt>async_result<Handler></tt>, * @returns This function returns <tt>async_initiate<NullaryToken,
* initializing the object as <tt>result(handler)</tt>. * void()>(Init{}, token)</tt>, where @c Init is a function object type defined
* as:
* *
* @li Obtains the handler's associated executor object @c ex by performing * @code class Init
* <tt>get_associated_executor(handler)</tt>. * {
* public:
* template <typename CompletionHandler>
* void operator()(CompletionHandler&& completion_handler) const;
* }; @endcode
*
* The function call operator of @c Init:
*
* @li Obtains the handler's associated executor object @c ex of type @c Ex by
* performing @code auto ex = get_associated_executor(handler); @endcode
* *
* @li Obtains the handler's associated allocator object @c alloc by performing * @li Obtains the handler's associated allocator object @c alloc by performing
* <tt>get_associated_allocator(handler)</tt>. * @code auto alloc = get_associated_allocator(handler); @endcode
* *
* @li Performs <tt>ex.defer(std::move(handler), alloc)</tt>. * @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs
* @code prefer(
* require(ex, execution::blocking.never),
* execution::relationship.continuation,
* execution::allocator(alloc)
* ).execute(std::forward<CompletionHandler>(completion_handler)); @endcode
* *
* @li Returns <tt>result.get()</tt>. * @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs
* @code ex.defer(
* std::forward<CompletionHandler>(completion_handler),
* alloc); @endcode
*
* @par Completion Signature
* @code void() @endcode
*/ */
template <typename CompletionToken> template <ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken>
ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( auto defer(NullaryToken&& token)
ASIO_MOVE_ARG(CompletionToken) token); -> decltype(
async_initiate<NullaryToken, void()>(
declval<detail::initiate_defer>(), token))
{
return async_initiate<NullaryToken, void()>(
detail::initiate_defer(), token);
}
/// Submits a completion token or function object for execution. /// Submits a completion token or function object for execution.
/** /**
@@ -59,49 +94,125 @@ ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer(
* The function object is queued for execution, and is never called from the * The function object is queued for execution, and is never called from the
* current thread prior to returning from <tt>defer()</tt>. * current thread prior to returning from <tt>defer()</tt>.
* *
* This function has the following effects: * The use of @c defer(), rather than @ref post(), indicates the caller's
* preference that the executor defer the queueing of the function object. This
* may allow the executor to optimise queueing for cases when the function
* object represents a continuation of the current call context.
* *
* @li Constructs a function object handler of type @c Handler, initialized * @param ex The target executor.
* with <tt>handler(forward<CompletionToken>(token))</tt>.
* *
* @li Constructs an object @c result of type <tt>async_result<Handler></tt>, * @param token The @ref completion_token that will be used to produce a
* initializing the object as <tt>result(handler)</tt>. * completion handler. The function signature of the completion handler must be:
* @code void handler(); @endcode
* *
* @li Obtains the handler's associated executor object @c ex1 by performing * @returns This function returns <tt>async_initiate<NullaryToken,
* <tt>get_associated_executor(handler)</tt>. * void()>(Init{ex}, token)</tt>, where @c Init is a function object type
* defined as:
* *
* @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>. * @code class Init
* {
* public:
* using executor_type = Executor;
* explicit Init(const Executor& ex) : ex_(ex) {}
* executor_type get_executor() const noexcept { return ex_; }
* template <typename CompletionHandler>
* void operator()(CompletionHandler&& completion_handler) const;
* private:
* Executor ex_; // exposition only
* }; @endcode
*
* The function call operator of @c Init:
*
* @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by
* performing @code auto ex1 = get_associated_executor(handler, ex); @endcode
* *
* @li Obtains the handler's associated allocator object @c alloc by performing * @li Obtains the handler's associated allocator object @c alloc by performing
* <tt>get_associated_allocator(handler)</tt>. * @code auto alloc = get_associated_allocator(handler); @endcode
* *
* @li Constructs a function object @c f with a function call operator that * @li If <tt>execution::is_executor<Ex1>::value</tt> is true, constructs a
* performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by * function object @c f with a member @c executor_ that is initialised with
* <tt>w.reset()</tt>. * <tt>prefer(ex1, execution::outstanding_work.tracked)</tt>, a member @c
* handler_ that is a decay-copy of @c completion_handler, and a function call
* operator that performs:
* @code auto a = get_associated_allocator(handler_);
* prefer(executor_, execution::allocator(a)).execute(std::move(handler_));
* @endcode
* *
* @li Performs <tt>Executor(ex).defer(std::move(f), alloc)</tt>. * @li If <tt>execution::is_executor<Ex1>::value</tt> is false, constructs a
* function object @c f with a member @c work_ that is initialised with
* <tt>make_work_guard(ex1)</tt>, a member @c handler_ that is a decay-copy of
* @c completion_handler, and a function call operator that performs:
* @code auto a = get_associated_allocator(handler_);
* work_.get_executor().dispatch(std::move(handler_), a);
* work_.reset(); @endcode
* *
* @li Returns <tt>result.get()</tt>. * @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs
* @code prefer(
* require(ex, execution::blocking.never),
* execution::relationship.continuation,
* execution::allocator(alloc)
* ).execute(std::move(f)); @endcode
*
* @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs
* @code ex.defer(std::move(f), alloc); @endcode
*
* @par Completion Signature
* @code void() @endcode
*/ */
template <typename Executor, typename CompletionToken> template <typename Executor,
ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token, = default_completion_token_t<Executor>>
typename enable_if<is_executor<Executor>::value>::type* = 0); auto defer(const Executor& ex,
NullaryToken&& token
= default_completion_token_t<Executor>(),
constraint_t<
(execution::is_executor<Executor>::value
&& can_require<Executor, execution::blocking_t::never_t>::value)
|| is_executor<Executor>::value
> = 0)
-> decltype(
async_initiate<NullaryToken, void()>(
declval<detail::initiate_defer_with_executor<Executor>>(), token))
{
return async_initiate<NullaryToken, void()>(
detail::initiate_defer_with_executor<Executor>(ex), token);
}
/// Submits a completion token or function object for execution. /// Submits a completion token or function object for execution.
/** /**
* @returns <tt>defer(ctx.get_executor(), forward<CompletionToken>(token))</tt>. * @param ctx An execution context, from which the target executor is obtained.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler. The function signature of the completion handler must be:
* @code void handler(); @endcode
*
* @returns <tt>defer(ctx.get_executor(), forward<NullaryToken>(token))</tt>.
*
* @par Completion Signature
* @code void() @endcode
*/ */
template <typename ExecutionContext, typename CompletionToken> template <typename ExecutionContext,
ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token, = default_completion_token_t<typename ExecutionContext::executor_type>>
typename enable_if<is_convertible< auto defer(ExecutionContext& ctx,
ExecutionContext&, execution_context&>::value>::type* = 0); NullaryToken&& token
= default_completion_token_t<typename ExecutionContext::executor_type>(),
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
-> decltype(
async_initiate<NullaryToken, void()>(
declval<detail::initiate_defer_with_executor<
typename ExecutionContext::executor_type>>(), token))
{
return async_initiate<NullaryToken, void()>(
detail::initiate_defer_with_executor<
typename ExecutionContext::executor_type>(
ctx.get_executor()), token);
}
} // namespace asio } // namespace asio
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
#include "asio/impl/defer.hpp"
#endif // ASIO_DEFER_HPP #endif // ASIO_DEFER_HPP

View File

@@ -0,0 +1,715 @@
//
// deferred.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 ASIO_DEFERRED_HPP
#define ASIO_DEFERRED_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <tuple>
#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/utility.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Trait for detecting objects that are usable as deferred operations.
template <typename T>
struct is_deferred : false_type
{
};
/// Helper type to wrap multiple completion signatures.
template <typename... Signatures>
struct deferred_signatures
{
};
namespace detail {
// Helper trait for getting the completion signatures of the tail in a sequence
// when invoked with the specified arguments.
template <typename Tail, typename... Signatures>
struct deferred_sequence_signatures;
template <typename Tail, typename R, typename... Args, typename... Signatures>
struct deferred_sequence_signatures<Tail, R(Args...), Signatures...>
: completion_signature_of<decltype(declval<Tail>()(declval<Args>()...))>
{
static_assert(
!is_same<decltype(declval<Tail>()(declval<Args>()...)), void>::value,
"deferred functions must produce a deferred return type");
};
// Completion handler for the head component of a deferred sequence.
template <typename Handler, typename Tail>
class deferred_sequence_handler
{
public:
template <typename H, typename T>
explicit deferred_sequence_handler(H&& handler, T&& tail)
: handler_(static_cast<H&&>(handler)),
tail_(static_cast<T&&>(tail))
{
}
template <typename... Args>
void operator()(Args&&... args)
{
static_cast<Tail&&>(tail_)(
static_cast<Args&&>(args)...)(
static_cast<Handler&&>(handler_));
}
//private:
Handler handler_;
Tail tail_;
};
template <typename Head, typename Tail, typename... Signatures>
class deferred_sequence_base
{
private:
struct initiate
{
template <typename Handler>
void operator()(Handler&& handler, Head head, Tail&& tail)
{
static_cast<Head&&>(head)(
deferred_sequence_handler<decay_t<Handler>, decay_t<Tail>>(
static_cast<Handler&&>(handler), static_cast<Tail&&>(tail)));
}
};
Head head_;
Tail tail_;
public:
template <typename H, typename T>
constexpr explicit deferred_sequence_base(H&& head, T&& tail)
: head_(static_cast<H&&>(head)),
tail_(static_cast<T&&>(tail))
{
}
template <ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
async_initiate<CompletionToken, Signatures...>(
initiate(), token, static_cast<Head&&>(this->head_),
static_cast<Tail&&>(this->tail_)))
{
return async_initiate<CompletionToken, Signatures...>(initiate(),
token, static_cast<Head&&>(head_), static_cast<Tail&&>(tail_));
}
template <ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
async_initiate<CompletionToken, Signatures...>(
initiate(), token, this->head_, this->tail_))
{
return async_initiate<CompletionToken, Signatures...>(
initiate(), token, head_, tail_);
}
};
// Two-step application of variadic Signatures to determine correct base type.
template <typename Head, typename Tail>
struct deferred_sequence_types
{
template <typename... Signatures>
struct op1
{
typedef deferred_sequence_base<Head, Tail, Signatures...> type;
};
template <typename... Signatures>
struct op2
{
typedef typename deferred_sequence_signatures<Tail, Signatures...>::template
apply<op1>::type::type type;
};
typedef typename completion_signature_of<Head>::template
apply<op2>::type::type base;
};
} // namespace detail
/// Used to represent an empty deferred action.
struct deferred_noop
{
/// No effect.
template <typename... Args>
void operator()(Args&&...) &&
{
}
/// No effect.
template <typename... Args>
void operator()(Args&&...) const &
{
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <>
struct is_deferred<deferred_noop> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Tag type to disambiguate deferred constructors.
struct deferred_init_tag {};
/// Wraps a function object so that it may be used as an element in a deferred
/// composition.
template <typename Function>
class deferred_function
{
public:
/// Constructor.
template <typename F>
constexpr explicit deferred_function(deferred_init_tag, F&& function)
: function_(static_cast<F&&>(function))
{
}
//private:
Function function_;
public:
template <typename... Args>
auto operator()(Args&&... args) &&
-> decltype(
static_cast<Function&&>(this->function_)(static_cast<Args&&>(args)...))
{
return static_cast<Function&&>(function_)(static_cast<Args&&>(args)...);
}
template <typename... Args>
auto operator()(Args&&... args) const &
-> decltype(Function(function_)(static_cast<Args&&>(args)...))
{
return Function(function_)(static_cast<Args&&>(args)...);
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename Function>
struct is_deferred<deferred_function<Function>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Encapsulates deferred values.
template <typename... Values>
class ASIO_NODISCARD deferred_values
{
private:
std::tuple<Values...> values_;
struct initiate
{
template <typename Handler, typename... V>
void operator()(Handler handler, V&&... values)
{
static_cast<Handler&&>(handler)(static_cast<V&&>(values)...);
}
};
template <typename CompletionToken, std::size_t... I>
auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, void(Values...)>(initiate(), token,
std::get<I>(static_cast<std::tuple<Values...>&&>(this->values_))...))
{
return async_initiate<CompletionToken, void(Values...)>(initiate(), token,
std::get<I>(static_cast<std::tuple<Values...>&&>(values_))...);
}
template <typename CompletionToken, std::size_t... I>
auto const_invoke_helper(CompletionToken&& token,
detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, void(Values...)>(
initiate(), token, std::get<I>(values_)...))
{
return async_initiate<CompletionToken, void(Values...)>(
initiate(), token, std::get<I>(values_)...);
}
public:
/// Construct a deferred asynchronous operation from the arguments to an
/// initiation function object.
template <typename... V>
constexpr explicit deferred_values(
deferred_init_tag, V&&... values)
: values_(static_cast<V&&>(values)...)
{
}
/// Initiate the deferred operation using the supplied completion token.
template <ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>()))
{
return this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>());
}
template <ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>()))
{
return this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>());
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename... Values>
struct is_deferred<deferred_values<Values...>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Encapsulates a deferred asynchronous operation.
template <typename Signature, typename Initiation, typename... InitArgs>
class ASIO_NODISCARD deferred_async_operation
{
private:
typedef decay_t<Initiation> initiation_t;
initiation_t initiation_;
typedef std::tuple<decay_t<InitArgs>...> init_args_t;
init_args_t init_args_;
template <typename CompletionToken, std::size_t... I>
auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, Signature>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...))
{
return async_initiate<CompletionToken, Signature>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...);
}
template <typename CompletionToken, std::size_t... I>
auto const_invoke_helper(CompletionToken&& token,
detail::index_sequence<I...>) const &
-> decltype(
async_initiate<CompletionToken, Signature>(
initiation_t(initiation_), token, std::get<I>(init_args_)...))
{
return async_initiate<CompletionToken, Signature>(
initiation_t(initiation_), token, std::get<I>(init_args_)...);
}
public:
/// Construct a deferred asynchronous operation from the arguments to an
/// initiation function object.
template <typename I, typename... A>
constexpr explicit deferred_async_operation(
deferred_init_tag, I&& initiation, A&&... init_args)
: initiation_(static_cast<I&&>(initiation)),
init_args_(static_cast<A&&>(init_args)...)
{
}
/// Initiate the asynchronous operation using the supplied completion token.
template <ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
template <ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
};
/// Encapsulates a deferred asynchronous operation thas has multiple completion
/// signatures.
template <typename... Signatures, typename Initiation, typename... InitArgs>
class ASIO_NODISCARD deferred_async_operation<
deferred_signatures<Signatures...>, Initiation, InitArgs...>
{
private:
typedef decay_t<Initiation> initiation_t;
initiation_t initiation_;
typedef std::tuple<decay_t<InitArgs>...> init_args_t;
init_args_t init_args_;
template <typename CompletionToken, std::size_t... I>
auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, Signatures...>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...))
{
return async_initiate<CompletionToken, Signatures...>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...);
}
template <typename CompletionToken, std::size_t... I>
auto const_invoke_helper(CompletionToken&& token,
detail::index_sequence<I...>) const &
-> decltype(
async_initiate<CompletionToken, Signatures...>(
initiation_t(initiation_), token, std::get<I>(init_args_)...))
{
return async_initiate<CompletionToken, Signatures...>(
initiation_t(initiation_), token, std::get<I>(init_args_)...);
}
public:
/// Construct a deferred asynchronous operation from the arguments to an
/// initiation function object.
template <typename I, typename... A>
constexpr explicit deferred_async_operation(
deferred_init_tag, I&& initiation, A&&... init_args)
: initiation_(static_cast<I&&>(initiation)),
init_args_(static_cast<A&&>(init_args)...)
{
}
/// Initiate the asynchronous operation using the supplied completion token.
template <ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
template <ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename Signature, typename Initiation, typename... InitArgs>
struct is_deferred<
deferred_async_operation<Signature, Initiation, InitArgs...>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Defines a link between two consecutive operations in a sequence.
template <typename Head, typename Tail>
class ASIO_NODISCARD deferred_sequence :
public detail::deferred_sequence_types<Head, Tail>::base
{
public:
template <typename H, typename T>
constexpr explicit deferred_sequence(deferred_init_tag, H&& head, T&& tail)
: detail::deferred_sequence_types<Head, Tail>::base(
static_cast<H&&>(head), static_cast<T&&>(tail))
{
}
#if defined(GENERATING_DOCUMENTATION)
template <typename CompletionToken>
auto operator()(CompletionToken&& token) &&;
template <typename CompletionToken>
auto operator()(CompletionToken&& token) const &;
#endif // defined(GENERATING_DOCUMENTATION)
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename Head, typename Tail>
struct is_deferred<deferred_sequence<Head, Tail>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Used to represent a deferred conditional branch.
template <typename OnTrue = deferred_noop, typename OnFalse = deferred_noop>
class ASIO_NODISCARD deferred_conditional
{
private:
template <typename T, typename F> friend class deferred_conditional;
// Helper constructor.
template <typename T, typename F>
explicit deferred_conditional(bool b, T&& on_true, F&& on_false)
: on_true_(static_cast<T&&>(on_true)),
on_false_(static_cast<F&&>(on_false)),
bool_(b)
{
}
OnTrue on_true_;
OnFalse on_false_;
bool bool_;
public:
/// Construct a deferred conditional with the value to determine which branch
/// will be executed.
constexpr explicit deferred_conditional(bool b)
: on_true_(),
on_false_(),
bool_(b)
{
}
/// Invoke the conditional branch bsaed on the stored value.
template <typename... Args>
auto operator()(Args&&... args) &&
-> decltype(static_cast<OnTrue&&>(on_true_)(static_cast<Args&&>(args)...))
{
if (bool_)
{
return static_cast<OnTrue&&>(on_true_)(static_cast<Args&&>(args)...);
}
else
{
return static_cast<OnFalse&&>(on_false_)(static_cast<Args&&>(args)...);
}
}
template <typename... Args>
auto operator()(Args&&... args) const &
-> decltype(on_true_(static_cast<Args&&>(args)...))
{
if (bool_)
{
return on_true_(static_cast<Args&&>(args)...);
}
else
{
return on_false_(static_cast<Args&&>(args)...);
}
}
/// Set the true branch of the conditional.
template <typename T>
deferred_conditional<T, OnFalse> then(T on_true,
constraint_t<
is_deferred<T>::value
>* = 0,
constraint_t<
is_same<
conditional_t<true, OnTrue, T>,
deferred_noop
>::value
>* = 0) &&
{
return deferred_conditional<T, OnFalse>(
bool_, static_cast<T&&>(on_true),
static_cast<OnFalse&&>(on_false_));
}
/// Set the false branch of the conditional.
template <typename T>
deferred_conditional<OnTrue, T> otherwise(T on_false,
constraint_t<
is_deferred<T>::value
>* = 0,
constraint_t<
!is_same<
conditional_t<true, OnTrue, T>,
deferred_noop
>::value
>* = 0,
constraint_t<
is_same<
conditional_t<true, OnFalse, T>,
deferred_noop
>::value
>* = 0) &&
{
return deferred_conditional<OnTrue, T>(
bool_, static_cast<OnTrue&&>(on_true_),
static_cast<T&&>(on_false));
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename OnTrue, typename OnFalse>
struct is_deferred<deferred_conditional<OnTrue, OnFalse>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Class used to specify that an asynchronous operation should return a
/// function object to lazily launch the operation.
/**
* The deferred_t class is used to indicate that an asynchronous operation
* should return a function object which is itself an initiation function. A
* deferred_t object may be passed as a completion token to an asynchronous
* operation, typically using the special value @c asio::deferred. For
* example:
*
* @code auto my_deferred_op
* = my_socket.async_read_some(my_buffer,
* asio::deferred); @endcode
*
* The initiating function (async_read_some in the above example) returns a
* function object that will lazily initiate the operation.
*/
class deferred_t
{
public:
/// Default constructor.
constexpr deferred_t()
{
}
/// Adapts an executor to add the @c deferred_t completion token as the
/// default.
template <typename InnerExecutor>
struct executor_with_default : InnerExecutor
{
/// Specify @c deferred_t as the default completion token type.
typedef deferred_t default_completion_token_type;
/// Construct the adapted executor from the inner executor type.
template <typename InnerExecutor1>
executor_with_default(const InnerExecutor1& ex,
constraint_t<
conditional_t<
!is_same<InnerExecutor1, executor_with_default>::value,
is_convertible<InnerExecutor1, InnerExecutor>,
false_type
>::value
> = 0) noexcept
: InnerExecutor(ex)
{
}
};
/// Type alias to adapt an I/O object to use @c deferred_t as its
/// default completion token type.
template <typename T>
using as_default_on_t = typename T::template rebind_executor<
executor_with_default<typename T::executor_type>>::other;
/// Function helper to adapt an I/O object to use @c deferred_t as its
/// default completion token type.
template <typename T>
static typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other
as_default_on(T&& object)
{
return typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other(static_cast<T&&>(object));
}
/// Creates a new deferred from a function.
template <typename Function>
constraint_t<
!is_deferred<decay_t<Function>>::value,
deferred_function<decay_t<Function>>
> operator()(Function&& function) const
{
return deferred_function<decay_t<Function>>(
deferred_init_tag{}, static_cast<Function&&>(function));
}
/// Passes through anything that is already deferred.
template <typename T>
constraint_t<
is_deferred<decay_t<T>>::value,
decay_t<T>
> operator()(T&& t) const
{
return static_cast<T&&>(t);
}
/// Returns a deferred operation that returns the provided values.
template <typename... Args>
static constexpr deferred_values<decay_t<Args>...> values(Args&&... args)
{
return deferred_values<decay_t<Args>...>(
deferred_init_tag{}, static_cast<Args&&>(args)...);
}
/// Creates a conditional object for branching deferred operations.
static constexpr deferred_conditional<> when(bool b)
{
return deferred_conditional<>(b);
}
};
/// Pipe operator used to chain deferred operations.
template <typename Head, typename Tail>
inline auto operator|(Head head, Tail&& tail)
-> constraint_t<
is_deferred<Head>::value,
decltype(static_cast<Head&&>(head)(static_cast<Tail&&>(tail)))
>
{
return static_cast<Head&&>(head)(static_cast<Tail&&>(tail));
}
/// A @ref completion_token object used to specify that an asynchronous
/// operation should return a function object to lazily launch the operation.
/**
* See the documentation for asio::deferred_t for a usage example.
*/
constexpr deferred_t deferred;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/deferred.hpp"
#endif // ASIO_DEFERRED_HPP

View File

@@ -0,0 +1,105 @@
//
// detached.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 ASIO_DETACHED_HPP
#define ASIO_DETACHED_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <memory>
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// A @ref completion_token type used to specify that an asynchronous operation
/// is detached.
/**
* The detached_t class is used to indicate that an asynchronous operation is
* detached. That is, there is no completion handler waiting for the
* operation's result. A detached_t object may be passed as a handler to an
* asynchronous operation, typically using the special value
* @c asio::detached. For example:
*
* @code my_socket.async_send(my_buffer, asio::detached);
* @endcode
*/
class detached_t
{
public:
/// Constructor.
constexpr detached_t()
{
}
/// Adapts an executor to add the @c detached_t completion token as the
/// default.
template <typename InnerExecutor>
struct executor_with_default : InnerExecutor
{
/// Specify @c detached_t as the default completion token type.
typedef detached_t default_completion_token_type;
/// Construct the adapted executor from the inner executor type.
executor_with_default(const InnerExecutor& ex) noexcept
: InnerExecutor(ex)
{
}
/// Convert the specified executor to the inner executor type, then use
/// that to construct the adapted executor.
template <typename OtherExecutor>
executor_with_default(const OtherExecutor& ex,
constraint_t<
is_convertible<OtherExecutor, InnerExecutor>::value
> = 0) noexcept
: InnerExecutor(ex)
{
}
};
/// Type alias to adapt an I/O object to use @c detached_t as its
/// default completion token type.
template <typename T>
using as_default_on_t = typename T::template rebind_executor<
executor_with_default<typename T::executor_type>>::other;
/// Function helper to adapt an I/O object to use @c detached_t as its
/// default completion token type.
template <typename T>
static typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other
as_default_on(T&& object)
{
return typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other(static_cast<T&&>(object));
}
};
/// A @ref completion_token object used to specify that an asynchronous
/// operation is detached.
/**
* See the documentation for asio::detached_t for a usage example.
*/
constexpr detached_t detached;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/detached.hpp"
#endif // ASIO_DETACHED_HPP

View File

@@ -2,7 +2,7 @@
// detail/array.hpp // detail/array.hpp
// ~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -17,20 +17,12 @@
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#if defined(ASIO_HAS_STD_ARRAY)
#include <array> #include <array>
#else // defined(ASIO_HAS_STD_ARRAY)
# include <boost/array.hpp>
#endif // defined(ASIO_HAS_STD_ARRAY)
namespace asio { namespace asio {
namespace detail { namespace detail {
#if defined(ASIO_HAS_STD_ARRAY)
using std::array; using std::array;
#else // defined(ASIO_HAS_STD_ARRAY)
using boost::array;
#endif // defined(ASIO_HAS_STD_ARRAY)
} // namespace detail } // namespace detail
} // namespace asio } // namespace asio

View File

@@ -2,7 +2,7 @@
// detail/array_fwd.hpp // detail/array_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -27,8 +27,6 @@ class array;
// Standard library components can't be forward declared, so we'll have to // Standard library components can't be forward declared, so we'll have to
// include the array header. Fortunately, it's fairly lightweight and doesn't // include the array header. Fortunately, it's fairly lightweight and doesn't
// add significantly to the compile time. // add significantly to the compile time.
#if defined(ASIO_HAS_STD_ARRAY)
#include <array> #include <array>
#endif // defined(ASIO_HAS_STD_ARRAY)
#endif // ASIO_DETAIL_ARRAY_FWD_HPP #endif // ASIO_DETAIL_ARRAY_FWD_HPP

View File

@@ -2,7 +2,7 @@
// detail/assert.hpp // detail/assert.hpp
// ~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/atomic_count.hpp // detail/atomic_count.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -19,11 +19,9 @@
#if !defined(ASIO_HAS_THREADS) #if !defined(ASIO_HAS_THREADS)
// Nothing to include. // Nothing to include.
#elif defined(ASIO_HAS_STD_ATOMIC) #else // !defined(ASIO_HAS_THREADS)
# include <atomic> # include <atomic>
#else // defined(ASIO_HAS_STD_ATOMIC) #endif // !defined(ASIO_HAS_THREADS)
# include <boost/detail/atomic_count.hpp>
#endif // defined(ASIO_HAS_STD_ATOMIC)
namespace asio { namespace asio {
namespace detail { namespace detail {
@@ -31,13 +29,29 @@ namespace detail {
#if !defined(ASIO_HAS_THREADS) #if !defined(ASIO_HAS_THREADS)
typedef long atomic_count; typedef long atomic_count;
inline void increment(atomic_count& a, long b) { a += b; } inline void increment(atomic_count& a, long b) { a += b; }
#elif defined(ASIO_HAS_STD_ATOMIC) inline void decrement(atomic_count& a, long b) { a -= b; }
inline void ref_count_up(atomic_count& a) { ++a; }
inline bool ref_count_down(atomic_count& a) { return --a == 0; }
#else // !defined(ASIO_HAS_THREADS)
typedef std::atomic<long> atomic_count; typedef std::atomic<long> atomic_count;
inline void increment(atomic_count& a, long b) { a += b; } inline void increment(atomic_count& a, long b) { a += b; }
#else // defined(ASIO_HAS_STD_ATOMIC) inline void decrement(atomic_count& a, long b) { a -= b; }
typedef boost::detail::atomic_count atomic_count;
inline void increment(atomic_count& a, long b) { while (b > 0) ++a, --b; } inline void ref_count_up(atomic_count& a)
#endif // defined(ASIO_HAS_STD_ATOMIC) {
a.fetch_add(1, std::memory_order_relaxed);
}
inline bool ref_count_down(atomic_count& a)
{
if (a.fetch_sub(1, std::memory_order_release) == 1)
{
std::atomic_thread_fence(std::memory_order_acquire);
return true;
}
return false;
}
#endif // !defined(ASIO_HAS_THREADS)
} // namespace detail } // namespace detail
} // namespace asio } // namespace asio

View File

@@ -0,0 +1,164 @@
//
// detail/base_from_cancellation_state.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 ASIO_DETAIL_BASE_FROM_CANCELLATION_STATE_HPP
#define ASIO_DETAIL_BASE_FROM_CANCELLATION_STATE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/associated_cancellation_slot.hpp"
#include "asio/cancellation_state.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Handler, typename = void>
class base_from_cancellation_state
{
public:
typedef cancellation_slot cancellation_slot_type;
cancellation_slot_type get_cancellation_slot() const noexcept
{
return cancellation_state_.slot();
}
cancellation_state get_cancellation_state() const noexcept
{
return cancellation_state_;
}
protected:
explicit base_from_cancellation_state(const Handler& handler)
: cancellation_state_(
asio::get_associated_cancellation_slot(handler))
{
}
template <typename Filter>
base_from_cancellation_state(const Handler& handler, Filter filter)
: cancellation_state_(
asio::get_associated_cancellation_slot(handler), filter, filter)
{
}
template <typename InFilter, typename OutFilter>
base_from_cancellation_state(const Handler& handler,
InFilter&& in_filter,
OutFilter&& out_filter)
: cancellation_state_(
asio::get_associated_cancellation_slot(handler),
static_cast<InFilter&&>(in_filter),
static_cast<OutFilter&&>(out_filter))
{
}
void reset_cancellation_state(const Handler& handler)
{
cancellation_state_ = cancellation_state(
asio::get_associated_cancellation_slot(handler));
}
template <typename Filter>
void reset_cancellation_state(const Handler& handler, Filter filter)
{
cancellation_state_ = cancellation_state(
asio::get_associated_cancellation_slot(handler), filter, filter);
}
template <typename InFilter, typename OutFilter>
void reset_cancellation_state(const Handler& handler,
InFilter&& in_filter,
OutFilter&& out_filter)
{
cancellation_state_ = cancellation_state(
asio::get_associated_cancellation_slot(handler),
static_cast<InFilter&&>(in_filter),
static_cast<OutFilter&&>(out_filter));
}
cancellation_type_t cancelled() const noexcept
{
return cancellation_state_.cancelled();
}
private:
cancellation_state cancellation_state_;
};
template <typename Handler>
class base_from_cancellation_state<Handler,
enable_if_t<
is_same<
typename associated_cancellation_slot<
Handler, cancellation_slot
>::asio_associated_cancellation_slot_is_unspecialised,
void
>::value
>
>
{
public:
cancellation_state get_cancellation_state() const noexcept
{
return cancellation_state();
}
protected:
explicit base_from_cancellation_state(const Handler&)
{
}
template <typename Filter>
base_from_cancellation_state(const Handler&, Filter)
{
}
template <typename InFilter, typename OutFilter>
base_from_cancellation_state(const Handler&,
InFilter&&,
OutFilter&&)
{
}
void reset_cancellation_state(const Handler&)
{
}
template <typename Filter>
void reset_cancellation_state(const Handler&, Filter)
{
}
template <typename InFilter, typename OutFilter>
void reset_cancellation_state(const Handler&,
InFilter&&,
OutFilter&&)
{
}
constexpr cancellation_type_t cancelled() const noexcept
{
return cancellation_type::none;
}
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_BASE_FROM_CANCELLATION_STATE_HPP

View File

@@ -2,7 +2,7 @@
// detail/base_from_completion_cond.hpp // detail/base_from_completion_cond.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -27,8 +27,9 @@ template <typename CompletionCondition>
class base_from_completion_cond class base_from_completion_cond
{ {
protected: protected:
explicit base_from_completion_cond(CompletionCondition completion_condition) explicit base_from_completion_cond(CompletionCondition& completion_condition)
: completion_condition_(completion_condition) : completion_condition_(
static_cast<CompletionCondition&&>(completion_condition))
{ {
} }

View File

@@ -2,7 +2,7 @@
// detail/bind_handler.hpp // detail/bind_handler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,11 +16,8 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#include "asio/associated_allocator.hpp" #include "asio/associator.hpp"
#include "asio/associated_executor.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_cont_helpers.hpp" #include "asio/detail/handler_cont_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/type_traits.hpp" #include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
@@ -28,24 +25,78 @@
namespace asio { namespace asio {
namespace detail { namespace detail {
template <typename Handler>
class binder0
{
public:
template <typename T>
binder0(int, T&& handler)
: handler_(static_cast<T&&>(handler))
{
}
binder0(Handler& handler)
: handler_(static_cast<Handler&&>(handler))
{
}
binder0(const binder0& other)
: handler_(other.handler_)
{
}
binder0(binder0&& other)
: handler_(static_cast<Handler&&>(other.handler_))
{
}
void operator()()
{
static_cast<Handler&&>(handler_)();
}
void operator()() const
{
handler_();
}
//private:
Handler handler_;
};
template <typename Handler>
inline bool asio_handler_is_continuation(
binder0<Handler>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Handler>
inline binder0<decay_t<Handler>> bind_handler(
Handler&& handler)
{
return binder0<decay_t<Handler>>(
0, static_cast<Handler&&>(handler));
}
template <typename Handler, typename Arg1> template <typename Handler, typename Arg1>
class binder1 class binder1
{ {
public: public:
template <typename T> template <typename T>
binder1(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1) binder1(int, T&& handler, const Arg1& arg1)
: handler_(ASIO_MOVE_CAST(T)(handler)), : handler_(static_cast<T&&>(handler)),
arg1_(arg1) arg1_(arg1)
{ {
} }
binder1(Handler& handler, const Arg1& arg1) binder1(Handler& handler, const Arg1& arg1)
: handler_(ASIO_MOVE_CAST(Handler)(handler)), : handler_(static_cast<Handler&&>(handler)),
arg1_(arg1) arg1_(arg1)
{ {
} }
#if defined(ASIO_HAS_MOVE)
binder1(const binder1& other) binder1(const binder1& other)
: handler_(other.handler_), : handler_(other.handler_),
arg1_(other.arg1_) arg1_(other.arg1_)
@@ -53,15 +104,15 @@ public:
} }
binder1(binder1&& other) binder1(binder1&& other)
: handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), : handler_(static_cast<Handler&&>(other.handler_)),
arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)) arg1_(static_cast<Arg1&&>(other.arg1_))
{ {
} }
#endif // defined(ASIO_HAS_MOVE)
void operator()() void operator()()
{ {
handler_(static_cast<const Arg1&>(arg1_)); static_cast<Handler&&>(handler_)(
static_cast<const Arg1&>(arg1_));
} }
void operator()() const void operator()() const
@@ -74,22 +125,6 @@ public:
Arg1 arg1_; Arg1 arg1_;
}; };
template <typename Handler, typename Arg1>
inline void* asio_handler_allocate(std::size_t size,
binder1<Handler, Arg1>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}
template <typename Handler, typename Arg1>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder1<Handler, Arg1>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}
template <typename Handler, typename Arg1> template <typename Handler, typename Arg1>
inline bool asio_handler_is_continuation( inline bool asio_handler_is_continuation(
binder1<Handler, Arg1>* this_handler) binder1<Handler, Arg1>* this_handler)
@@ -98,28 +133,12 @@ inline bool asio_handler_is_continuation(
this_handler->handler_); this_handler->handler_);
} }
template <typename Function, typename Handler, typename Arg1>
inline void asio_handler_invoke(Function& function,
binder1<Handler, Arg1>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Function, typename Handler, typename Arg1>
inline void asio_handler_invoke(const Function& function,
binder1<Handler, Arg1>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Handler, typename Arg1> template <typename Handler, typename Arg1>
inline binder1<typename decay<Handler>::type, Arg1> bind_handler( inline binder1<decay_t<Handler>, Arg1> bind_handler(
ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1) Handler&& handler, const Arg1& arg1)
{ {
return binder1<typename decay<Handler>::type, Arg1>(0, return binder1<decay_t<Handler>, Arg1>(0,
ASIO_MOVE_CAST(Handler)(handler), arg1); static_cast<Handler&&>(handler), arg1);
} }
template <typename Handler, typename Arg1, typename Arg2> template <typename Handler, typename Arg1, typename Arg2>
@@ -127,22 +146,21 @@ class binder2
{ {
public: public:
template <typename T> template <typename T>
binder2(int, ASIO_MOVE_ARG(T) handler, binder2(int, T&& handler,
const Arg1& arg1, const Arg2& arg2) const Arg1& arg1, const Arg2& arg2)
: handler_(ASIO_MOVE_CAST(T)(handler)), : handler_(static_cast<T&&>(handler)),
arg1_(arg1), arg1_(arg1),
arg2_(arg2) arg2_(arg2)
{ {
} }
binder2(Handler& handler, const Arg1& arg1, const Arg2& arg2) binder2(Handler& handler, const Arg1& arg1, const Arg2& arg2)
: handler_(ASIO_MOVE_CAST(Handler)(handler)), : handler_(static_cast<Handler&&>(handler)),
arg1_(arg1), arg1_(arg1),
arg2_(arg2) arg2_(arg2)
{ {
} }
#if defined(ASIO_HAS_MOVE)
binder2(const binder2& other) binder2(const binder2& other)
: handler_(other.handler_), : handler_(other.handler_),
arg1_(other.arg1_), arg1_(other.arg1_),
@@ -151,16 +169,16 @@ public:
} }
binder2(binder2&& other) binder2(binder2&& other)
: handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), : handler_(static_cast<Handler&&>(other.handler_)),
arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), arg1_(static_cast<Arg1&&>(other.arg1_)),
arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)) arg2_(static_cast<Arg2&&>(other.arg2_))
{ {
} }
#endif // defined(ASIO_HAS_MOVE)
void operator()() void operator()()
{ {
handler_(static_cast<const Arg1&>(arg1_), static_cast<Handler&&>(handler_)(
static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_)); static_cast<const Arg2&>(arg2_));
} }
@@ -175,22 +193,6 @@ public:
Arg2 arg2_; Arg2 arg2_;
}; };
template <typename Handler, typename Arg1, typename Arg2>
inline void* asio_handler_allocate(std::size_t size,
binder2<Handler, Arg1, Arg2>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder2<Handler, Arg1, Arg2>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2> template <typename Handler, typename Arg1, typename Arg2>
inline bool asio_handler_is_continuation( inline bool asio_handler_is_continuation(
binder2<Handler, Arg1, Arg2>* this_handler) binder2<Handler, Arg1, Arg2>* this_handler)
@@ -199,28 +201,12 @@ inline bool asio_handler_is_continuation(
this_handler->handler_); this_handler->handler_);
} }
template <typename Function, typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_invoke(Function& function,
binder2<Handler, Arg1, Arg2>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Function, typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_invoke(const Function& function,
binder2<Handler, Arg1, Arg2>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2> template <typename Handler, typename Arg1, typename Arg2>
inline binder2<typename decay<Handler>::type, Arg1, Arg2> bind_handler( inline binder2<decay_t<Handler>, Arg1, Arg2> bind_handler(
ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2) Handler&& handler, const Arg1& arg1, const Arg2& arg2)
{ {
return binder2<typename decay<Handler>::type, Arg1, Arg2>(0, return binder2<decay_t<Handler>, Arg1, Arg2>(0,
ASIO_MOVE_CAST(Handler)(handler), arg1, arg2); static_cast<Handler&&>(handler), arg1, arg2);
} }
template <typename Handler, typename Arg1, typename Arg2, typename Arg3> template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
@@ -228,9 +214,9 @@ class binder3
{ {
public: public:
template <typename T> template <typename T>
binder3(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1, binder3(int, T&& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3) const Arg2& arg2, const Arg3& arg3)
: handler_(ASIO_MOVE_CAST(T)(handler)), : handler_(static_cast<T&&>(handler)),
arg1_(arg1), arg1_(arg1),
arg2_(arg2), arg2_(arg2),
arg3_(arg3) arg3_(arg3)
@@ -239,14 +225,13 @@ public:
binder3(Handler& handler, const Arg1& arg1, binder3(Handler& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3) const Arg2& arg2, const Arg3& arg3)
: handler_(ASIO_MOVE_CAST(Handler)(handler)), : handler_(static_cast<Handler&&>(handler)),
arg1_(arg1), arg1_(arg1),
arg2_(arg2), arg2_(arg2),
arg3_(arg3) arg3_(arg3)
{ {
} }
#if defined(ASIO_HAS_MOVE)
binder3(const binder3& other) binder3(const binder3& other)
: handler_(other.handler_), : handler_(other.handler_),
arg1_(other.arg1_), arg1_(other.arg1_),
@@ -256,18 +241,19 @@ public:
} }
binder3(binder3&& other) binder3(binder3&& other)
: handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), : handler_(static_cast<Handler&&>(other.handler_)),
arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), arg1_(static_cast<Arg1&&>(other.arg1_)),
arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)), arg2_(static_cast<Arg2&&>(other.arg2_)),
arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)) arg3_(static_cast<Arg3&&>(other.arg3_))
{ {
} }
#endif // defined(ASIO_HAS_MOVE)
void operator()() void operator()()
{ {
handler_(static_cast<const Arg1&>(arg1_), static_cast<Handler&&>(handler_)(
static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_)); static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_));
} }
void operator()() const void operator()() const
@@ -282,22 +268,6 @@ public:
Arg3 arg3_; Arg3 arg3_;
}; };
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline void* asio_handler_allocate(std::size_t size,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3> template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline bool asio_handler_is_continuation( inline bool asio_handler_is_continuation(
binder3<Handler, Arg1, Arg2, Arg3>* this_handler) binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
@@ -306,31 +276,13 @@ inline bool asio_handler_is_continuation(
this_handler->handler_); this_handler->handler_);
} }
template <typename Function, typename Handler,
typename Arg1, typename Arg2, typename Arg3>
inline void asio_handler_invoke(Function& function,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Function, typename Handler,
typename Arg1, typename Arg2, typename Arg3>
inline void asio_handler_invoke(const Function& function,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3> template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3> bind_handler( inline binder3<decay_t<Handler>, Arg1, Arg2, Arg3> bind_handler(
ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2, Handler&& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3) const Arg3& arg3)
{ {
return binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3>(0, return binder3<decay_t<Handler>, Arg1, Arg2, Arg3>(0,
ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3); static_cast<Handler&&>(handler), arg1, arg2, arg3);
} }
template <typename Handler, typename Arg1, template <typename Handler, typename Arg1,
@@ -339,9 +291,9 @@ class binder4
{ {
public: public:
template <typename T> template <typename T>
binder4(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1, binder4(int, T&& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
: handler_(ASIO_MOVE_CAST(T)(handler)), : handler_(static_cast<T&&>(handler)),
arg1_(arg1), arg1_(arg1),
arg2_(arg2), arg2_(arg2),
arg3_(arg3), arg3_(arg3),
@@ -351,7 +303,7 @@ public:
binder4(Handler& handler, const Arg1& arg1, binder4(Handler& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
: handler_(ASIO_MOVE_CAST(Handler)(handler)), : handler_(static_cast<Handler&&>(handler)),
arg1_(arg1), arg1_(arg1),
arg2_(arg2), arg2_(arg2),
arg3_(arg3), arg3_(arg3),
@@ -359,7 +311,6 @@ public:
{ {
} }
#if defined(ASIO_HAS_MOVE)
binder4(const binder4& other) binder4(const binder4& other)
: handler_(other.handler_), : handler_(other.handler_),
arg1_(other.arg1_), arg1_(other.arg1_),
@@ -370,19 +321,20 @@ public:
} }
binder4(binder4&& other) binder4(binder4&& other)
: handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), : handler_(static_cast<Handler&&>(other.handler_)),
arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), arg1_(static_cast<Arg1&&>(other.arg1_)),
arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)), arg2_(static_cast<Arg2&&>(other.arg2_)),
arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)), arg3_(static_cast<Arg3&&>(other.arg3_)),
arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_)) arg4_(static_cast<Arg4&&>(other.arg4_))
{ {
} }
#endif // defined(ASIO_HAS_MOVE)
void operator()() void operator()()
{ {
handler_(static_cast<const Arg1&>(arg1_), static_cast<Handler&&>(handler_)(
static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_), static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_),
static_cast<const Arg4&>(arg4_)); static_cast<const Arg4&>(arg4_));
} }
@@ -399,24 +351,6 @@ public:
Arg4 arg4_; Arg4 arg4_;
}; };
template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void* asio_handler_allocate(std::size_t size,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}
template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}
template <typename Handler, typename Arg1, template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4> typename Arg2, typename Arg3, typename Arg4>
inline bool asio_handler_is_continuation( inline bool asio_handler_is_continuation(
@@ -426,32 +360,14 @@ inline bool asio_handler_is_continuation(
this_handler->handler_); this_handler->handler_);
} }
template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void asio_handler_invoke(Function& function,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void asio_handler_invoke(const Function& function,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Handler, typename Arg1, template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4> typename Arg2, typename Arg3, typename Arg4>
inline binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4> inline binder4<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4>
bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, bind_handler(Handler&& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
{ {
return binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>(0, return binder4<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4>(0,
ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4); static_cast<Handler&&>(handler), arg1, arg2, arg3, arg4);
} }
template <typename Handler, typename Arg1, typename Arg2, template <typename Handler, typename Arg1, typename Arg2,
@@ -460,9 +376,9 @@ class binder5
{ {
public: public:
template <typename T> template <typename T>
binder5(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1, binder5(int, T&& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
: handler_(ASIO_MOVE_CAST(T)(handler)), : handler_(static_cast<T&&>(handler)),
arg1_(arg1), arg1_(arg1),
arg2_(arg2), arg2_(arg2),
arg3_(arg3), arg3_(arg3),
@@ -473,7 +389,7 @@ public:
binder5(Handler& handler, const Arg1& arg1, const Arg2& arg2, binder5(Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
: handler_(ASIO_MOVE_CAST(Handler)(handler)), : handler_(static_cast<Handler&&>(handler)),
arg1_(arg1), arg1_(arg1),
arg2_(arg2), arg2_(arg2),
arg3_(arg3), arg3_(arg3),
@@ -482,7 +398,6 @@ public:
{ {
} }
#if defined(ASIO_HAS_MOVE)
binder5(const binder5& other) binder5(const binder5& other)
: handler_(other.handler_), : handler_(other.handler_),
arg1_(other.arg1_), arg1_(other.arg1_),
@@ -494,21 +409,23 @@ public:
} }
binder5(binder5&& other) binder5(binder5&& other)
: handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), : handler_(static_cast<Handler&&>(other.handler_)),
arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), arg1_(static_cast<Arg1&&>(other.arg1_)),
arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)), arg2_(static_cast<Arg2&&>(other.arg2_)),
arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)), arg3_(static_cast<Arg3&&>(other.arg3_)),
arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_)), arg4_(static_cast<Arg4&&>(other.arg4_)),
arg5_(ASIO_MOVE_CAST(Arg5)(other.arg5_)) arg5_(static_cast<Arg5&&>(other.arg5_))
{ {
} }
#endif // defined(ASIO_HAS_MOVE)
void operator()() void operator()()
{ {
handler_(static_cast<const Arg1&>(arg1_), static_cast<Handler&&>(handler_)(
static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_), static_cast<const Arg1&>(arg1_),
static_cast<const Arg4&>(arg4_), static_cast<const Arg5&>(arg5_)); static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_),
static_cast<const Arg4&>(arg4_),
static_cast<const Arg5&>(arg5_));
} }
void operator()() const void operator()() const
@@ -525,24 +442,6 @@ public:
Arg5 arg5_; Arg5 arg5_;
}; };
template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
inline void* asio_handler_allocate(std::size_t size,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5> typename Arg3, typename Arg4, typename Arg5>
inline bool asio_handler_is_continuation( inline bool asio_handler_is_continuation(
@@ -552,56 +451,37 @@ inline bool asio_handler_is_continuation(
this_handler->handler_); this_handler->handler_);
} }
template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4, typename Arg5>
inline void asio_handler_invoke(Function& function,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4, typename Arg5>
inline void asio_handler_invoke(const Function& function,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5> typename Arg3, typename Arg4, typename Arg5>
inline binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5> inline binder5<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4, Arg5>
bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, bind_handler(Handler&& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
{ {
return binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5>(0, return binder5<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4, Arg5>(0,
ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4, arg5); static_cast<Handler&&>(handler), arg1, arg2, arg3, arg4, arg5);
} }
#if defined(ASIO_HAS_MOVE)
template <typename Handler, typename Arg1> template <typename Handler, typename Arg1>
class move_binder1 class move_binder1
{ {
public: public:
move_binder1(int, ASIO_MOVE_ARG(Handler) handler, move_binder1(int, Handler&& handler,
ASIO_MOVE_ARG(Arg1) arg1) Arg1&& arg1)
: handler_(ASIO_MOVE_CAST(Handler)(handler)), : handler_(static_cast<Handler&&>(handler)),
arg1_(ASIO_MOVE_CAST(Arg1)(arg1)) arg1_(static_cast<Arg1&&>(arg1))
{ {
} }
move_binder1(move_binder1&& other) move_binder1(move_binder1&& other)
: handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), : handler_(static_cast<Handler&&>(other.handler_)),
arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)) arg1_(static_cast<Arg1&&>(other.arg1_))
{ {
} }
void operator()() void operator()()
{ {
handler_(ASIO_MOVE_CAST(Arg1)(arg1_)); static_cast<Handler&&>(handler_)(
static_cast<Arg1&&>(arg1_));
} }
//private: //private:
@@ -609,22 +489,6 @@ public:
Arg1 arg1_; Arg1 arg1_;
}; };
template <typename Handler, typename Arg1>
inline void* asio_handler_allocate(std::size_t size,
move_binder1<Handler, Arg1>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}
template <typename Handler, typename Arg1>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
move_binder1<Handler, Arg1>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}
template <typename Handler, typename Arg1> template <typename Handler, typename Arg1>
inline bool asio_handler_is_continuation( inline bool asio_handler_is_continuation(
move_binder1<Handler, Arg1>* this_handler) move_binder1<Handler, Arg1>* this_handler)
@@ -633,37 +497,30 @@ inline bool asio_handler_is_continuation(
this_handler->handler_); this_handler->handler_);
} }
template <typename Function, typename Handler, typename Arg1>
inline void asio_handler_invoke(ASIO_MOVE_ARG(Function) function,
move_binder1<Handler, Arg1>* this_handler)
{
asio_handler_invoke_helpers::invoke(
ASIO_MOVE_CAST(Function)(function), this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2> template <typename Handler, typename Arg1, typename Arg2>
class move_binder2 class move_binder2
{ {
public: public:
move_binder2(int, ASIO_MOVE_ARG(Handler) handler, move_binder2(int, Handler&& handler,
const Arg1& arg1, ASIO_MOVE_ARG(Arg2) arg2) const Arg1& arg1, Arg2&& arg2)
: handler_(ASIO_MOVE_CAST(Handler)(handler)), : handler_(static_cast<Handler&&>(handler)),
arg1_(arg1), arg1_(arg1),
arg2_(ASIO_MOVE_CAST(Arg2)(arg2)) arg2_(static_cast<Arg2&&>(arg2))
{ {
} }
move_binder2(move_binder2&& other) move_binder2(move_binder2&& other)
: handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), : handler_(static_cast<Handler&&>(other.handler_)),
arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), arg1_(static_cast<Arg1&&>(other.arg1_)),
arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)) arg2_(static_cast<Arg2&&>(other.arg2_))
{ {
} }
void operator()() void operator()()
{ {
handler_(static_cast<const Arg1&>(arg1_), static_cast<Handler&&>(handler_)(
ASIO_MOVE_CAST(Arg2)(arg2_)); static_cast<const Arg1&>(arg1_),
static_cast<Arg2&&>(arg2_));
} }
//private: //private:
@@ -672,22 +529,6 @@ public:
Arg2 arg2_; Arg2 arg2_;
}; };
template <typename Handler, typename Arg1, typename Arg2>
inline void* asio_handler_allocate(std::size_t size,
move_binder2<Handler, Arg1, Arg2>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
move_binder2<Handler, Arg1, Arg2>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2> template <typename Handler, typename Arg1, typename Arg2>
inline bool asio_handler_is_continuation( inline bool asio_handler_is_continuation(
move_binder2<Handler, Arg1, Arg2>* this_handler) move_binder2<Handler, Arg1, Arg2>* this_handler)
@@ -696,119 +537,173 @@ inline bool asio_handler_is_continuation(
this_handler->handler_); this_handler->handler_);
} }
template <typename Function, typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_invoke(ASIO_MOVE_ARG(Function) function,
move_binder2<Handler, Arg1, Arg2>* this_handler)
{
asio_handler_invoke_helpers::invoke(
ASIO_MOVE_CAST(Function)(function), this_handler->handler_);
}
#endif // defined(ASIO_HAS_MOVE)
} // namespace detail } // namespace detail
template <typename Handler, typename Arg1, typename Allocator> template <template <typename, typename> class Associator,
struct associated_allocator<detail::binder1<Handler, Arg1>, Allocator> typename Handler, typename DefaultCandidate>
struct associator<Associator,
detail::binder0<Handler>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{ {
typedef typename associated_allocator<Handler, Allocator>::type type; static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder0<Handler>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static type get(const detail::binder1<Handler, Arg1>& h, static auto get(const detail::binder0<Handler>& h,
const Allocator& a = Allocator()) ASIO_NOEXCEPT const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{ {
return associated_allocator<Handler, Allocator>::get(h.handler_, a); return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
} }
}; };
template <typename Handler, typename Arg1, typename Arg2, typename Allocator> template <template <typename, typename> class Associator,
struct associated_allocator<detail::binder2<Handler, Arg1, Arg2>, Allocator> typename Handler, typename Arg1, typename DefaultCandidate>
struct associator<Associator,
detail::binder1<Handler, Arg1>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{ {
typedef typename associated_allocator<Handler, Allocator>::type type; static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder1<Handler, Arg1>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static type get(const detail::binder2<Handler, Arg1, Arg2>& h, static auto get(const detail::binder1<Handler, Arg1>& h,
const Allocator& a = Allocator()) ASIO_NOEXCEPT const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{ {
return associated_allocator<Handler, Allocator>::get(h.handler_, a); return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
} }
}; };
template <typename Handler, typename Arg1, typename Executor> template <template <typename, typename> class Associator,
struct associated_executor<detail::binder1<Handler, Arg1>, Executor> typename Handler, typename Arg1, typename Arg2,
typename DefaultCandidate>
struct associator<Associator,
detail::binder2<Handler, Arg1, Arg2>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{ {
typedef typename associated_executor<Handler, Executor>::type type; static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder2<Handler, Arg1, Arg2>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static type get(const detail::binder1<Handler, Arg1>& h, static auto get(const detail::binder2<Handler, Arg1, Arg2>& h,
const Executor& ex = Executor()) ASIO_NOEXCEPT const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{ {
return associated_executor<Handler, Executor>::get(h.handler_, ex); return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
} }
}; };
template <typename Handler, typename Arg1, typename Arg2, typename Executor> template <template <typename, typename> class Associator,
struct associated_executor<detail::binder2<Handler, Arg1, Arg2>, Executor> typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename DefaultCandidate>
struct associator<Associator,
detail::binder3<Handler, Arg1, Arg2, Arg3>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{ {
typedef typename associated_executor<Handler, Executor>::type type; static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder3<Handler, Arg1, Arg2, Arg3>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static type get(const detail::binder2<Handler, Arg1, Arg2>& h, static auto get(const detail::binder3<Handler, Arg1, Arg2, Arg3>& h,
const Executor& ex = Executor()) ASIO_NOEXCEPT const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{ {
return associated_executor<Handler, Executor>::get(h.handler_, ex); return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
} }
}; };
#if defined(ASIO_HAS_MOVE) template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename Arg2, typename Arg3,
template <typename Handler, typename Arg1, typename Allocator> typename Arg4, typename DefaultCandidate>
struct associated_allocator<detail::move_binder1<Handler, Arg1>, Allocator> struct associator<Associator,
detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{ {
typedef typename associated_allocator<Handler, Allocator>::type type; static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>& h) noexcept
static type get(const detail::move_binder1<Handler, Arg1>& h,
const Allocator& a = Allocator()) ASIO_NOEXCEPT
{ {
return associated_allocator<Handler, Allocator>::get(h.handler_, a); return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
} }
}; };
template <typename Handler, typename Arg1, typename Arg2, typename Allocator> template <template <typename, typename> class Associator,
struct associated_allocator< typename Handler, typename Arg1, typename Arg2, typename Arg3,
detail::move_binder2<Handler, Arg1, Arg2>, Allocator> typename Arg4, typename Arg5, typename DefaultCandidate>
struct associator<Associator,
detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{ {
typedef typename associated_allocator<Handler, Allocator>::type type; static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h, static auto get(
const Allocator& a = Allocator()) ASIO_NOEXCEPT const detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{ {
return associated_allocator<Handler, Allocator>::get(h.handler_, a); return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
} }
}; };
template <typename Handler, typename Arg1, typename Executor> template <template <typename, typename> class Associator,
struct associated_executor<detail::move_binder1<Handler, Arg1>, Executor> typename Handler, typename Arg1, typename DefaultCandidate>
struct associator<Associator,
detail::move_binder1<Handler, Arg1>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{ {
typedef typename associated_executor<Handler, Executor>::type type; static typename Associator<Handler, DefaultCandidate>::type get(
const detail::move_binder1<Handler, Arg1>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static type get(const detail::move_binder1<Handler, Arg1>& h, static auto get(const detail::move_binder1<Handler, Arg1>& h,
const Executor& ex = Executor()) ASIO_NOEXCEPT const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{ {
return associated_executor<Handler, Executor>::get(h.handler_, ex); return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
} }
}; };
template <typename Handler, typename Arg1, typename Arg2, typename Executor> template <template <typename, typename> class Associator,
struct associated_executor<detail::move_binder2<Handler, Arg1, Arg2>, Executor> typename Handler, typename Arg1, typename Arg2, typename DefaultCandidate>
struct associator<Associator,
detail::move_binder2<Handler, Arg1, Arg2>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{ {
typedef typename associated_executor<Handler, Executor>::type type; static typename Associator<Handler, DefaultCandidate>::type get(
const detail::move_binder2<Handler, Arg1, Arg2>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h, static auto get(const detail::move_binder2<Handler, Arg1, Arg2>& h,
const Executor& ex = Executor()) ASIO_NOEXCEPT const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{ {
return associated_executor<Handler, Executor>::get(h.handler_, ex); return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
} }
}; };
#endif // defined(ASIO_HAS_MOVE)
} // namespace asio } // namespace asio
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"

View File

@@ -0,0 +1,107 @@
//
// detail/blocking_executor_op.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 ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP
#define ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/event.hpp"
#include "asio/detail/fenced_block.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/scheduler_operation.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Operation = scheduler_operation>
class blocking_executor_op_base : public Operation
{
public:
blocking_executor_op_base(typename Operation::func_type complete_func)
: Operation(complete_func),
is_complete_(false)
{
}
void wait()
{
asio::detail::mutex::scoped_lock lock(mutex_);
while (!is_complete_)
event_.wait(lock);
}
protected:
struct do_complete_cleanup
{
~do_complete_cleanup()
{
asio::detail::mutex::scoped_lock lock(op_->mutex_);
op_->is_complete_ = true;
op_->event_.unlock_and_signal_one_for_destruction(lock);
}
blocking_executor_op_base* op_;
};
private:
asio::detail::mutex mutex_;
asio::detail::event event_;
bool is_complete_;
};
template <typename Handler, typename Operation = scheduler_operation>
class blocking_executor_op : public blocking_executor_op_base<Operation>
{
public:
blocking_executor_op(Handler& h)
: blocking_executor_op_base<Operation>(&blocking_executor_op::do_complete),
handler_(h)
{
}
static void do_complete(void* owner, Operation* base,
const asio::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
ASIO_ASSUME(base != 0);
blocking_executor_op* o(static_cast<blocking_executor_op*>(base));
typename blocking_executor_op_base<Operation>::do_complete_cleanup
on_exit = { o };
(void)on_exit;
ASIO_HANDLER_COMPLETION((*o));
// Make the upcall if required.
if (owner)
{
fenced_block b(fenced_block::half);
ASIO_HANDLER_INVOCATION_BEGIN(());
static_cast<Handler&&>(o->handler_)();
ASIO_HANDLER_INVOCATION_END;
}
}
private:
Handler& handler_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP

View File

@@ -2,7 +2,7 @@
// detail/buffer_resize_guard.hpp // detail/buffer_resize_guard.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/buffer_sequence_adapter.hpp // detail/buffer_sequence_adapter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -19,6 +19,7 @@
#include "asio/buffer.hpp" #include "asio/buffer.hpp"
#include "asio/detail/array_fwd.hpp" #include "asio/detail/array_fwd.hpp"
#include "asio/detail/socket_types.hpp" #include "asio/detail/socket_types.hpp"
#include "asio/registered_buffer.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
@@ -104,6 +105,9 @@ class buffer_sequence_adapter
: buffer_sequence_adapter_base : buffer_sequence_adapter_base
{ {
public: public:
enum { is_single_buffer = false };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter(const Buffers& buffer_sequence) explicit buffer_sequence_adapter(const Buffers& buffer_sequence)
: count_(0), total_buffer_size_(0) : count_(0), total_buffer_size_(0)
{ {
@@ -127,6 +131,11 @@ public:
return total_buffer_size_; return total_buffer_size_;
} }
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const bool all_empty() const
{ {
return total_buffer_size_ == 0; return total_buffer_size_ == 0;
@@ -153,6 +162,16 @@ public:
asio::buffer_sequence_end(buffer_sequence)); asio::buffer_sequence_end(buffer_sequence));
} }
enum { linearisation_storage_size = 8192 };
static Buffer linearise(const Buffers& buffer_sequence,
const asio::mutable_buffer& storage)
{
return buffer_sequence_adapter::linearise(
asio::buffer_sequence_begin(buffer_sequence),
asio::buffer_sequence_end(buffer_sequence), storage);
}
private: private:
template <typename Iterator> template <typename Iterator>
void init(Iterator begin, Iterator end) void init(Iterator begin, Iterator end)
@@ -201,6 +220,30 @@ private:
return Buffer(); return Buffer();
} }
template <typename Iterator>
static Buffer linearise(Iterator begin, Iterator end,
const asio::mutable_buffer& storage)
{
asio::mutable_buffer unused_storage = storage;
Iterator iter = begin;
while (iter != end && unused_storage.size() != 0)
{
Buffer buffer(*iter);
++iter;
if (buffer.size() == 0)
continue;
if (unused_storage.size() == storage.size())
{
if (iter == end)
return buffer;
if (buffer.size() >= unused_storage.size())
return buffer;
}
unused_storage += asio::buffer_copy(unused_storage, buffer);
}
return Buffer(storage.data(), storage.size() - unused_storage.size());
}
native_buffer_type buffers_[max_buffers]; native_buffer_type buffers_[max_buffers];
std::size_t count_; std::size_t count_;
std::size_t total_buffer_size_; std::size_t total_buffer_size_;
@@ -211,6 +254,9 @@ class buffer_sequence_adapter<Buffer, asio::mutable_buffer>
: buffer_sequence_adapter_base : buffer_sequence_adapter_base
{ {
public: public:
enum { is_single_buffer = true };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter( explicit buffer_sequence_adapter(
const asio::mutable_buffer& buffer_sequence) const asio::mutable_buffer& buffer_sequence)
{ {
@@ -233,6 +279,11 @@ public:
return total_buffer_size_; return total_buffer_size_;
} }
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const bool all_empty() const
{ {
return total_buffer_size_ == 0; return total_buffer_size_ == 0;
@@ -253,6 +304,14 @@ public:
return Buffer(buffer_sequence); return Buffer(buffer_sequence);
} }
enum { linearisation_storage_size = 1 };
static Buffer linearise(const asio::mutable_buffer& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence);
}
private: private:
native_buffer_type buffer_; native_buffer_type buffer_;
std::size_t total_buffer_size_; std::size_t total_buffer_size_;
@@ -263,6 +322,9 @@ class buffer_sequence_adapter<Buffer, asio::const_buffer>
: buffer_sequence_adapter_base : buffer_sequence_adapter_base
{ {
public: public:
enum { is_single_buffer = true };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter( explicit buffer_sequence_adapter(
const asio::const_buffer& buffer_sequence) const asio::const_buffer& buffer_sequence)
{ {
@@ -285,6 +347,11 @@ public:
return total_buffer_size_; return total_buffer_size_;
} }
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const bool all_empty() const
{ {
return total_buffer_size_ == 0; return total_buffer_size_ == 0;
@@ -305,6 +372,14 @@ public:
return Buffer(buffer_sequence); return Buffer(buffer_sequence);
} }
enum { linearisation_storage_size = 1 };
static Buffer linearise(const asio::const_buffer& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence);
}
private: private:
native_buffer_type buffer_; native_buffer_type buffer_;
std::size_t total_buffer_size_; std::size_t total_buffer_size_;
@@ -317,6 +392,9 @@ class buffer_sequence_adapter<Buffer, asio::mutable_buffers_1>
: buffer_sequence_adapter_base : buffer_sequence_adapter_base
{ {
public: public:
enum { is_single_buffer = true };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter( explicit buffer_sequence_adapter(
const asio::mutable_buffers_1& buffer_sequence) const asio::mutable_buffers_1& buffer_sequence)
{ {
@@ -339,6 +417,11 @@ public:
return total_buffer_size_; return total_buffer_size_;
} }
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const bool all_empty() const
{ {
return total_buffer_size_ == 0; return total_buffer_size_ == 0;
@@ -359,6 +442,14 @@ public:
return Buffer(buffer_sequence); return Buffer(buffer_sequence);
} }
enum { linearisation_storage_size = 1 };
static Buffer linearise(const asio::mutable_buffers_1& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence);
}
private: private:
native_buffer_type buffer_; native_buffer_type buffer_;
std::size_t total_buffer_size_; std::size_t total_buffer_size_;
@@ -369,6 +460,9 @@ class buffer_sequence_adapter<Buffer, asio::const_buffers_1>
: buffer_sequence_adapter_base : buffer_sequence_adapter_base
{ {
public: public:
enum { is_single_buffer = true };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter( explicit buffer_sequence_adapter(
const asio::const_buffers_1& buffer_sequence) const asio::const_buffers_1& buffer_sequence)
{ {
@@ -391,6 +485,11 @@ public:
return total_buffer_size_; return total_buffer_size_;
} }
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const bool all_empty() const
{ {
return total_buffer_size_ == 0; return total_buffer_size_ == 0;
@@ -411,6 +510,14 @@ public:
return Buffer(buffer_sequence); return Buffer(buffer_sequence);
} }
enum { linearisation_storage_size = 1 };
static Buffer linearise(const asio::const_buffers_1& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence);
}
private: private:
native_buffer_type buffer_; native_buffer_type buffer_;
std::size_t total_buffer_size_; std::size_t total_buffer_size_;
@@ -418,11 +525,162 @@ private:
#endif // !defined(ASIO_NO_DEPRECATED) #endif // !defined(ASIO_NO_DEPRECATED)
template <typename Buffer>
class buffer_sequence_adapter<Buffer, asio::mutable_registered_buffer>
: buffer_sequence_adapter_base
{
public:
enum { is_single_buffer = true };
enum { is_registered_buffer = true };
explicit buffer_sequence_adapter(
const asio::mutable_registered_buffer& buffer_sequence)
{
init_native_buffer(buffer_, buffer_sequence.buffer());
total_buffer_size_ = buffer_sequence.size();
registered_id_ = buffer_sequence.id();
}
native_buffer_type* buffers()
{
return &buffer_;
}
std::size_t count() const
{
return 1;
}
std::size_t total_size() const
{
return total_buffer_size_;
}
registered_buffer_id registered_id() const
{
return registered_id_;
}
bool all_empty() const
{
return total_buffer_size_ == 0;
}
static bool all_empty(
const asio::mutable_registered_buffer& buffer_sequence)
{
return buffer_sequence.size() == 0;
}
static void validate(
const asio::mutable_registered_buffer& buffer_sequence)
{
buffer_sequence.data();
}
static Buffer first(
const asio::mutable_registered_buffer& buffer_sequence)
{
return Buffer(buffer_sequence.buffer());
}
enum { linearisation_storage_size = 1 };
static Buffer linearise(
const asio::mutable_registered_buffer& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence.buffer());
}
private:
native_buffer_type buffer_;
std::size_t total_buffer_size_;
registered_buffer_id registered_id_;
};
template <typename Buffer>
class buffer_sequence_adapter<Buffer, asio::const_registered_buffer>
: buffer_sequence_adapter_base
{
public:
enum { is_single_buffer = true };
enum { is_registered_buffer = true };
explicit buffer_sequence_adapter(
const asio::const_registered_buffer& buffer_sequence)
{
init_native_buffer(buffer_, buffer_sequence.buffer());
total_buffer_size_ = buffer_sequence.size();
registered_id_ = buffer_sequence.id();
}
native_buffer_type* buffers()
{
return &buffer_;
}
std::size_t count() const
{
return 1;
}
std::size_t total_size() const
{
return total_buffer_size_;
}
registered_buffer_id registered_id() const
{
return registered_id_;
}
bool all_empty() const
{
return total_buffer_size_ == 0;
}
static bool all_empty(
const asio::const_registered_buffer& buffer_sequence)
{
return buffer_sequence.size() == 0;
}
static void validate(
const asio::const_registered_buffer& buffer_sequence)
{
buffer_sequence.data();
}
static Buffer first(
const asio::const_registered_buffer& buffer_sequence)
{
return Buffer(buffer_sequence.buffer());
}
enum { linearisation_storage_size = 1 };
static Buffer linearise(
const asio::const_registered_buffer& buffer_sequence,
const Buffer&)
{
return Buffer(buffer_sequence.buffer());
}
private:
native_buffer_type buffer_;
std::size_t total_buffer_size_;
registered_buffer_id registered_id_;
};
template <typename Buffer, typename Elem> template <typename Buffer, typename Elem>
class buffer_sequence_adapter<Buffer, boost::array<Elem, 2>> class buffer_sequence_adapter<Buffer, boost::array<Elem, 2>>
: buffer_sequence_adapter_base : buffer_sequence_adapter_base
{ {
public: public:
enum { is_single_buffer = false };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter( explicit buffer_sequence_adapter(
const boost::array<Elem, 2>& buffer_sequence) const boost::array<Elem, 2>& buffer_sequence)
{ {
@@ -446,6 +704,11 @@ public:
return total_buffer_size_; return total_buffer_size_;
} }
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const bool all_empty() const
{ {
return total_buffer_size_ == 0; return total_buffer_size_ == 0;
@@ -468,18 +731,32 @@ public:
? buffer_sequence[0] : buffer_sequence[1]); ? buffer_sequence[0] : buffer_sequence[1]);
} }
enum { linearisation_storage_size = 8192 };
static Buffer linearise(const boost::array<Elem, 2>& buffer_sequence,
const asio::mutable_buffer& storage)
{
if (buffer_sequence[0].size() == 0)
return Buffer(buffer_sequence[1]);
if (buffer_sequence[1].size() == 0)
return Buffer(buffer_sequence[0]);
return Buffer(storage.data(),
asio::buffer_copy(storage, buffer_sequence));
}
private: private:
native_buffer_type buffers_[2]; native_buffer_type buffers_[2];
std::size_t total_buffer_size_; std::size_t total_buffer_size_;
}; };
#if defined(ASIO_HAS_STD_ARRAY)
template <typename Buffer, typename Elem> template <typename Buffer, typename Elem>
class buffer_sequence_adapter<Buffer, std::array<Elem, 2>> class buffer_sequence_adapter<Buffer, std::array<Elem, 2>>
: buffer_sequence_adapter_base : buffer_sequence_adapter_base
{ {
public: public:
enum { is_single_buffer = false };
enum { is_registered_buffer = false };
explicit buffer_sequence_adapter( explicit buffer_sequence_adapter(
const std::array<Elem, 2>& buffer_sequence) const std::array<Elem, 2>& buffer_sequence)
{ {
@@ -503,6 +780,11 @@ public:
return total_buffer_size_; return total_buffer_size_;
} }
registered_buffer_id registered_id() const
{
return registered_buffer_id();
}
bool all_empty() const bool all_empty() const
{ {
return total_buffer_size_ == 0; return total_buffer_size_ == 0;
@@ -525,13 +807,24 @@ public:
? buffer_sequence[0] : buffer_sequence[1]); ? buffer_sequence[0] : buffer_sequence[1]);
} }
enum { linearisation_storage_size = 8192 };
static Buffer linearise(const std::array<Elem, 2>& buffer_sequence,
const asio::mutable_buffer& storage)
{
if (buffer_sequence[0].size() == 0)
return Buffer(buffer_sequence[1]);
if (buffer_sequence[1].size() == 0)
return Buffer(buffer_sequence[0]);
return Buffer(storage.data(),
asio::buffer_copy(storage, buffer_sequence));
}
private: private:
native_buffer_type buffers_[2]; native_buffer_type buffers_[2];
std::size_t total_buffer_size_; std::size_t total_buffer_size_;
}; };
#endif // defined(ASIO_HAS_STD_ARRAY)
} // namespace detail } // namespace detail
} // namespace asio } // namespace asio

View File

@@ -2,7 +2,7 @@
// detail/buffered_stream_storage.hpp // detail/buffered_stream_storage.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/call_stack.hpp // detail/call_stack.hpp
// ~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/chrono.hpp // detail/chrono.hpp
// ~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,17 +16,11 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#if defined(ASIO_HAS_STD_CHRONO)
#include <chrono> #include <chrono>
#elif defined(ASIO_HAS_BOOST_CHRONO)
# include <boost/chrono/system_clocks.hpp>
#endif // defined(ASIO_HAS_BOOST_CHRONO)
namespace asio { namespace asio {
namespace chrono { namespace chrono {
#if defined(ASIO_HAS_STD_CHRONO)
using std::chrono::duration; using std::chrono::duration;
using std::chrono::time_point; using std::chrono::time_point;
using std::chrono::duration_cast; using std::chrono::duration_cast;
@@ -44,21 +38,6 @@ using std::chrono::steady_clock;
#endif // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) #endif // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
using std::chrono::system_clock; using std::chrono::system_clock;
using std::chrono::high_resolution_clock; using std::chrono::high_resolution_clock;
#elif defined(ASIO_HAS_BOOST_CHRONO)
using boost::chrono::duration;
using boost::chrono::time_point;
using boost::chrono::duration_cast;
using boost::chrono::nanoseconds;
using boost::chrono::microseconds;
using boost::chrono::milliseconds;
using boost::chrono::seconds;
using boost::chrono::minutes;
using boost::chrono::hours;
using boost::chrono::time_point_cast;
using boost::chrono::system_clock;
using boost::chrono::steady_clock;
using boost::chrono::high_resolution_clock;
#endif // defined(ASIO_HAS_BOOST_CHRONO)
} // namespace chrono } // namespace chrono
} // namespace asio } // namespace asio

View File

@@ -2,7 +2,7 @@
// detail/chrono_time_traits.hpp // detail/chrono_time_traits.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/completion_handler.hpp // detail/completion_handler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -27,17 +27,17 @@
namespace asio { namespace asio {
namespace detail { namespace detail {
template <typename Handler> template <typename Handler, typename IoExecutor>
class completion_handler : public operation class completion_handler : public operation
{ {
public: public:
ASIO_DEFINE_HANDLER_PTR(completion_handler); ASIO_DEFINE_HANDLER_PTR(completion_handler);
completion_handler(Handler& h) completion_handler(Handler& h, const IoExecutor& io_ex)
: operation(&completion_handler::do_complete), : operation(&completion_handler::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(h)) handler_(static_cast<Handler&&>(h)),
work_(handler_, io_ex)
{ {
handler_work<Handler>::start(handler_);
} }
static void do_complete(void* owner, operation* base, static void do_complete(void* owner, operation* base,
@@ -47,17 +47,21 @@ public:
// Take ownership of the handler object. // Take ownership of the handler object.
completion_handler* h(static_cast<completion_handler*>(base)); completion_handler* h(static_cast<completion_handler*>(base));
ptr p = { asio::detail::addressof(h->handler_), h, h }; ptr p = { asio::detail::addressof(h->handler_), h, h };
handler_work<Handler> w(h->handler_);
ASIO_HANDLER_COMPLETION((*h)); ASIO_HANDLER_COMPLETION((*h));
// Take ownership of the operation's outstanding work.
handler_work<Handler, IoExecutor> w(
static_cast<handler_work<Handler, IoExecutor>&&>(
h->work_));
// Make a copy of the handler so that the memory can be deallocated before // Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a // the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated // sub-object of the handler may be the true owner of the memory associated
// with the handler. Consequently, a local copy of the handler is required // with the handler. Consequently, a local copy of the handler is required
// to ensure that any owning sub-object remains valid until after we have // to ensure that any owning sub-object remains valid until after we have
// deallocated the memory here. // deallocated the memory here.
Handler handler(ASIO_MOVE_CAST(Handler)(h->handler_)); Handler handler(static_cast<Handler&&>(h->handler_));
p.h = asio::detail::addressof(handler); p.h = asio::detail::addressof(handler);
p.reset(); p.reset();
@@ -73,6 +77,7 @@ public:
private: private:
Handler handler_; Handler handler_;
handler_work<Handler, IoExecutor> work_;
}; };
} // namespace detail } // namespace detail

View File

@@ -0,0 +1,252 @@
//
// detail/composed_work.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 ASIO_DETAIL_COMPOSED_WORK_HPP
#define ASIO_DETAIL_COMPOSED_WORK_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/execution/executor.hpp"
#include "asio/execution/outstanding_work.hpp"
#include "asio/executor_work_guard.hpp"
#include "asio/is_executor.hpp"
#include "asio/system_executor.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Executor, typename = void>
class composed_work_guard
{
public:
typedef decay_t<
prefer_result_t<Executor, execution::outstanding_work_t::tracked_t>
> executor_type;
composed_work_guard(const Executor& ex)
: executor_(asio::prefer(ex, execution::outstanding_work.tracked))
{
}
void reset()
{
}
executor_type get_executor() const noexcept
{
return executor_;
}
private:
executor_type executor_;
};
template <>
struct composed_work_guard<system_executor>
{
public:
typedef system_executor executor_type;
composed_work_guard(const system_executor&)
{
}
void reset()
{
}
executor_type get_executor() const noexcept
{
return system_executor();
}
};
#if !defined(ASIO_NO_TS_EXECUTORS)
template <typename Executor>
struct composed_work_guard<Executor,
enable_if_t<
!execution::is_executor<Executor>::value
>
> : executor_work_guard<Executor>
{
composed_work_guard(const Executor& ex)
: executor_work_guard<Executor>(ex)
{
}
};
#endif // !defined(ASIO_NO_TS_EXECUTORS)
template <typename>
struct composed_io_executors;
template <>
struct composed_io_executors<void()>
{
composed_io_executors() noexcept
: head_(system_executor())
{
}
typedef system_executor head_type;
system_executor head_;
};
inline composed_io_executors<void()> make_composed_io_executors()
{
return composed_io_executors<void()>();
}
template <typename Head>
struct composed_io_executors<void(Head)>
{
explicit composed_io_executors(const Head& ex) noexcept
: head_(ex)
{
}
typedef Head head_type;
Head head_;
};
template <typename Head>
inline composed_io_executors<void(Head)>
make_composed_io_executors(const Head& head)
{
return composed_io_executors<void(Head)>(head);
}
template <typename Head, typename... Tail>
struct composed_io_executors<void(Head, Tail...)>
{
explicit composed_io_executors(const Head& head,
const Tail&... tail) noexcept
: head_(head),
tail_(tail...)
{
}
void reset()
{
head_.reset();
tail_.reset();
}
typedef Head head_type;
Head head_;
composed_io_executors<void(Tail...)> tail_;
};
template <typename Head, typename... Tail>
inline composed_io_executors<void(Head, Tail...)>
make_composed_io_executors(const Head& head, const Tail&... tail)
{
return composed_io_executors<void(Head, Tail...)>(head, tail...);
}
template <typename>
struct composed_work;
template <>
struct composed_work<void()>
{
typedef composed_io_executors<void()> executors_type;
composed_work(const executors_type&) noexcept
: head_(system_executor())
{
}
void reset()
{
head_.reset();
}
typedef system_executor head_type;
composed_work_guard<system_executor> head_;
};
template <typename Head>
struct composed_work<void(Head)>
{
typedef composed_io_executors<void(Head)> executors_type;
explicit composed_work(const executors_type& ex) noexcept
: head_(ex.head_)
{
}
void reset()
{
head_.reset();
}
typedef Head head_type;
composed_work_guard<Head> head_;
};
template <typename Head, typename... Tail>
struct composed_work<void(Head, Tail...)>
{
typedef composed_io_executors<void(Head, Tail...)> executors_type;
explicit composed_work(const executors_type& ex) noexcept
: head_(ex.head_),
tail_(ex.tail_)
{
}
void reset()
{
head_.reset();
tail_.reset();
}
typedef Head head_type;
composed_work_guard<Head> head_;
composed_work<void(Tail...)> tail_;
};
template <typename IoObject>
inline typename IoObject::executor_type
get_composed_io_executor(IoObject& io_object,
enable_if_t<
!is_executor<IoObject>::value
>* = 0,
enable_if_t<
!execution::is_executor<IoObject>::value
>* = 0)
{
return io_object.get_executor();
}
template <typename Executor>
inline const Executor& get_composed_io_executor(const Executor& ex,
enable_if_t<
is_executor<Executor>::value
|| execution::is_executor<Executor>::value
>* = 0)
{
return ex;
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_COMPOSED_WORK_HPP

View File

@@ -2,7 +2,7 @@
// detail/concurrency_hint.hpp // detail/concurrency_hint.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/conditionally_enabled_event.hpp // detail/conditionally_enabled_event.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -64,6 +64,14 @@ public:
event_.unlock_and_signal_one(lock); event_.unlock_and_signal_one(lock);
} }
// Unlock the mutex and signal one waiter who may destroy us.
void unlock_and_signal_one_for_destruction(
conditionally_enabled_mutex::scoped_lock& lock)
{
if (lock.mutex_.enabled_)
event_.unlock_and_signal_one(lock);
}
// If there's a waiter, unlock the mutex and signal it. // If there's a waiter, unlock the mutex and signal it.
bool maybe_unlock_and_signal_one( bool maybe_unlock_and_signal_one(
conditionally_enabled_mutex::scoped_lock& lock) conditionally_enabled_mutex::scoped_lock& lock)

View File

@@ -2,7 +2,7 @@
// detail/conditionally_enabled_mutex.hpp // detail/conditionally_enabled_mutex.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
// detail/consuming_buffers.hpp // detail/consuming_buffers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -20,6 +20,7 @@
#include "asio/buffer.hpp" #include "asio/buffer.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/limits.hpp" #include "asio/detail/limits.hpp"
#include "asio/registered_buffer.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
@@ -39,16 +40,12 @@ struct prepared_buffers_max<boost::array<Elem, N> >
enum { value = N }; enum { value = N };
}; };
#if defined(ASIO_HAS_STD_ARRAY)
template <typename Elem, std::size_t N> template <typename Elem, std::size_t N>
struct prepared_buffers_max<std::array<Elem, N>> struct prepared_buffers_max<std::array<Elem, N>>
{ {
enum { value = N }; enum { value = N };
}; };
#endif // defined(ASIO_HAS_STD_ARRAY)
// A buffer sequence used to represent a subsequence of the buffers. // A buffer sequence used to represent a subsequence of the buffers.
template <typename Buffer, std::size_t MaxBuffers> template <typename Buffer, std::size_t MaxBuffers>
struct prepared_buffers struct prepared_buffers
@@ -269,6 +266,42 @@ public:
#endif // !defined(ASIO_NO_DEPRECATED) #endif // !defined(ASIO_NO_DEPRECATED)
template <>
class consuming_buffers<mutable_buffer,
mutable_registered_buffer, const mutable_buffer*>
: public consuming_single_buffer<mutable_registered_buffer>
{
public:
explicit consuming_buffers(const mutable_registered_buffer& buffer)
: consuming_single_buffer<mutable_registered_buffer>(buffer)
{
}
};
template <>
class consuming_buffers<const_buffer,
mutable_registered_buffer, const mutable_buffer*>
: public consuming_single_buffer<mutable_registered_buffer>
{
public:
explicit consuming_buffers(const mutable_registered_buffer& buffer)
: consuming_single_buffer<mutable_registered_buffer>(buffer)
{
}
};
template <>
class consuming_buffers<const_buffer,
const_registered_buffer, const const_buffer*>
: public consuming_single_buffer<const_registered_buffer>
{
public:
explicit consuming_buffers(const const_registered_buffer& buffer)
: consuming_single_buffer<const_registered_buffer>(buffer)
{
}
};
template <typename Buffer, typename Elem> template <typename Buffer, typename Elem>
class consuming_buffers<Buffer, boost::array<Elem, 2>, class consuming_buffers<Buffer, boost::array<Elem, 2>,
typename boost::array<Elem, 2>::const_iterator> typename boost::array<Elem, 2>::const_iterator>
@@ -319,8 +352,6 @@ private:
std::size_t total_consumed_; std::size_t total_consumed_;
}; };
#if defined(ASIO_HAS_STD_ARRAY)
template <typename Buffer, typename Elem> template <typename Buffer, typename Elem>
class consuming_buffers<Buffer, std::array<Elem, 2>, class consuming_buffers<Buffer, std::array<Elem, 2>,
typename std::array<Elem, 2>::const_iterator> typename std::array<Elem, 2>::const_iterator>
@@ -371,8 +402,6 @@ private:
std::size_t total_consumed_; std::size_t total_consumed_;
}; };
#endif // defined(ASIO_HAS_STD_ARRAY)
// Specialisation for null_buffers to ensure that the null_buffers type is // Specialisation for null_buffers to ensure that the null_buffers type is
// always passed through to the underlying read or write operation. // always passed through to the underlying read or write operation.
template <typename Buffer> template <typename Buffer>

View File

@@ -2,7 +2,7 @@
// detail/cstddef.hpp // detail/cstddef.hpp
// ~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -20,11 +20,7 @@
namespace asio { namespace asio {
#if defined(ASIO_HAS_NULLPTR)
using std::nullptr_t; using std::nullptr_t;
#else // defined(ASIO_HAS_NULLPTR)
struct nullptr_t {};
#endif // defined(ASIO_HAS_NULLPTR)
} // namespace asio } // namespace asio

View File

@@ -2,7 +2,7 @@
// detail/cstdint.hpp // detail/cstdint.hpp
// ~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,16 +16,10 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#if defined(ASIO_HAS_CSTDINT)
#include <cstdint> #include <cstdint>
#else // defined(ASIO_HAS_CSTDINT)
# include <boost/cstdint.hpp>
#endif // defined(ASIO_HAS_CSTDINT)
namespace asio { namespace asio {
#if defined(ASIO_HAS_CSTDINT)
using std::int16_t; using std::int16_t;
using std::int_least16_t; using std::int_least16_t;
using std::uint16_t; using std::uint16_t;
@@ -38,22 +32,8 @@ using std::int64_t;
using std::int_least64_t; using std::int_least64_t;
using std::uint64_t; using std::uint64_t;
using std::uint_least64_t; using std::uint_least64_t;
using std::uintptr_t;
using std::uintmax_t; using std::uintmax_t;
#else // defined(ASIO_HAS_CSTDINT)
using boost::int16_t;
using boost::int_least16_t;
using boost::uint16_t;
using boost::uint_least16_t;
using boost::int32_t;
using boost::int_least32_t;
using boost::uint32_t;
using boost::uint_least32_t;
using boost::int64_t;
using boost::int_least64_t;
using boost::uint64_t;
using boost::uint_least64_t;
using boost::uintmax_t;
#endif // defined(ASIO_HAS_CSTDINT)
} // namespace asio } // namespace asio

View File

@@ -2,7 +2,7 @@
// detail/date_time_fwd.hpp // detail/date_time_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/deadline_timer_service.hpp // detail/deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -17,8 +17,10 @@
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#include <cstddef> #include <cstddef>
#include "asio/associated_cancellation_slot.hpp"
#include "asio/cancellation_type.hpp"
#include "asio/error.hpp" #include "asio/error.hpp"
#include "asio/io_context.hpp" #include "asio/execution_context.hpp"
#include "asio/detail/bind_handler.hpp" #include "asio/detail/bind_handler.hpp"
#include "asio/detail/fenced_block.hpp" #include "asio/detail/fenced_block.hpp"
#include "asio/detail/memory.hpp" #include "asio/detail/memory.hpp"
@@ -43,7 +45,7 @@ namespace detail {
template <typename Time_Traits> template <typename Time_Traits>
class deadline_timer_service class deadline_timer_service
: public service_base<deadline_timer_service<Time_Traits> > : public execution_context_service_base<deadline_timer_service<Time_Traits>>
{ {
public: public:
// The time type. // The time type.
@@ -63,9 +65,10 @@ public:
}; };
// Constructor. // Constructor.
deadline_timer_service(asio::io_context& io_context) deadline_timer_service(execution_context& context)
: service_base<deadline_timer_service<Time_Traits> >(io_context), : execution_context_service_base<
scheduler_(asio::use_service<timer_scheduler>(io_context)) deadline_timer_service<Time_Traits>>(context),
scheduler_(asio::use_service<timer_scheduler>(context))
{ {
scheduler_.init_task(); scheduler_.init_task();
scheduler_.add_timer_queue(timer_queue_); scheduler_.add_timer_queue(timer_queue_);
@@ -96,7 +99,7 @@ public:
cancel(impl, ec); cancel(impl, ec);
} }
// Move-construct a new serial port implementation. // Move-construct a new timer implementation.
void move_construct(implementation_type& impl, void move_construct(implementation_type& impl,
implementation_type& other_impl) implementation_type& other_impl)
{ {
@@ -109,7 +112,7 @@ public:
other_impl.might_have_pending_waits = false; other_impl.might_have_pending_waits = false;
} }
// Move-assign from another serial port implementation. // Move-assign from another timer implementation.
void move_assign(implementation_type& impl, void move_assign(implementation_type& impl,
deadline_timer_service& other_service, deadline_timer_service& other_service,
implementation_type& other_impl) implementation_type& other_impl)
@@ -128,6 +131,21 @@ public:
other_impl.might_have_pending_waits = false; other_impl.might_have_pending_waits = false;
} }
// Move-construct a new timer implementation.
void converting_move_construct(implementation_type& impl,
deadline_timer_service&, implementation_type& other_impl)
{
move_construct(impl, other_impl);
}
// Move-assign from another timer implementation.
void converting_move_assign(implementation_type& impl,
deadline_timer_service& other_service,
implementation_type& other_impl)
{
move_assign(impl, other_service, other_impl);
}
// Cancel any asynchronous wait operations associated with the timer. // Cancel any asynchronous wait operations associated with the timer.
std::size_t cancel(implementation_type& impl, asio::error_code& ec) std::size_t cancel(implementation_type& impl, asio::error_code& ec)
{ {
@@ -225,14 +243,25 @@ public:
} }
// Start an asynchronous wait on the timer. // Start an asynchronous wait on the timer.
template <typename Handler> template <typename Handler, typename IoExecutor>
void async_wait(implementation_type& impl, Handler& handler) void async_wait(implementation_type& impl,
Handler& handler, const IoExecutor& io_ex)
{ {
associated_cancellation_slot_t<Handler> slot
= asio::get_associated_cancellation_slot(handler);
// Allocate and construct an operation to wrap the handler. // Allocate and construct an operation to wrap the handler.
typedef wait_handler<Handler> op; typedef wait_handler<Handler, IoExecutor> op;
typename op::ptr p = { asio::detail::addressof(handler), typename op::ptr p = { asio::detail::addressof(handler),
op::ptr::allocate(handler), 0 }; op::ptr::allocate(handler), 0 };
p.p = new (p.v) op(handler); p.p = new (p.v) op(handler, io_ex);
// Optionally register for per-operation cancellation.
if (slot.is_connected())
{
p.p->cancellation_key_ =
&slot.template emplace<op_cancellation>(this, &impl.timer_data);
}
impl.might_have_pending_waits = true; impl.might_have_pending_waits = true;
@@ -263,6 +292,34 @@ private:
#endif // defined(ASIO_WINDOWS_RUNTIME) #endif // defined(ASIO_WINDOWS_RUNTIME)
} }
// Helper class used to implement per-operation cancellation.
class op_cancellation
{
public:
op_cancellation(deadline_timer_service* s,
typename timer_queue<Time_Traits>::per_timer_data* p)
: service_(s),
timer_data_(p)
{
}
void operator()(cancellation_type_t type)
{
if (!!(type &
(cancellation_type::terminal
| cancellation_type::partial
| cancellation_type::total)))
{
service_->scheduler_.cancel_timer_by_key(
service_->timer_queue_, timer_data_, this);
}
}
private:
deadline_timer_service* service_;
typename timer_queue<Time_Traits>::per_timer_data* timer_data_;
};
// The queue of timers. // The queue of timers.
timer_queue<Time_Traits> timer_queue_; timer_queue<Time_Traits> timer_queue_;

View File

@@ -2,7 +2,7 @@
// detail/dependent_type.hpp // detail/dependent_type.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// detail/descriptor_ops.hpp // detail/descriptor_ops.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -24,6 +24,7 @@
#include <cstddef> #include <cstddef>
#include "asio/error.hpp" #include "asio/error.hpp"
#include "asio/error_code.hpp" #include "asio/error_code.hpp"
#include "asio/detail/cstdint.hpp"
#include "asio/detail/socket_types.hpp" #include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
@@ -50,18 +51,26 @@ enum
typedef unsigned char state_type; typedef unsigned char state_type;
template <typename ReturnType> inline void get_last_error(
inline ReturnType error_wrapper(ReturnType return_value, asio::error_code& ec, bool is_error_condition)
asio::error_code& ec) {
if (!is_error_condition)
{
asio::error::clear(ec);
}
else
{ {
ec = asio::error_code(errno, ec = asio::error_code(errno,
asio::error::get_system_category()); asio::error::get_system_category());
return return_value; }
} }
ASIO_DECL int open(const char* path, int flags, ASIO_DECL int open(const char* path, int flags,
asio::error_code& ec); asio::error_code& ec);
ASIO_DECL int open(const char* path, int flags, unsigned mode,
asio::error_code& ec);
ASIO_DECL int close(int d, state_type& state, ASIO_DECL int close(int d, state_type& state,
asio::error_code& ec); asio::error_code& ec);
@@ -76,17 +85,66 @@ typedef iovec buf;
ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs, ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs,
std::size_t count, bool all_empty, asio::error_code& ec); std::size_t count, bool all_empty, asio::error_code& ec);
ASIO_DECL std::size_t sync_read1(int d, state_type state, void* data,
std::size_t size, asio::error_code& ec);
ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count, ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count,
asio::error_code& ec, std::size_t& bytes_transferred); asio::error_code& ec, std::size_t& bytes_transferred);
ASIO_DECL bool non_blocking_read1(int d, void* data, std::size_t size,
asio::error_code& ec, std::size_t& bytes_transferred);
ASIO_DECL std::size_t sync_write(int d, state_type state, ASIO_DECL std::size_t sync_write(int d, state_type state,
const buf* bufs, std::size_t count, bool all_empty, const buf* bufs, std::size_t count, bool all_empty,
asio::error_code& ec); asio::error_code& ec);
ASIO_DECL std::size_t sync_write1(int d, state_type state,
const void* data, std::size_t size, asio::error_code& ec);
ASIO_DECL bool non_blocking_write(int d, ASIO_DECL bool non_blocking_write(int d,
const buf* bufs, std::size_t count, const buf* bufs, std::size_t count,
asio::error_code& ec, std::size_t& bytes_transferred); asio::error_code& ec, std::size_t& bytes_transferred);
ASIO_DECL bool non_blocking_write1(int d,
const void* data, std::size_t size,
asio::error_code& ec, std::size_t& bytes_transferred);
#if defined(ASIO_HAS_FILE)
ASIO_DECL std::size_t sync_read_at(int d, state_type state,
uint64_t offset, buf* bufs, std::size_t count, bool all_empty,
asio::error_code& ec);
ASIO_DECL std::size_t sync_read_at1(int d, state_type state,
uint64_t offset, void* data, std::size_t size,
asio::error_code& ec);
ASIO_DECL bool non_blocking_read_at(int d, uint64_t offset,
buf* bufs, std::size_t count, asio::error_code& ec,
std::size_t& bytes_transferred);
ASIO_DECL bool non_blocking_read_at1(int d, uint64_t offset,
void* data, std::size_t size, asio::error_code& ec,
std::size_t& bytes_transferred);
ASIO_DECL std::size_t sync_write_at(int d, state_type state,
uint64_t offset, const buf* bufs, std::size_t count, bool all_empty,
asio::error_code& ec);
ASIO_DECL std::size_t sync_write_at1(int d, state_type state,
uint64_t offset, const void* data, std::size_t size,
asio::error_code& ec);
ASIO_DECL bool non_blocking_write_at(int d,
uint64_t offset, const buf* bufs, std::size_t count,
asio::error_code& ec, std::size_t& bytes_transferred);
ASIO_DECL bool non_blocking_write_at1(int d,
uint64_t offset, const void* data, std::size_t size,
asio::error_code& ec, std::size_t& bytes_transferred);
#endif // defined(ASIO_HAS_FILE)
ASIO_DECL int ioctl(int d, state_type& state, long cmd, ASIO_DECL int ioctl(int d, state_type& state, long cmd,
ioctl_arg_type* arg, asio::error_code& ec); ioctl_arg_type* arg, asio::error_code& ec);

View File

@@ -2,7 +2,7 @@
// detail/descriptor_read_op.hpp // detail/descriptor_read_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -26,6 +26,7 @@
#include "asio/detail/handler_work.hpp" #include "asio/detail/handler_work.hpp"
#include "asio/detail/memory.hpp" #include "asio/detail/memory.hpp"
#include "asio/detail/reactor_op.hpp" #include "asio/detail/reactor_op.hpp"
#include "asio/dispatch.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
@@ -36,9 +37,11 @@ template <typename MutableBufferSequence>
class descriptor_read_op_base : public reactor_op class descriptor_read_op_base : public reactor_op
{ {
public: public:
descriptor_read_op_base(int descriptor, descriptor_read_op_base(const asio::error_code& success_ec,
const MutableBufferSequence& buffers, func_type complete_func) int descriptor, const MutableBufferSequence& buffers,
: reactor_op(&descriptor_read_op_base::do_perform, complete_func), func_type complete_func)
: reactor_op(success_ec,
&descriptor_read_op_base::do_perform, complete_func),
descriptor_(descriptor), descriptor_(descriptor),
buffers_(buffers) buffers_(buffers)
{ {
@@ -46,14 +49,27 @@ public:
static status do_perform(reactor_op* base) static status do_perform(reactor_op* base)
{ {
ASIO_ASSUME(base != 0);
descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base)); descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base));
buffer_sequence_adapter<asio::mutable_buffer, typedef buffer_sequence_adapter<asio::mutable_buffer,
MutableBufferSequence> bufs(o->buffers_); MutableBufferSequence> bufs_type;
status result = descriptor_ops::non_blocking_read(o->descriptor_, status result;
if (bufs_type::is_single_buffer)
{
result = descriptor_ops::non_blocking_read1(o->descriptor_,
bufs_type::first(o->buffers_).data(),
bufs_type::first(o->buffers_).size(),
o->ec_, o->bytes_transferred_) ? done : not_done;
}
else
{
bufs_type bufs(o->buffers_);
result = descriptor_ops::non_blocking_read(o->descriptor_,
bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
? done : not_done; ? done : not_done;
}
ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read", ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read",
o->ec_, o->bytes_transferred_)); o->ec_, o->bytes_transferred_));
@@ -66,20 +82,24 @@ private:
MutableBufferSequence buffers_; MutableBufferSequence buffers_;
}; };
template <typename MutableBufferSequence, typename Handler> template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
class descriptor_read_op class descriptor_read_op
: public descriptor_read_op_base<MutableBufferSequence> : public descriptor_read_op_base<MutableBufferSequence>
{ {
public: public:
typedef Handler handler_type;
typedef IoExecutor io_executor_type;
ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); ASIO_DEFINE_HANDLER_PTR(descriptor_read_op);
descriptor_read_op(int descriptor, descriptor_read_op(const asio::error_code& success_ec,
const MutableBufferSequence& buffers, Handler& handler) int descriptor, const MutableBufferSequence& buffers,
: descriptor_read_op_base<MutableBufferSequence>( Handler& handler, const IoExecutor& io_ex)
: descriptor_read_op_base<MutableBufferSequence>(success_ec,
descriptor, buffers, &descriptor_read_op::do_complete), descriptor, buffers, &descriptor_read_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler)) handler_(static_cast<Handler&&>(handler)),
work_(handler_, io_ex)
{ {
handler_work<Handler>::start(handler_);
} }
static void do_complete(void* owner, operation* base, static void do_complete(void* owner, operation* base,
@@ -87,12 +107,19 @@ public:
std::size_t /*bytes_transferred*/) std::size_t /*bytes_transferred*/)
{ {
// Take ownership of the handler object. // Take ownership of the handler object.
ASIO_ASSUME(base != 0);
descriptor_read_op* o(static_cast<descriptor_read_op*>(base)); descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o }; ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
ASIO_HANDLER_COMPLETION((*o)); ASIO_HANDLER_COMPLETION((*o));
// Take ownership of the operation's outstanding work.
handler_work<Handler, IoExecutor> w(
static_cast<handler_work<Handler, IoExecutor>&&>(
o->work_));
ASIO_ERROR_LOCATION(o->ec_);
// Make a copy of the handler so that the memory can be deallocated before // Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a // the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated // sub-object of the handler may be the true owner of the memory associated
@@ -114,8 +141,41 @@ public:
} }
} }
static void do_immediate(operation* base, bool, const void* io_ex)
{
// Take ownership of the handler object.
ASIO_ASSUME(base != 0);
descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
ASIO_HANDLER_COMPLETION((*o));
// Take ownership of the operation's outstanding work.
immediate_handler_work<Handler, IoExecutor> w(
static_cast<handler_work<Handler, IoExecutor>&&>(
o->work_));
ASIO_ERROR_LOCATION(o->ec_);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated
// with the handler. Consequently, a local copy of the handler is required
// to ensure that any owning sub-object remains valid until after we have
// deallocated the memory here.
detail::binder2<Handler, asio::error_code, std::size_t>
handler(o->handler_, o->ec_, o->bytes_transferred_);
p.h = asio::detail::addressof(handler.handler_);
p.reset();
ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
w.complete(handler, handler.handler_, io_ex);
ASIO_HANDLER_INVOCATION_END;
}
private: private:
Handler handler_; Handler handler_;
handler_work<Handler, IoExecutor> work_;
}; };
} // namespace detail } // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/descriptor_write_op.hpp // detail/descriptor_write_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -36,9 +36,11 @@ template <typename ConstBufferSequence>
class descriptor_write_op_base : public reactor_op class descriptor_write_op_base : public reactor_op
{ {
public: public:
descriptor_write_op_base(int descriptor, descriptor_write_op_base(const asio::error_code& success_ec,
const ConstBufferSequence& buffers, func_type complete_func) int descriptor, const ConstBufferSequence& buffers,
: reactor_op(&descriptor_write_op_base::do_perform, complete_func), func_type complete_func)
: reactor_op(success_ec,
&descriptor_write_op_base::do_perform, complete_func),
descriptor_(descriptor), descriptor_(descriptor),
buffers_(buffers) buffers_(buffers)
{ {
@@ -46,14 +48,27 @@ public:
static status do_perform(reactor_op* base) static status do_perform(reactor_op* base)
{ {
ASIO_ASSUME(base != 0);
descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base)); descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base));
buffer_sequence_adapter<asio::const_buffer, typedef buffer_sequence_adapter<asio::const_buffer,
ConstBufferSequence> bufs(o->buffers_); ConstBufferSequence> bufs_type;
status result = descriptor_ops::non_blocking_write(o->descriptor_, status result;
if (bufs_type::is_single_buffer)
{
result = descriptor_ops::non_blocking_write1(o->descriptor_,
bufs_type::first(o->buffers_).data(),
bufs_type::first(o->buffers_).size(),
o->ec_, o->bytes_transferred_) ? done : not_done;
}
else
{
bufs_type bufs(o->buffers_);
result = descriptor_ops::non_blocking_write(o->descriptor_,
bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
? done : not_done; ? done : not_done;
}
ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write", ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write",
o->ec_, o->bytes_transferred_)); o->ec_, o->bytes_transferred_));
@@ -66,20 +81,24 @@ private:
ConstBufferSequence buffers_; ConstBufferSequence buffers_;
}; };
template <typename ConstBufferSequence, typename Handler> template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
class descriptor_write_op class descriptor_write_op
: public descriptor_write_op_base<ConstBufferSequence> : public descriptor_write_op_base<ConstBufferSequence>
{ {
public: public:
typedef Handler handler_type;
typedef IoExecutor io_executor_type;
ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); ASIO_DEFINE_HANDLER_PTR(descriptor_write_op);
descriptor_write_op(int descriptor, descriptor_write_op(const asio::error_code& success_ec,
const ConstBufferSequence& buffers, Handler& handler) int descriptor, const ConstBufferSequence& buffers,
: descriptor_write_op_base<ConstBufferSequence>( Handler& handler, const IoExecutor& io_ex)
: descriptor_write_op_base<ConstBufferSequence>(success_ec,
descriptor, buffers, &descriptor_write_op::do_complete), descriptor, buffers, &descriptor_write_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(handler)) handler_(static_cast<Handler&&>(handler)),
work_(handler_, io_ex)
{ {
handler_work<Handler>::start(handler_);
} }
static void do_complete(void* owner, operation* base, static void do_complete(void* owner, operation* base,
@@ -87,12 +106,19 @@ public:
std::size_t /*bytes_transferred*/) std::size_t /*bytes_transferred*/)
{ {
// Take ownership of the handler object. // Take ownership of the handler object.
ASIO_ASSUME(base != 0);
descriptor_write_op* o(static_cast<descriptor_write_op*>(base)); descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o }; ptr p = { asio::detail::addressof(o->handler_), o, o };
handler_work<Handler> w(o->handler_);
ASIO_HANDLER_COMPLETION((*o)); ASIO_HANDLER_COMPLETION((*o));
// Take ownership of the operation's outstanding work.
handler_work<Handler, IoExecutor> w(
static_cast<handler_work<Handler, IoExecutor>&&>(
o->work_));
ASIO_ERROR_LOCATION(o->ec_);
// Make a copy of the handler so that the memory can be deallocated before // Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a // the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated // sub-object of the handler may be the true owner of the memory associated
@@ -114,8 +140,41 @@ public:
} }
} }
static void do_immediate(operation* base, bool, const void* io_ex)
{
// Take ownership of the handler object.
ASIO_ASSUME(base != 0);
descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
ptr p = { asio::detail::addressof(o->handler_), o, o };
ASIO_HANDLER_COMPLETION((*o));
// Take ownership of the operation's outstanding work.
immediate_handler_work<Handler, IoExecutor> w(
static_cast<handler_work<Handler, IoExecutor>&&>(
o->work_));
ASIO_ERROR_LOCATION(o->ec_);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the handler may be the true owner of the memory associated
// with the handler. Consequently, a local copy of the handler is required
// to ensure that any owning sub-object remains valid until after we have
// deallocated the memory here.
detail::binder2<Handler, asio::error_code, std::size_t>
handler(o->handler_, o->ec_, o->bytes_transferred_);
p.h = asio::detail::addressof(handler.handler_);
p.reset();
ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
w.complete(handler, handler.handler_, io_ex);
ASIO_HANDLER_INVOCATION_END;
}
private: private:
Handler handler_; Handler handler_;
handler_work<Handler, IoExecutor> work_;
}; };
} // namespace detail } // namespace detail

View File

@@ -2,7 +2,7 @@
// detail/dev_poll_reactor.hpp // detail/dev_poll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -28,6 +28,7 @@
#include "asio/detail/op_queue.hpp" #include "asio/detail/op_queue.hpp"
#include "asio/detail/reactor_op.hpp" #include "asio/detail/reactor_op.hpp"
#include "asio/detail/reactor_op_queue.hpp" #include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/scheduler_task.hpp"
#include "asio/detail/select_interrupter.hpp" #include "asio/detail/select_interrupter.hpp"
#include "asio/detail/socket_types.hpp" #include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_base.hpp"
@@ -41,7 +42,8 @@ namespace asio {
namespace detail { namespace detail {
class dev_poll_reactor class dev_poll_reactor
: public execution_context_service_base<dev_poll_reactor> : public execution_context_service_base<dev_poll_reactor>,
public scheduler_task
{ {
public: public:
enum op_types { read_op = 0, write_op = 1, enum op_types { read_op = 0, write_op = 1,
@@ -84,22 +86,43 @@ public:
per_descriptor_data& source_descriptor_data); per_descriptor_data& source_descriptor_data);
// Post a reactor operation for immediate completion. // Post a reactor operation for immediate completion.
void post_immediate_completion(reactor_op* op, bool is_continuation) void post_immediate_completion(operation* op, bool is_continuation) const;
{
scheduler_.post_immediate_completion(op, is_continuation); // Post a reactor operation for immediate completion.
} ASIO_DECL static void call_post_immediate_completion(
operation* op, bool is_continuation, const void* self);
// Start a new operation. The reactor operation will be performed when the // Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred. // given descriptor is flagged as ready, or an error has occurred.
ASIO_DECL void start_op(int op_type, socket_type descriptor, ASIO_DECL void start_op(int op_type, socket_type descriptor,
per_descriptor_data&, reactor_op* op, per_descriptor_data&, reactor_op* op,
bool is_continuation, bool allow_speculative); bool is_continuation, bool allow_speculative,
void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg);
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
void start_op(int op_type, socket_type descriptor,
per_descriptor_data& descriptor_data, reactor_op* op,
bool is_continuation, bool allow_speculative)
{
start_op(op_type, descriptor, descriptor_data,
op, is_continuation, allow_speculative,
&dev_poll_reactor::call_post_immediate_completion, this);
}
// Cancel all operations associated with the given descriptor. The // Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the // handlers associated with the descriptor will be invoked with the
// operation_aborted error. // operation_aborted error.
ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
// Cancel all operations associated with the given descriptor and key. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
ASIO_DECL void cancel_ops_by_key(socket_type descriptor,
per_descriptor_data& descriptor_data,
int op_type, void* cancellation_key);
// Cancel any operations that are running against the descriptor and remove // Cancel any operations that are running against the descriptor and remove
// its registration from the reactor. The reactor resources associated with // its registration from the reactor. The reactor resources associated with
// the descriptor must be released by calling cleanup_descriptor_data. // the descriptor must be released by calling cleanup_descriptor_data.
@@ -138,6 +161,12 @@ public:
typename timer_queue<Time_Traits>::per_timer_data& timer, typename timer_queue<Time_Traits>::per_timer_data& timer,
std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
// Cancel the timer operations associated with the given key.
template <typename Time_Traits>
void cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key);
// Move the timer operations associated with the given timer. // Move the timer operations associated with the given timer.
template <typename Time_Traits> template <typename Time_Traits>
void move_timer(timer_queue<Time_Traits>& queue, void move_timer(timer_queue<Time_Traits>& queue,

View File

@@ -2,7 +2,7 @@
// detail/epoll_reactor.hpp // detail/epoll_reactor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -25,6 +25,7 @@
#include "asio/detail/object_pool.hpp" #include "asio/detail/object_pool.hpp"
#include "asio/detail/op_queue.hpp" #include "asio/detail/op_queue.hpp"
#include "asio/detail/reactor_op.hpp" #include "asio/detail/reactor_op.hpp"
#include "asio/detail/scheduler_task.hpp"
#include "asio/detail/select_interrupter.hpp" #include "asio/detail/select_interrupter.hpp"
#include "asio/detail/socket_types.hpp" #include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_base.hpp"
@@ -42,7 +43,8 @@ namespace asio {
namespace detail { namespace detail {
class epoll_reactor class epoll_reactor
: public execution_context_service_base<epoll_reactor> : public execution_context_service_base<epoll_reactor>,
public scheduler_task
{ {
private: private:
// The mutex type used by this reactor. // The mutex type used by this reactor.
@@ -114,16 +116,30 @@ public:
per_descriptor_data& source_descriptor_data); per_descriptor_data& source_descriptor_data);
// Post a reactor operation for immediate completion. // Post a reactor operation for immediate completion.
void post_immediate_completion(reactor_op* op, bool is_continuation) void post_immediate_completion(operation* op, bool is_continuation) const;
{
scheduler_.post_immediate_completion(op, is_continuation); // Post a reactor operation for immediate completion.
} ASIO_DECL static void call_post_immediate_completion(
operation* op, bool is_continuation, const void* self);
// Start a new operation. The reactor operation will be performed when the // Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred. // given descriptor is flagged as ready, or an error has occurred.
ASIO_DECL void start_op(int op_type, socket_type descriptor, ASIO_DECL void start_op(int op_type, socket_type descriptor,
per_descriptor_data& descriptor_data, reactor_op* op, per_descriptor_data& descriptor_data, reactor_op* op,
bool is_continuation, bool allow_speculative); bool is_continuation, bool allow_speculative,
void (*on_immediate)(operation*, bool, const void*),
const void* immediate_arg);
// Start a new operation. The reactor operation will be performed when the
// given descriptor is flagged as ready, or an error has occurred.
void start_op(int op_type, socket_type descriptor,
per_descriptor_data& descriptor_data, reactor_op* op,
bool is_continuation, bool allow_speculative)
{
start_op(op_type, descriptor, descriptor_data,
op, is_continuation, allow_speculative,
&epoll_reactor::call_post_immediate_completion, this);
}
// Cancel all operations associated with the given descriptor. The // Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the // handlers associated with the descriptor will be invoked with the
@@ -131,6 +147,13 @@ public:
ASIO_DECL void cancel_ops(socket_type descriptor, ASIO_DECL void cancel_ops(socket_type descriptor,
per_descriptor_data& descriptor_data); per_descriptor_data& descriptor_data);
// Cancel all operations associated with the given descriptor and key. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
ASIO_DECL void cancel_ops_by_key(socket_type descriptor,
per_descriptor_data& descriptor_data,
int op_type, void* cancellation_key);
// Cancel any operations that are running against the descriptor and remove // Cancel any operations that are running against the descriptor and remove
// its registration from the reactor. The reactor resources associated with // its registration from the reactor. The reactor resources associated with
// the descriptor must be released by calling cleanup_descriptor_data. // the descriptor must be released by calling cleanup_descriptor_data.
@@ -170,6 +193,12 @@ public:
typename timer_queue<Time_Traits>::per_timer_data& timer, typename timer_queue<Time_Traits>::per_timer_data& timer,
std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
// Cancel the timer operations associated with the given key.
template <typename Time_Traits>
void cancel_timer_by_key(timer_queue<Time_Traits>& queue,
typename timer_queue<Time_Traits>::per_timer_data* timer,
void* cancellation_key);
// Move the timer operations associated with the given timer. // Move the timer operations associated with the given timer.
template <typename Time_Traits> template <typename Time_Traits>
void move_timer(timer_queue<Time_Traits>& queue, void move_timer(timer_queue<Time_Traits>& queue,

View File

@@ -2,7 +2,7 @@
// detail/event.hpp // detail/event.hpp
// ~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -23,10 +23,8 @@
# include "asio/detail/win_event.hpp" # include "asio/detail/win_event.hpp"
#elif defined(ASIO_HAS_PTHREADS) #elif defined(ASIO_HAS_PTHREADS)
# include "asio/detail/posix_event.hpp" # include "asio/detail/posix_event.hpp"
#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
# include "asio/detail/std_event.hpp"
#else #else
# error Only Windows, POSIX and std::condition_variable are supported! # include "asio/detail/std_event.hpp"
#endif #endif
namespace asio { namespace asio {
@@ -38,7 +36,7 @@ typedef null_event event;
typedef win_event event; typedef win_event event;
#elif defined(ASIO_HAS_PTHREADS) #elif defined(ASIO_HAS_PTHREADS)
typedef posix_event event; typedef posix_event event;
#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR) #else
typedef std_event event; typedef std_event event;
#endif #endif

View File

@@ -2,7 +2,7 @@
// detail/eventfd_select_interrupter.hpp // detail/eventfd_select_interrupter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -40,7 +40,7 @@ public:
// Interrupt the select call. // Interrupt the select call.
ASIO_DECL void interrupt(); ASIO_DECL void interrupt();
// Reset the select interrupt. Returns true if the call was interrupted. // Reset the select interrupter. Returns true if the reset was successful.
ASIO_DECL bool reset(); ASIO_DECL bool reset();
// Get the read descriptor to be passed to select. // Get the read descriptor to be passed to select.

View File

@@ -0,0 +1,29 @@
//
// detail/exception.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 ASIO_DETAIL_EXCEPTION_HPP
#define ASIO_DETAIL_EXCEPTION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <exception>
namespace asio {
using std::exception_ptr;
using std::current_exception;
using std::rethrow_exception;
} // namespace asio
#endif // ASIO_DETAIL_EXCEPTION_HPP

View File

@@ -0,0 +1,152 @@
//
// detail/executor_function.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 ASIO_DETAIL_EXECUTOR_FUNCTION_HPP
#define ASIO_DETAIL_EXECUTOR_FUNCTION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/memory.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
// Lightweight, move-only function object wrapper.
class executor_function
{
public:
template <typename F, typename Alloc>
explicit executor_function(F f, const Alloc& a)
{
// Allocate and construct an object to wrap the function.
typedef impl<F, Alloc> impl_type;
typename impl_type::ptr p = {
detail::addressof(a), impl_type::ptr::allocate(a), 0 };
impl_ = new (p.v) impl_type(static_cast<F&&>(f), a);
p.v = 0;
}
executor_function(executor_function&& other) noexcept
: impl_(other.impl_)
{
other.impl_ = 0;
}
~executor_function()
{
if (impl_)
impl_->complete_(impl_, false);
}
void operator()()
{
if (impl_)
{
impl_base* i = impl_;
impl_ = 0;
i->complete_(i, true);
}
}
private:
// Base class for polymorphic function implementations.
struct impl_base
{
void (*complete_)(impl_base*, bool);
};
// Polymorphic function implementation.
template <typename Function, typename Alloc>
struct impl : impl_base
{
ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(
thread_info_base::executor_function_tag, impl);
template <typename F>
impl(F&& f, const Alloc& a)
: function_(static_cast<F&&>(f)),
allocator_(a)
{
complete_ = &executor_function::complete<Function, Alloc>;
}
Function function_;
Alloc allocator_;
};
// Helper to complete function invocation.
template <typename Function, typename Alloc>
static void complete(impl_base* base, bool call)
{
// Take ownership of the function object.
impl<Function, Alloc>* i(static_cast<impl<Function, Alloc>*>(base));
Alloc allocator(i->allocator_);
typename impl<Function, Alloc>::ptr p = {
detail::addressof(allocator), i, i };
// Make a copy of the function so that the memory can be deallocated before
// the upcall is made. Even if we're not about to make an upcall, a
// sub-object of the function may be the true owner of the memory
// associated with the function. Consequently, a local copy of the function
// is required to ensure that any owning sub-object remains valid until
// after we have deallocated the memory here.
Function function(static_cast<Function&&>(i->function_));
p.reset();
// Make the upcall if required.
if (call)
{
static_cast<Function&&>(function)();
}
}
impl_base* impl_;
};
// Lightweight, non-owning, copyable function object wrapper.
class executor_function_view
{
public:
template <typename F>
explicit executor_function_view(F& f) noexcept
: complete_(&executor_function_view::complete<F>),
function_(&f)
{
}
void operator()()
{
complete_(function_);
}
private:
// Helper to complete function invocation.
template <typename F>
static void complete(void* f)
{
(*static_cast<F*>(f))();
}
void (*complete_)(void*);
void* function_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_EXECUTOR_FUNCTION_HPP

View File

@@ -2,7 +2,7 @@
// detail/executor_op.hpp // detail/executor_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~
// //
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// //
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -18,7 +18,6 @@
#include "asio/detail/config.hpp" #include "asio/detail/config.hpp"
#include "asio/detail/fenced_block.hpp" #include "asio/detail/fenced_block.hpp"
#include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/scheduler_operation.hpp" #include "asio/detail/scheduler_operation.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
@@ -34,9 +33,9 @@ public:
ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op); ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op);
template <typename H> template <typename H>
executor_op(ASIO_MOVE_ARG(H) h, const Alloc& allocator) executor_op(H&& h, const Alloc& allocator)
: Operation(&executor_op::do_complete), : Operation(&executor_op::do_complete),
handler_(ASIO_MOVE_CAST(H)(h)), handler_(static_cast<H&&>(h)),
allocator_(allocator) allocator_(allocator)
{ {
} }
@@ -46,6 +45,7 @@ public:
std::size_t /*bytes_transferred*/) std::size_t /*bytes_transferred*/)
{ {
// Take ownership of the handler object. // Take ownership of the handler object.
ASIO_ASSUME(base != 0);
executor_op* o(static_cast<executor_op*>(base)); executor_op* o(static_cast<executor_op*>(base));
Alloc allocator(o->allocator_); Alloc allocator(o->allocator_);
ptr p = { detail::addressof(allocator), o, o }; ptr p = { detail::addressof(allocator), o, o };
@@ -58,7 +58,7 @@ public:
// with the handler. Consequently, a local copy of the handler is required // with the handler. Consequently, a local copy of the handler is required
// to ensure that any owning sub-object remains valid until after we have // to ensure that any owning sub-object remains valid until after we have
// deallocated the memory here. // deallocated the memory here.
Handler handler(ASIO_MOVE_CAST(Handler)(o->handler_)); Handler handler(static_cast<Handler&&>(o->handler_));
p.reset(); p.reset();
// Make the upcall if required. // Make the upcall if required.
@@ -66,7 +66,7 @@ public:
{ {
fenced_block b(fenced_block::half); fenced_block b(fenced_block::half);
ASIO_HANDLER_INVOCATION_BEGIN(()); ASIO_HANDLER_INVOCATION_BEGIN(());
asio_handler_invoke_helpers::invoke(handler, handler); static_cast<Handler&&>(handler)();
ASIO_HANDLER_INVOCATION_END; ASIO_HANDLER_INVOCATION_END;
} }
} }

Some files were not shown because too many files have changed in this diff Show More