tidal-link (empty) → 1.0
raw patch · 717 files changed
+176207/−0 lines, 717 filesdep +basedep +tidal-link
Dependencies added: base, tidal-link
Files
- LICENSE +674/−0
- README.md +6/−0
- link/examples/linkaudio/AudioEngine.hpp +81/−0
- link/examples/linkaudio/AudioPlatform.hpp +44/−0
- link/examples/linkaudio/AudioPlatform_Asio.hpp +103/−0
- link/examples/linkaudio/AudioPlatform_CoreAudio.hpp +54/−0
- link/examples/linkaudio/AudioPlatform_Dummy.hpp +112/−0
- link/examples/linkaudio/AudioPlatform_Jack.hpp +58/−0
- link/examples/linkaudio/AudioPlatform_Portaudio.hpp +59/−0
- link/examples/linkaudio/AudioPlatform_Wasapi.hpp +72/−0
- link/extensions/abl_link/include/abl_link.h +352/−0
- link/extensions/abl_link/src/abl_link.cpp +214/−0
- link/include/ableton/Link.hpp +403/−0
- link/include/ableton/Link.ipp +280/−0
- link/include/ableton/discovery/InterfaceScanner.hpp +102/−0
- link/include/ableton/discovery/IpV4Interface.hpp +123/−0
- link/include/ableton/discovery/MessageTypes.hpp +50/−0
- link/include/ableton/discovery/NetworkByteStreamSerializable.hpp +462/−0
- link/include/ableton/discovery/Payload.hpp +296/−0
- link/include/ableton/discovery/PeerGateway.hpp +251/−0
- link/include/ableton/discovery/PeerGateways.hpp +182/−0
- link/include/ableton/discovery/Service.hpp +72/−0
- link/include/ableton/discovery/UdpMessenger.hpp +330/−0
- link/include/ableton/discovery/test/Interface.hpp +75/−0
- link/include/ableton/discovery/test/PayloadEntries.hpp +133/−0
- link/include/ableton/discovery/test/Socket.hpp +85/−0
- link/include/ableton/discovery/v1/Messages.hpp +168/−0
- link/include/ableton/link/Beats.hpp +125/−0
- link/include/ableton/link/ClientSessionTimelines.hpp +115/−0
- link/include/ableton/link/Controller.hpp +792/−0
- link/include/ableton/link/Gateway.hpp +93/−0
- link/include/ableton/link/GhostXForm.hpp +61/−0
- link/include/ableton/link/HostTimeFilter.hpp +86/−0
- link/include/ableton/link/LinearRegression.hpp +61/−0
- link/include/ableton/link/Measurement.hpp +250/−0
- link/include/ableton/link/MeasurementEndpointV4.hpp +69/−0
- link/include/ableton/link/MeasurementService.hpp +144/−0
- link/include/ableton/link/Median.hpp +50/−0
- link/include/ableton/link/NodeId.hpp +78/−0
- link/include/ableton/link/NodeState.hpp +77/−0
- link/include/ableton/link/Optional.hpp +97/−0
- link/include/ableton/link/PayloadEntries.hpp +140/−0
- link/include/ableton/link/PeerState.hpp +90/−0
- link/include/ableton/link/Peers.hpp +368/−0
- link/include/ableton/link/Phase.hpp +100/−0
- link/include/ableton/link/PingResponder.hpp +171/−0
- link/include/ableton/link/SessionId.hpp +63/−0
- link/include/ableton/link/SessionState.hpp +115/−0
- link/include/ableton/link/Sessions.hpp +301/−0
- link/include/ableton/link/StartStopState.hpp +152/−0
- link/include/ableton/link/Tempo.hpp +125/−0
- link/include/ableton/link/Timeline.hpp +98/−0
- link/include/ableton/link/TripleBuffer.hpp +121/−0
- link/include/ableton/link/v1/Messages.hpp +138/−0
- link/include/ableton/platforms/Config.hpp +101/−0
- link/include/ableton/platforms/asio/AsioTimer.hpp +132/−0
- link/include/ableton/platforms/asio/AsioWrapper.hpp +90/−0
- link/include/ableton/platforms/asio/Context.hpp +196/−0
- link/include/ableton/platforms/asio/LockFreeCallbackDispatcher.hpp +88/−0
- link/include/ableton/platforms/asio/Socket.hpp +110/−0
- link/include/ableton/platforms/asio/Util.hpp +43/−0
- link/include/ableton/platforms/darwin/Clock.hpp +70/−0
- link/include/ableton/platforms/darwin/Darwin.hpp +30/−0
- link/include/ableton/platforms/darwin/ThreadFactory.hpp +48/−0
- link/include/ableton/platforms/esp32/Clock.hpp +36/−0
- link/include/ableton/platforms/esp32/Context.hpp +228/−0
- link/include/ableton/platforms/esp32/Esp32.hpp +27/−0
- link/include/ableton/platforms/esp32/LockFreeCallbackDispatcher.hpp +94/−0
- link/include/ableton/platforms/esp32/Random.hpp +36/−0
- link/include/ableton/platforms/esp32/ScanIpIfAddrs.hpp +59/−0
- link/include/ableton/platforms/linux/Clock.hpp +60/−0
- link/include/ableton/platforms/linux/Linux.hpp +30/−0
- link/include/ableton/platforms/linux/ThreadFactory.hpp +45/−0
- link/include/ableton/platforms/posix/ScanIpIfAddrs.hpp +110/−0
- link/include/ableton/platforms/stl/Clock.hpp +43/−0
- link/include/ableton/platforms/stl/Random.hpp +51/−0
- link/include/ableton/platforms/windows/Clock.hpp +71/−0
- link/include/ableton/platforms/windows/ScanIpIfAddrs.hpp +140/−0
- link/include/ableton/platforms/windows/ThreadFactory.hpp +52/−0
- link/include/ableton/platforms/windows/Windows.hpp +32/−0
- link/include/ableton/test/CatchWrapper.hpp +42/−0
- link/include/ableton/test/serial_io/Context.hpp +109/−0
- link/include/ableton/test/serial_io/Fixture.hpp +92/−0
- link/include/ableton/test/serial_io/SchedulerTree.hpp +104/−0
- link/include/ableton/test/serial_io/Timer.hpp +110/−0
- link/include/ableton/util/Injected.hpp +254/−0
- link/include/ableton/util/Log.hpp +176/−0
- link/include/ableton/util/SafeAsyncHandler.hpp +66/−0
- link/include/ableton/util/SampleTiming.hpp +52/−0
- link/include/ableton/util/test/IoService.hpp +114/−0
- link/include/ableton/util/test/Timer.hpp +96/−0
- link/modules/asio-standalone/asio/include/asio.hpp +182/−0
- link/modules/asio-standalone/asio/include/asio/any_io_executor.hpp +71/−0
- link/modules/asio-standalone/asio/include/asio/associated_allocator.hpp +125/−0
- link/modules/asio-standalone/asio/include/asio/associated_executor.hpp +166/−0
- link/modules/asio-standalone/asio/include/asio/async_result.hpp +582/−0
- link/modules/asio-standalone/asio/include/asio/awaitable.hpp +133/−0
- link/modules/asio-standalone/asio/include/asio/basic_datagram_socket.hpp +1215/−0
- link/modules/asio-standalone/asio/include/asio/basic_deadline_timer.hpp +693/−0
- link/modules/asio-standalone/asio/include/asio/basic_io_object.hpp +290/−0
- link/modules/asio-standalone/asio/include/asio/basic_raw_socket.hpp +1206/−0
- link/modules/asio-standalone/asio/include/asio/basic_seq_packet_socket.hpp +761/−0
- link/modules/asio-standalone/asio/include/asio/basic_serial_port.hpp +907/−0
- link/modules/asio-standalone/asio/include/asio/basic_signal_set.hpp +568/−0
- link/modules/asio-standalone/asio/include/asio/basic_socket.hpp +1894/−0
- link/modules/asio-standalone/asio/include/asio/basic_socket_acceptor.hpp +2501/−0
- link/modules/asio-standalone/asio/include/asio/basic_socket_iostream.hpp +407/−0
- link/modules/asio-standalone/asio/include/asio/basic_socket_streambuf.hpp +687/−0
- link/modules/asio-standalone/asio/include/asio/basic_stream_socket.hpp +1053/−0
- link/modules/asio-standalone/asio/include/asio/basic_streambuf.hpp +452/−0
- link/modules/asio-standalone/asio/include/asio/basic_streambuf_fwd.hpp +36/−0
- link/modules/asio-standalone/asio/include/asio/basic_waitable_timer.hpp +811/−0
- link/modules/asio-standalone/asio/include/asio/bind_executor.hpp +575/−0
- link/modules/asio-standalone/asio/include/asio/buffer.hpp +2496/−0
- link/modules/asio-standalone/asio/include/asio/buffered_read_stream.hpp +253/−0
- link/modules/asio-standalone/asio/include/asio/buffered_read_stream_fwd.hpp +25/−0
- link/modules/asio-standalone/asio/include/asio/buffered_stream.hpp +279/−0
- link/modules/asio-standalone/asio/include/asio/buffered_stream_fwd.hpp +25/−0
- link/modules/asio-standalone/asio/include/asio/buffered_write_stream.hpp +245/−0
- link/modules/asio-standalone/asio/include/asio/buffered_write_stream_fwd.hpp +25/−0
- link/modules/asio-standalone/asio/include/asio/buffers_iterator.hpp +521/−0
- link/modules/asio-standalone/asio/include/asio/co_spawn.hpp +471/−0
- link/modules/asio-standalone/asio/include/asio/completion_condition.hpp +218/−0
- link/modules/asio-standalone/asio/include/asio/compose.hpp +136/−0
- link/modules/asio-standalone/asio/include/asio/connect.hpp +1076/−0
- link/modules/asio-standalone/asio/include/asio/coroutine.hpp +328/−0
- link/modules/asio-standalone/asio/include/asio/deadline_timer.hpp +38/−0
- link/modules/asio-standalone/asio/include/asio/defer.hpp +130/−0
- link/modules/asio-standalone/asio/include/asio/detached.hpp +112/−0
- link/modules/asio-standalone/asio/include/asio/detail/array.hpp +38/−0
- link/modules/asio-standalone/asio/include/asio/detail/array_fwd.hpp +34/−0
- link/modules/asio-standalone/asio/include/asio/detail/assert.hpp +32/−0
- link/modules/asio-standalone/asio/include/asio/detail/atomic_count.hpp +64/−0
- link/modules/asio-standalone/asio/include/asio/detail/base_from_completion_cond.hpp +69/−0
- link/modules/asio-standalone/asio/include/asio/detail/bind_handler.hpp +934/−0
- link/modules/asio-standalone/asio/include/asio/detail/blocking_executor_op.hpp +107/−0
- link/modules/asio-standalone/asio/include/asio/detail/buffer_resize_guard.hpp +66/−0
- link/modules/asio-standalone/asio/include/asio/detail/buffer_sequence_adapter.hpp +650/−0
- link/modules/asio-standalone/asio/include/asio/detail/buffered_stream_storage.hpp +126/−0
- link/modules/asio-standalone/asio/include/asio/detail/bulk_executor_op.hpp +88/−0
- link/modules/asio-standalone/asio/include/asio/detail/call_stack.hpp +125/−0
- link/modules/asio-standalone/asio/include/asio/detail/chrono.hpp +66/−0
- link/modules/asio-standalone/asio/include/asio/detail/chrono_time_traits.hpp +190/−0
- link/modules/asio-standalone/asio/include/asio/detail/completion_handler.hpp +88/−0
- link/modules/asio-standalone/asio/include/asio/detail/concurrency_hint.hpp +94/−0
- link/modules/asio-standalone/asio/include/asio/detail/conditionally_enabled_event.hpp +120/−0
- link/modules/asio-standalone/asio/include/asio/detail/conditionally_enabled_mutex.hpp +149/−0
- link/modules/asio-standalone/asio/include/asio/detail/config.hpp +1822/−0
- link/modules/asio-standalone/asio/include/asio/detail/consuming_buffers.hpp +414/−0
- link/modules/asio-standalone/asio/include/asio/detail/cstddef.hpp +31/−0
- link/modules/asio-standalone/asio/include/asio/detail/cstdint.hpp +60/−0
- link/modules/asio-standalone/asio/include/asio/detail/date_time_fwd.hpp +34/−0
- link/modules/asio-standalone/asio/include/asio/detail/deadline_timer_service.hpp +295/−0
- link/modules/asio-standalone/asio/include/asio/detail/dependent_type.hpp +36/−0
- link/modules/asio-standalone/asio/include/asio/detail/descriptor_ops.hpp +139/−0
- link/modules/asio-standalone/asio/include/asio/detail/descriptor_read_op.hpp +148/−0
- link/modules/asio-standalone/asio/include/asio/detail/descriptor_write_op.hpp +148/−0
- link/modules/asio-standalone/asio/include/asio/detail/dev_poll_reactor.hpp +218/−0
- link/modules/asio-standalone/asio/include/asio/detail/epoll_reactor.hpp +266/−0
- link/modules/asio-standalone/asio/include/asio/detail/event.hpp +48/−0
- link/modules/asio-standalone/asio/include/asio/detail/eventfd_select_interrupter.hpp +83/−0
- link/modules/asio-standalone/asio/include/asio/detail/executor_function.hpp +203/−0
- link/modules/asio-standalone/asio/include/asio/detail/executor_op.hpp +84/−0
- link/modules/asio-standalone/asio/include/asio/detail/fd_set_adapter.hpp +39/−0
- link/modules/asio-standalone/asio/include/asio/detail/fenced_block.hpp +80/−0
- link/modules/asio-standalone/asio/include/asio/detail/functional.hpp +38/−0
- link/modules/asio-standalone/asio/include/asio/detail/future.hpp +33/−0
- link/modules/asio-standalone/asio/include/asio/detail/gcc_arm_fenced_block.hpp +91/−0
- link/modules/asio-standalone/asio/include/asio/detail/gcc_hppa_fenced_block.hpp +68/−0
- link/modules/asio-standalone/asio/include/asio/detail/gcc_sync_fenced_block.hpp +65/−0
- link/modules/asio-standalone/asio/include/asio/detail/gcc_x86_fenced_block.hpp +99/−0
- link/modules/asio-standalone/asio/include/asio/detail/global.hpp +52/−0
- link/modules/asio-standalone/asio/include/asio/detail/handler_alloc_helpers.hpp +284/−0
- link/modules/asio-standalone/asio/include/asio/detail/handler_cont_helpers.hpp +45/−0
- link/modules/asio-standalone/asio/include/asio/detail/handler_invoke_helpers.hpp +80/−0
- link/modules/asio-standalone/asio/include/asio/detail/handler_tracking.hpp +264/−0
- link/modules/asio-standalone/asio/include/asio/detail/handler_type_requirements.hpp +556/−0
- link/modules/asio-standalone/asio/include/asio/detail/handler_work.hpp +438/−0
- link/modules/asio-standalone/asio/include/asio/detail/hash_map.hpp +331/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/buffer_sequence_adapter.ipp +118/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/descriptor_ops.ipp +608/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/dev_poll_reactor.hpp +91/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/dev_poll_reactor.ipp +446/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/epoll_reactor.hpp +89/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/epoll_reactor.ipp +787/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/eventfd_select_interrupter.ipp +169/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/handler_tracking.ipp +396/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/kqueue_reactor.hpp +93/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/kqueue_reactor.ipp +570/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/null_event.ipp +74/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/pipe_select_interrupter.ipp +129/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/posix_event.ipp +59/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/posix_mutex.ipp +46/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/posix_thread.ipp +84/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/posix_tss_ptr.ipp +46/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_descriptor_service.ipp +223/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_serial_port_service.ipp +149/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_socket_service_base.ipp +300/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/resolver_service_base.ipp +158/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/scheduler.ipp +654/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/select_reactor.hpp +100/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/select_reactor.ipp +338/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/service_registry.hpp +94/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/service_registry.ipp +197/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/signal_set_service.ipp +668/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/socket_ops.ipp +3962/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/socket_select_interrupter.ipp +185/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/strand_executor_service.hpp +385/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/strand_executor_service.ipp +134/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/strand_service.hpp +117/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/strand_service.ipp +178/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/throw_error.ipp +60/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/timer_queue_ptime.ipp +91/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/timer_queue_set.ipp +101/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/win_event.ipp +76/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_handle_service.ipp +525/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_io_context.hpp +103/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_io_context.ipp +603/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_serial_port_service.ipp +192/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp +801/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/win_mutex.ipp +84/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/win_object_handle_service.ipp +448/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/win_static_mutex.ipp +136/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/win_thread.ipp +150/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/win_tss_ptr.ipp +57/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_ssocket_service_base.ipp +626/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp +92/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_timer_scheduler.ipp +121/−0
- link/modules/asio-standalone/asio/include/asio/detail/impl/winsock_init.ipp +82/−0
- link/modules/asio-standalone/asio/include/asio/detail/io_control.hpp +84/−0
- link/modules/asio-standalone/asio/include/asio/detail/io_object_impl.hpp +175/−0
- link/modules/asio-standalone/asio/include/asio/detail/is_buffer_sequence.hpp +312/−0
- link/modules/asio-standalone/asio/include/asio/detail/is_executor.hpp +126/−0
- link/modules/asio-standalone/asio/include/asio/detail/keyword_tss_ptr.hpp +70/−0
- link/modules/asio-standalone/asio/include/asio/detail/kqueue_reactor.hpp +242/−0
- link/modules/asio-standalone/asio/include/asio/detail/limits.hpp +26/−0
- link/modules/asio-standalone/asio/include/asio/detail/local_free_on_block_exit.hpp +59/−0
- link/modules/asio-standalone/asio/include/asio/detail/macos_fenced_block.hpp +62/−0
- link/modules/asio-standalone/asio/include/asio/detail/memory.hpp +73/−0
- link/modules/asio-standalone/asio/include/asio/detail/mutex.hpp +48/−0
- link/modules/asio-standalone/asio/include/asio/detail/non_const_lvalue.hpp +54/−0
- link/modules/asio-standalone/asio/include/asio/detail/noncopyable.hpp +43/−0
- link/modules/asio-standalone/asio/include/asio/detail/null_event.hpp +106/−0
- link/modules/asio-standalone/asio/include/asio/detail/null_fenced_block.hpp +47/−0
- link/modules/asio-standalone/asio/include/asio/detail/null_global.hpp +59/−0
- link/modules/asio-standalone/asio/include/asio/detail/null_mutex.hpp +64/−0
- link/modules/asio-standalone/asio/include/asio/detail/null_reactor.hpp +68/−0
- link/modules/asio-standalone/asio/include/asio/detail/null_signal_blocker.hpp +69/−0
- link/modules/asio-standalone/asio/include/asio/detail/null_socket_service.hpp +519/−0
- link/modules/asio-standalone/asio/include/asio/detail/null_static_mutex.hpp +60/−0
- link/modules/asio-standalone/asio/include/asio/detail/null_thread.hpp +67/−0
- link/modules/asio-standalone/asio/include/asio/detail/null_tss_ptr.hpp +68/−0
- link/modules/asio-standalone/asio/include/asio/detail/object_pool.hpp +171/−0
- link/modules/asio-standalone/asio/include/asio/detail/old_win_sdk_compat.hpp +214/−0
- link/modules/asio-standalone/asio/include/asio/detail/op_queue.hpp +162/−0
- link/modules/asio-standalone/asio/include/asio/detail/operation.hpp +38/−0
- link/modules/asio-standalone/asio/include/asio/detail/pipe_select_interrupter.hpp +89/−0
- link/modules/asio-standalone/asio/include/asio/detail/pop_options.hpp +141/−0
- link/modules/asio-standalone/asio/include/asio/detail/posix_event.hpp +175/−0
- link/modules/asio-standalone/asio/include/asio/detail/posix_fd_set_adapter.hpp +118/−0
- link/modules/asio-standalone/asio/include/asio/detail/posix_global.hpp +80/−0
- link/modules/asio-standalone/asio/include/asio/detail/posix_mutex.hpp +76/−0
- link/modules/asio-standalone/asio/include/asio/detail/posix_signal_blocker.hpp +85/−0
- link/modules/asio-standalone/asio/include/asio/detail/posix_static_mutex.hpp +64/−0
- link/modules/asio-standalone/asio/include/asio/detail/posix_thread.hpp +109/−0
- link/modules/asio-standalone/asio/include/asio/detail/posix_tss_ptr.hpp +79/−0
- link/modules/asio-standalone/asio/include/asio/detail/push_options.hpp +185/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_descriptor_service.hpp +416/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_null_buffers_op.hpp +98/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_serial_port_service.hpp +237/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_accept_op.hpp +242/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_connect_op.hpp +123/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recv_op.hpp +159/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recvfrom_op.hpp +164/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recvmsg_op.hpp +145/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_send_op.hpp +162/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_sendto_op.hpp +156/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_service.hpp +528/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_service_base.hpp +541/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactive_wait_op.hpp +98/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactor.hpp +32/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactor_fwd.hpp +40/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactor_op.hpp +67/−0
- link/modules/asio-standalone/asio/include/asio/detail/reactor_op_queue.hpp +168/−0
- link/modules/asio-standalone/asio/include/asio/detail/recycling_allocator.hpp +106/−0
- link/modules/asio-standalone/asio/include/asio/detail/regex_fwd.hpp +35/−0
- link/modules/asio-standalone/asio/include/asio/detail/resolve_endpoint_op.hpp +140/−0
- link/modules/asio-standalone/asio/include/asio/detail/resolve_op.hpp +45/−0
- link/modules/asio-standalone/asio/include/asio/detail/resolve_query_op.hpp +150/−0
- link/modules/asio-standalone/asio/include/asio/detail/resolver_service.hpp +145/−0
- link/modules/asio-standalone/asio/include/asio/detail/resolver_service_base.hpp +143/−0
- link/modules/asio-standalone/asio/include/asio/detail/scheduler.hpp +232/−0
- link/modules/asio-standalone/asio/include/asio/detail/scheduler_operation.hpp +78/−0
- link/modules/asio-standalone/asio/include/asio/detail/scheduler_thread_info.hpp +40/−0
- link/modules/asio-standalone/asio/include/asio/detail/scoped_lock.hpp +101/−0
- link/modules/asio-standalone/asio/include/asio/detail/scoped_ptr.hpp +87/−0
- link/modules/asio-standalone/asio/include/asio/detail/select_interrupter.hpp +46/−0
- link/modules/asio-standalone/asio/include/asio/detail/select_reactor.hpp +238/−0
- link/modules/asio-standalone/asio/include/asio/detail/service_registry.hpp +164/−0
- link/modules/asio-standalone/asio/include/asio/detail/signal_blocker.hpp +44/−0
- link/modules/asio-standalone/asio/include/asio/detail/signal_handler.hpp +90/−0
- link/modules/asio-standalone/asio/include/asio/detail/signal_init.hpp +47/−0
- link/modules/asio-standalone/asio/include/asio/detail/signal_op.hpp +49/−0
- link/modules/asio-standalone/asio/include/asio/detail/signal_set_service.hpp +229/−0
- link/modules/asio-standalone/asio/include/asio/detail/socket_holder.hpp +98/−0
- link/modules/asio-standalone/asio/include/asio/detail/socket_ops.hpp +383/−0
- link/modules/asio-standalone/asio/include/asio/detail/socket_option.hpp +316/−0
- link/modules/asio-standalone/asio/include/asio/detail/socket_select_interrupter.hpp +91/−0
- link/modules/asio-standalone/asio/include/asio/detail/socket_types.hpp +416/−0
- link/modules/asio-standalone/asio/include/asio/detail/solaris_fenced_block.hpp +62/−0
- link/modules/asio-standalone/asio/include/asio/detail/source_location.hpp +45/−0
- link/modules/asio-standalone/asio/include/asio/detail/static_mutex.hpp +52/−0
- link/modules/asio-standalone/asio/include/asio/detail/std_event.hpp +188/−0
- link/modules/asio-standalone/asio/include/asio/detail/std_fenced_block.hpp +62/−0
- link/modules/asio-standalone/asio/include/asio/detail/std_global.hpp +70/−0
- link/modules/asio-standalone/asio/include/asio/detail/std_mutex.hpp +73/−0
- link/modules/asio-standalone/asio/include/asio/detail/std_static_mutex.hpp +81/−0
- link/modules/asio-standalone/asio/include/asio/detail/std_thread.hpp +71/−0
- link/modules/asio-standalone/asio/include/asio/detail/strand_executor_service.hpp +166/−0
- link/modules/asio-standalone/asio/include/asio/detail/strand_service.hpp +145/−0
- link/modules/asio-standalone/asio/include/asio/detail/string_view.hpp +47/−0
- link/modules/asio-standalone/asio/include/asio/detail/thread.hpp +60/−0
- link/modules/asio-standalone/asio/include/asio/detail/thread_context.hpp +42/−0
- link/modules/asio-standalone/asio/include/asio/detail/thread_group.hpp +95/−0
- link/modules/asio-standalone/asio/include/asio/detail/thread_info_base.hpp +189/−0
- link/modules/asio-standalone/asio/include/asio/detail/throw_error.hpp +53/−0
- link/modules/asio-standalone/asio/include/asio/detail/throw_exception.hpp +51/−0
- link/modules/asio-standalone/asio/include/asio/detail/timer_queue.hpp +360/−0
- link/modules/asio-standalone/asio/include/asio/detail/timer_queue_base.hpp +68/−0
- link/modules/asio-standalone/asio/include/asio/detail/timer_queue_ptime.hpp +99/−0
- link/modules/asio-standalone/asio/include/asio/detail/timer_queue_set.hpp +66/−0
- link/modules/asio-standalone/asio/include/asio/detail/timer_scheduler.hpp +35/−0
- link/modules/asio-standalone/asio/include/asio/detail/timer_scheduler_fwd.hpp +40/−0
- link/modules/asio-standalone/asio/include/asio/detail/tss_ptr.hpp +69/−0
- link/modules/asio-standalone/asio/include/asio/detail/type_traits.hpp +148/−0
- link/modules/asio-standalone/asio/include/asio/detail/variadic_templates.hpp +294/−0
- link/modules/asio-standalone/asio/include/asio/detail/wait_handler.hpp +90/−0
- link/modules/asio-standalone/asio/include/asio/detail/wait_op.hpp +45/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_event.hpp +164/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_fd_set_adapter.hpp +149/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_fenced_block.hpp +90/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_global.hpp +71/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_read_op.hpp +117/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_service.hpp +335/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_write_op.hpp +110/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_io_context.hpp +342/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_null_buffers_op.hpp +127/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_operation.hpp +96/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_overlapped_op.hpp +96/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_overlapped_ptr.hpp +171/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_serial_port_service.hpp +232/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_accept_op.hpp +312/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_connect_op.hpp +135/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recv_op.hpp +124/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recvfrom_op.hpp +133/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recvmsg_op.hpp +125/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_send_op.hpp +118/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_service.hpp +581/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_service_base.hpp +600/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_thread_info.hpp +34/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_iocp_wait_op.hpp +128/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_mutex.hpp +78/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_object_handle_service.hpp +195/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_static_mutex.hpp +74/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_thread.hpp +147/−0
- link/modules/asio-standalone/asio/include/asio/detail/win_tss_ptr.hpp +79/−0
- link/modules/asio-standalone/asio/include/asio/detail/winapp_thread.hpp +124/−0
- link/modules/asio-standalone/asio/include/asio/detail/wince_thread.hpp +124/−0
- link/modules/asio-standalone/asio/include/asio/detail/winrt_async_manager.hpp +305/−0
- link/modules/asio-standalone/asio/include/asio/detail/winrt_async_op.hpp +65/−0
- link/modules/asio-standalone/asio/include/asio/detail/winrt_resolve_op.hpp +125/−0
- link/modules/asio-standalone/asio/include/asio/detail/winrt_resolver_service.hpp +212/−0
- link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_connect_op.hpp +98/−0
- link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_recv_op.hpp +119/−0
- link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_send_op.hpp +110/−0
- link/modules/asio-standalone/asio/include/asio/detail/winrt_ssocket_service.hpp +250/−0
- link/modules/asio-standalone/asio/include/asio/detail/winrt_ssocket_service_base.hpp +362/−0
- link/modules/asio-standalone/asio/include/asio/detail/winrt_timer_scheduler.hpp +147/−0
- link/modules/asio-standalone/asio/include/asio/detail/winrt_utils.hpp +106/−0
- link/modules/asio-standalone/asio/include/asio/detail/winsock_init.hpp +128/−0
- link/modules/asio-standalone/asio/include/asio/detail/work_dispatcher.hpp +148/−0
- link/modules/asio-standalone/asio/include/asio/detail/wrapped_handler.hpp +327/−0
- link/modules/asio-standalone/asio/include/asio/dispatch.hpp +121/−0
- link/modules/asio-standalone/asio/include/asio/error.hpp +356/−0
- link/modules/asio-standalone/asio/include/asio/error_code.hpp +202/−0
- link/modules/asio-standalone/asio/include/asio/execution.hpp +48/−0
- link/modules/asio-standalone/asio/include/asio/execution/allocator.hpp +249/−0
- link/modules/asio-standalone/asio/include/asio/execution/any_executor.hpp +2264/−0
- link/modules/asio-standalone/asio/include/asio/execution/bad_executor.hpp +47/−0
- link/modules/asio-standalone/asio/include/asio/execution/blocking.hpp +1351/−0
- link/modules/asio-standalone/asio/include/asio/execution/blocking_adaptation.hpp +1064/−0
- link/modules/asio-standalone/asio/include/asio/execution/bulk_execute.hpp +390/−0
- link/modules/asio-standalone/asio/include/asio/execution/bulk_guarantee.hpp +1018/−0
- link/modules/asio-standalone/asio/include/asio/execution/connect.hpp +486/−0
- link/modules/asio-standalone/asio/include/asio/execution/context.hpp +185/−0
- link/modules/asio-standalone/asio/include/asio/execution/context_as.hpp +201/−0
- link/modules/asio-standalone/asio/include/asio/execution/detail/as_invocable.hpp +152/−0
- link/modules/asio-standalone/asio/include/asio/execution/detail/as_operation.hpp +105/−0
- link/modules/asio-standalone/asio/include/asio/execution/detail/as_receiver.hpp +128/−0
- link/modules/asio-standalone/asio/include/asio/execution/detail/bulk_sender.hpp +261/−0
- link/modules/asio-standalone/asio/include/asio/execution/detail/submit_receiver.hpp +233/−0
- link/modules/asio-standalone/asio/include/asio/execution/detail/void_receiver.hpp +90/−0
- link/modules/asio-standalone/asio/include/asio/execution/execute.hpp +264/−0
- link/modules/asio-standalone/asio/include/asio/execution/executor.hpp +238/−0
- link/modules/asio-standalone/asio/include/asio/execution/impl/bad_executor.ipp +40/−0
- link/modules/asio-standalone/asio/include/asio/execution/impl/receiver_invocation_error.ipp +36/−0
- link/modules/asio-standalone/asio/include/asio/execution/invocable_archetype.hpp +71/−0
- link/modules/asio-standalone/asio/include/asio/execution/mapping.hpp +917/−0
- link/modules/asio-standalone/asio/include/asio/execution/occupancy.hpp +178/−0
- link/modules/asio-standalone/asio/include/asio/execution/operation_state.hpp +94/−0
- link/modules/asio-standalone/asio/include/asio/execution/outstanding_work.hpp +721/−0
- link/modules/asio-standalone/asio/include/asio/execution/prefer_only.hpp +327/−0
- link/modules/asio-standalone/asio/include/asio/execution/receiver.hpp +280/−0
- link/modules/asio-standalone/asio/include/asio/execution/receiver_invocation_error.hpp +48/−0
- link/modules/asio-standalone/asio/include/asio/execution/relationship.hpp +720/−0
- link/modules/asio-standalone/asio/include/asio/execution/schedule.hpp +290/−0
- link/modules/asio-standalone/asio/include/asio/execution/scheduler.hpp +86/−0
- link/modules/asio-standalone/asio/include/asio/execution/sender.hpp +311/−0
- link/modules/asio-standalone/asio/include/asio/execution/set_done.hpp +253/−0
- link/modules/asio-standalone/asio/include/asio/execution/set_error.hpp +253/−0
- link/modules/asio-standalone/asio/include/asio/execution/set_value.hpp +486/−0
- link/modules/asio-standalone/asio/include/asio/execution/start.hpp +250/−0
- link/modules/asio-standalone/asio/include/asio/execution/submit.hpp +450/−0
- link/modules/asio-standalone/asio/include/asio/execution_context.hpp +412/−0
- link/modules/asio-standalone/asio/include/asio/executor.hpp +347/−0
- link/modules/asio-standalone/asio/include/asio/executor_work_guard.hpp +287/−0
- link/modules/asio-standalone/asio/include/asio/generic/basic_endpoint.hpp +193/−0
- link/modules/asio-standalone/asio/include/asio/generic/datagram_protocol.hpp +123/−0
- link/modules/asio-standalone/asio/include/asio/generic/detail/endpoint.hpp +133/−0
- link/modules/asio-standalone/asio/include/asio/generic/detail/impl/endpoint.ipp +110/−0
- link/modules/asio-standalone/asio/include/asio/generic/raw_protocol.hpp +121/−0
- link/modules/asio-standalone/asio/include/asio/generic/seq_packet_protocol.hpp +122/−0
- link/modules/asio-standalone/asio/include/asio/generic/stream_protocol.hpp +127/−0
- link/modules/asio-standalone/asio/include/asio/handler_alloc_hook.hpp +104/−0
- link/modules/asio-standalone/asio/include/asio/handler_continuation_hook.hpp +54/−0
- link/modules/asio-standalone/asio/include/asio/handler_invoke_hook.hpp +111/−0
- link/modules/asio-standalone/asio/include/asio/high_resolution_timer.hpp +44/−0
- link/modules/asio-standalone/asio/include/asio/impl/awaitable.hpp +436/−0
- link/modules/asio-standalone/asio/include/asio/impl/buffered_read_stream.hpp +527/−0
- link/modules/asio-standalone/asio/include/asio/impl/buffered_write_stream.hpp +507/−0
- link/modules/asio-standalone/asio/include/asio/impl/co_spawn.hpp +298/−0
- link/modules/asio-standalone/asio/include/asio/impl/compose.hpp +635/−0
- link/modules/asio-standalone/asio/include/asio/impl/connect.hpp +916/−0
- link/modules/asio-standalone/asio/include/asio/impl/defer.hpp +248/−0
- link/modules/asio-standalone/asio/include/asio/impl/detached.hpp +130/−0
- link/modules/asio-standalone/asio/include/asio/impl/dispatch.hpp +243/−0
- link/modules/asio-standalone/asio/include/asio/impl/error.ipp +128/−0
- link/modules/asio-standalone/asio/include/asio/impl/error_code.ipp +206/−0
- link/modules/asio-standalone/asio/include/asio/impl/execution_context.hpp +109/−0
- link/modules/asio-standalone/asio/include/asio/impl/execution_context.ipp +82/−0
- link/modules/asio-standalone/asio/include/asio/impl/executor.hpp +301/−0
- link/modules/asio-standalone/asio/include/asio/impl/executor.ipp +43/−0
- link/modules/asio-standalone/asio/include/asio/impl/handler_alloc_hook.ipp +61/−0
- link/modules/asio-standalone/asio/include/asio/impl/io_context.hpp +440/−0
- link/modules/asio-standalone/asio/include/asio/impl/io_context.ipp +175/−0
- link/modules/asio-standalone/asio/include/asio/impl/multiple_exceptions.ipp +49/−0
- link/modules/asio-standalone/asio/include/asio/impl/post.hpp +248/−0
- link/modules/asio-standalone/asio/include/asio/impl/read.hpp +1202/−0
- link/modules/asio-standalone/asio/include/asio/impl/read_at.hpp +744/−0
- link/modules/asio-standalone/asio/include/asio/impl/read_until.hpp +3335/−0
- link/modules/asio-standalone/asio/include/asio/impl/redirect_error.hpp +390/−0
- link/modules/asio-standalone/asio/include/asio/impl/serial_port_base.hpp +59/−0
- link/modules/asio-standalone/asio/include/asio/impl/serial_port_base.ipp +554/−0
- link/modules/asio-standalone/asio/include/asio/impl/spawn.hpp +526/−0
- link/modules/asio-standalone/asio/include/asio/impl/src.hpp +85/−0
- link/modules/asio-standalone/asio/include/asio/impl/system_context.hpp +34/−0
- link/modules/asio-standalone/asio/include/asio/impl/system_context.ipp +92/−0
- link/modules/asio-standalone/asio/include/asio/impl/system_executor.hpp +186/−0
- link/modules/asio-standalone/asio/include/asio/impl/thread_pool.hpp +350/−0
- link/modules/asio-standalone/asio/include/asio/impl/thread_pool.ipp +141/−0
- link/modules/asio-standalone/asio/include/asio/impl/use_awaitable.hpp +279/−0
- link/modules/asio-standalone/asio/include/asio/impl/use_future.hpp +1028/−0
- link/modules/asio-standalone/asio/include/asio/impl/write.hpp +1104/−0
- link/modules/asio-standalone/asio/include/asio/impl/write_at.hpp +666/−0
- link/modules/asio-standalone/asio/include/asio/io_context.hpp +1530/−0
- link/modules/asio-standalone/asio/include/asio/io_context_strand.hpp +376/−0
- link/modules/asio-standalone/asio/include/asio/io_service.hpp +33/−0
- link/modules/asio-standalone/asio/include/asio/io_service_strand.hpp +20/−0
- link/modules/asio-standalone/asio/include/asio/ip/address.hpp +268/−0
- link/modules/asio-standalone/asio/include/asio/ip/address_v4.hpp +335/−0
- link/modules/asio-standalone/asio/include/asio/ip/address_v4_iterator.hpp +162/−0
- link/modules/asio-standalone/asio/include/asio/ip/address_v4_range.hpp +134/−0
- link/modules/asio-standalone/asio/include/asio/ip/address_v6.hpp +341/−0
- link/modules/asio-standalone/asio/include/asio/ip/address_v6_iterator.hpp +183/−0
- link/modules/asio-standalone/asio/include/asio/ip/address_v6_range.hpp +129/−0
- link/modules/asio-standalone/asio/include/asio/ip/bad_address_cast.hpp +53/−0
- link/modules/asio-standalone/asio/include/asio/ip/basic_endpoint.hpp +264/−0
- link/modules/asio-standalone/asio/include/asio/ip/basic_resolver.hpp +1030/−0
- link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_entry.hpp +113/−0
- link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_iterator.hpp +192/−0
- link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_query.hpp +244/−0
- link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_results.hpp +311/−0
- link/modules/asio-standalone/asio/include/asio/ip/detail/endpoint.hpp +141/−0
- link/modules/asio-standalone/asio/include/asio/ip/detail/impl/endpoint.ipp +199/−0
- link/modules/asio-standalone/asio/include/asio/ip/detail/socket_option.hpp +566/−0
- link/modules/asio-standalone/asio/include/asio/ip/host_name.hpp +42/−0
- link/modules/asio-standalone/asio/include/asio/ip/icmp.hpp +115/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/address.hpp +67/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/address.ipp +239/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/address_v4.hpp +67/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/address_v4.ipp +210/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/address_v6.hpp +67/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/address_v6.ipp +350/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/basic_endpoint.hpp +43/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/host_name.ipp +54/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/network_v4.hpp +54/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/network_v4.ipp +216/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/network_v6.hpp +53/−0
- link/modules/asio-standalone/asio/include/asio/ip/impl/network_v6.ipp +185/−0
- link/modules/asio-standalone/asio/include/asio/ip/multicast.hpp +191/−0
- link/modules/asio-standalone/asio/include/asio/ip/network_v4.hpp +261/−0
- link/modules/asio-standalone/asio/include/asio/ip/network_v6.hpp +235/−0
- link/modules/asio-standalone/asio/include/asio/ip/resolver_base.hpp +129/−0
- link/modules/asio-standalone/asio/include/asio/ip/resolver_query_base.hpp +43/−0
- link/modules/asio-standalone/asio/include/asio/ip/tcp.hpp +155/−0
- link/modules/asio-standalone/asio/include/asio/ip/udp.hpp +111/−0
- link/modules/asio-standalone/asio/include/asio/ip/unicast.hpp +70/−0
- link/modules/asio-standalone/asio/include/asio/ip/v6_only.hpp +69/−0
- link/modules/asio-standalone/asio/include/asio/is_applicable_property.hpp +61/−0
- link/modules/asio-standalone/asio/include/asio/is_executor.hpp +46/−0
- link/modules/asio-standalone/asio/include/asio/is_read_buffered.hpp +59/−0
- link/modules/asio-standalone/asio/include/asio/is_write_buffered.hpp +59/−0
- link/modules/asio-standalone/asio/include/asio/local/basic_endpoint.hpp +247/−0
- link/modules/asio-standalone/asio/include/asio/local/connect_pair.hpp +101/−0
- link/modules/asio-standalone/asio/include/asio/local/datagram_protocol.hpp +80/−0
- link/modules/asio-standalone/asio/include/asio/local/detail/endpoint.hpp +139/−0
- link/modules/asio-standalone/asio/include/asio/local/detail/impl/endpoint.ipp +136/−0
- link/modules/asio-standalone/asio/include/asio/local/stream_protocol.hpp +90/−0
- link/modules/asio-standalone/asio/include/asio/multiple_exceptions.hpp +58/−0
- link/modules/asio-standalone/asio/include/asio/packaged_task.hpp +126/−0
- link/modules/asio-standalone/asio/include/asio/placeholders.hpp +151/−0
- link/modules/asio-standalone/asio/include/asio/posix/basic_descriptor.hpp +697/−0
- link/modules/asio-standalone/asio/include/asio/posix/basic_stream_descriptor.hpp +470/−0
- link/modules/asio-standalone/asio/include/asio/posix/descriptor.hpp +37/−0
- link/modules/asio-standalone/asio/include/asio/posix/descriptor_base.hpp +90/−0
- link/modules/asio-standalone/asio/include/asio/posix/stream_descriptor.hpp +37/−0
- link/modules/asio-standalone/asio/include/asio/post.hpp +126/−0
- link/modules/asio-standalone/asio/include/asio/prefer.hpp +656/−0
- link/modules/asio-standalone/asio/include/asio/query.hpp +296/−0
- link/modules/asio-standalone/asio/include/asio/read.hpp +1288/−0
- link/modules/asio-standalone/asio/include/asio/read_at.hpp +694/−0
- link/modules/asio-standalone/asio/include/asio/read_until.hpp +2863/−0
- link/modules/asio-standalone/asio/include/asio/redirect_error.hpp +66/−0
- link/modules/asio-standalone/asio/include/asio/require.hpp +524/−0
- link/modules/asio-standalone/asio/include/asio/require_concept.hpp +310/−0
- link/modules/asio-standalone/asio/include/asio/serial_port.hpp +36/−0
- link/modules/asio-standalone/asio/include/asio/serial_port_base.hpp +167/−0
- link/modules/asio-standalone/asio/include/asio/signal_set.hpp +28/−0
- link/modules/asio-standalone/asio/include/asio/socket_base.hpp +559/−0
- link/modules/asio-standalone/asio/include/asio/spawn.hpp +344/−0
- link/modules/asio-standalone/asio/include/asio/ssl.hpp +28/−0
- link/modules/asio-standalone/asio/include/asio/ssl/context.hpp +761/−0
- link/modules/asio-standalone/asio/include/asio/ssl/context_base.hpp +209/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/buffered_handshake_op.hpp +119/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/engine.hpp +165/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/handshake_op.hpp +67/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/impl/engine.ipp +349/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/impl/openssl_init.ipp +165/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/io.hpp +415/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/openssl_init.hpp +101/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/openssl_types.hpp +34/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/password_callback.hpp +66/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/read_op.hpp +72/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/shutdown_op.hpp +69/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/stream_core.hpp +169/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/verify_callback.hpp +62/−0
- link/modules/asio-standalone/asio/include/asio/ssl/detail/write_op.hpp +76/−0
- link/modules/asio-standalone/asio/include/asio/ssl/error.hpp +125/−0
- link/modules/asio-standalone/asio/include/asio/ssl/host_name_verification.hpp +90/−0
- link/modules/asio-standalone/asio/include/asio/ssl/impl/context.hpp +67/−0
- link/modules/asio-standalone/asio/include/asio/ssl/impl/context.ipp +1238/−0
- link/modules/asio-standalone/asio/include/asio/ssl/impl/error.ipp +102/−0
- link/modules/asio-standalone/asio/include/asio/ssl/impl/host_name_verification.ipp +73/−0
- link/modules/asio-standalone/asio/include/asio/ssl/impl/rfc2818_verification.ipp +164/−0
- link/modules/asio-standalone/asio/include/asio/ssl/impl/src.hpp +29/−0
- link/modules/asio-standalone/asio/include/asio/ssl/rfc2818_verification.hpp +98/−0
- link/modules/asio-standalone/asio/include/asio/ssl/stream.hpp +900/−0
- link/modules/asio-standalone/asio/include/asio/ssl/stream_base.hpp +52/−0
- link/modules/asio-standalone/asio/include/asio/ssl/verify_context.hpp +67/−0
- link/modules/asio-standalone/asio/include/asio/ssl/verify_mode.hpp +63/−0
- link/modules/asio-standalone/asio/include/asio/static_thread_pool.hpp +31/−0
- link/modules/asio-standalone/asio/include/asio/steady_timer.hpp +42/−0
- link/modules/asio-standalone/asio/include/asio/strand.hpp +537/−0
- link/modules/asio-standalone/asio/include/asio/streambuf.hpp +33/−0
- link/modules/asio-standalone/asio/include/asio/system_context.hpp +90/−0
- link/modules/asio-standalone/asio/include/asio/system_error.hpp +131/−0
- link/modules/asio-standalone/asio/include/asio/system_executor.hpp +662/−0
- link/modules/asio-standalone/asio/include/asio/system_timer.hpp +42/−0
- link/modules/asio-standalone/asio/include/asio/this_coro.hpp +45/−0
- link/modules/asio-standalone/asio/include/asio/thread.hpp +92/−0
- link/modules/asio-standalone/asio/include/asio/thread_pool.hpp +1111/−0
- link/modules/asio-standalone/asio/include/asio/time_traits.hpp +86/−0
- link/modules/asio-standalone/asio/include/asio/traits/bulk_execute_free.hpp +114/−0
- link/modules/asio-standalone/asio/include/asio/traits/bulk_execute_member.hpp +114/−0
- link/modules/asio-standalone/asio/include/asio/traits/connect_free.hpp +112/−0
- link/modules/asio-standalone/asio/include/asio/traits/connect_member.hpp +112/−0
- link/modules/asio-standalone/asio/include/asio/traits/equality_comparable.hpp +100/−0
- link/modules/asio-standalone/asio/include/asio/traits/execute_free.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/execute_member.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/prefer_free.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/prefer_member.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/query_free.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/query_member.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/query_static_constexpr_member.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/require_concept_free.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/require_concept_member.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/require_free.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/require_member.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/schedule_free.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/schedule_member.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/set_done_free.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/set_done_member.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/set_error_free.hpp +112/−0
- link/modules/asio-standalone/asio/include/asio/traits/set_error_member.hpp +112/−0
- link/modules/asio-standalone/asio/include/asio/traits/set_value_free.hpp +234/−0
- link/modules/asio-standalone/asio/include/asio/traits/set_value_member.hpp +234/−0
- link/modules/asio-standalone/asio/include/asio/traits/start_free.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/start_member.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/static_query.hpp +108/−0
- link/modules/asio-standalone/asio/include/asio/traits/static_require.hpp +123/−0
- link/modules/asio-standalone/asio/include/asio/traits/static_require_concept.hpp +123/−0
- link/modules/asio-standalone/asio/include/asio/traits/submit_free.hpp +112/−0
- link/modules/asio-standalone/asio/include/asio/traits/submit_member.hpp +112/−0
- link/modules/asio-standalone/asio/include/asio/ts/buffer.hpp +24/−0
- link/modules/asio-standalone/asio/include/asio/ts/executor.hpp +35/−0
- link/modules/asio-standalone/asio/include/asio/ts/internet.hpp +40/−0
- link/modules/asio-standalone/asio/include/asio/ts/io_context.hpp +20/−0
- link/modules/asio-standalone/asio/include/asio/ts/net.hpp +26/−0
- link/modules/asio-standalone/asio/include/asio/ts/netfwd.hpp +262/−0
- link/modules/asio-standalone/asio/include/asio/ts/socket.hpp +27/−0
- link/modules/asio-standalone/asio/include/asio/ts/timer.hpp +26/−0
- link/modules/asio-standalone/asio/include/asio/unyield.hpp +21/−0
- link/modules/asio-standalone/asio/include/asio/use_awaitable.hpp +169/−0
- link/modules/asio-standalone/asio/include/asio/use_future.hpp +160/−0
- link/modules/asio-standalone/asio/include/asio/uses_executor.hpp +71/−0
- link/modules/asio-standalone/asio/include/asio/version.hpp +23/−0
- link/modules/asio-standalone/asio/include/asio/wait_traits.hpp +56/−0
- link/modules/asio-standalone/asio/include/asio/windows/basic_object_handle.hpp +435/−0
- link/modules/asio-standalone/asio/include/asio/windows/basic_overlapped_handle.hpp +361/−0
- link/modules/asio-standalone/asio/include/asio/windows/basic_random_access_handle.hpp +490/−0
- link/modules/asio-standalone/asio/include/asio/windows/basic_stream_handle.hpp +474/−0
- link/modules/asio-standalone/asio/include/asio/windows/object_handle.hpp +38/−0
- link/modules/asio-standalone/asio/include/asio/windows/overlapped_handle.hpp +39/−0
- link/modules/asio-standalone/asio/include/asio/windows/overlapped_ptr.hpp +145/−0
- link/modules/asio-standalone/asio/include/asio/windows/random_access_handle.hpp +37/−0
- link/modules/asio-standalone/asio/include/asio/windows/stream_handle.hpp +37/−0
- link/modules/asio-standalone/asio/include/asio/write.hpp +1246/−0
- link/modules/asio-standalone/asio/include/asio/write_at.hpp +702/−0
- link/modules/asio-standalone/asio/include/asio/yield.hpp +23/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/chat/chat_message.hpp +93/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server/connection.hpp +83/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server/connection_manager.hpp +44/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server/header.hpp +28/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server/mime_types.hpp +27/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server/reply.hpp +64/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request.hpp +34/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request_handler.hpp +46/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request_parser.hpp +95/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server/server.hpp +69/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/connection.hpp +75/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/header.hpp +28/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/io_context_pool.hpp +56/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/mime_types.hpp +27/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/reply.hpp +64/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request.hpp +34/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request_handler.hpp +46/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request_parser.hpp +95/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/server.hpp +68/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/connection.hpp +78/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/header.hpp +28/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/mime_types.hpp +27/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/reply.hpp +64/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request.hpp +34/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request_handler.hpp +46/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request_parser.hpp +95/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/server.hpp +70/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/file_handler.hpp +44/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/header.hpp +28/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/mime_types.hpp +27/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/reply.hpp +64/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/request.hpp +46/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/request_parser.hpp +78/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/server.hpp +73/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/icmp/icmp_header.hpp +94/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/icmp/ipv4_header.hpp +102/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/porthopper/protocol.hpp +156/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/serialization/connection.hpp +188/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/serialization/stock.hpp +50/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/services/basic_logger.hpp +77/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/services/logger.hpp +24/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/services/logger_service.hpp +145/−0
- link/modules/asio-standalone/asio/src/examples/cpp03/socks4/socks4.hpp +144/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/chat/chat_message.hpp +91/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/handler_tracking/custom_tracking.hpp +211/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/http/server/connection.hpp +79/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/http/server/connection_manager.hpp +48/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/http/server/header.hpp +28/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/http/server/mime_types.hpp +27/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/http/server/reply.hpp +64/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request.hpp +34/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request_handler.hpp +47/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request_parser.hpp +96/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/http/server/server.hpp +64/−0
- link/modules/asio-standalone/asio/src/examples/cpp11/socks4/socks4.hpp +143/−0
- link/modules/asio-standalone/asio/src/tests/latency/allocator.hpp +52/−0
- link/modules/asio-standalone/asio/src/tests/latency/high_res_clock.hpp +53/−0
- link/modules/asio-standalone/asio/src/tests/performance/handler_allocator.hpp +112/−0
- link/modules/asio-standalone/asio/src/tests/unit/archetypes/async_ops.hpp +415/−0
- link/modules/asio-standalone/asio/src/tests/unit/archetypes/async_result.hpp +94/−0
- link/modules/asio-standalone/asio/src/tests/unit/archetypes/gettable_socket_option.hpp +54/−0
- link/modules/asio-standalone/asio/src/tests/unit/archetypes/io_control_command.hpp +32/−0
- link/modules/asio-standalone/asio/src/tests/unit/archetypes/settable_socket_option.hpp +49/−0
- link/modules/asio-standalone/asio/src/tests/unit/unit_test.hpp +190/−0
- link/third_party/catch/catch.hpp +17959/−0
- src/hs/Main.hs +6/−0
- src/hs/Sound/Tidal/Link.hsc +139/−0
- tidal-link.cabal +87/−0
+ LICENSE view
@@ -0,0 +1,674 @@+ GNU GENERAL PUBLIC LICENSE+ Version 3, 29 June 2007++ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++ Preamble++ The GNU General Public License is a free, copyleft license for+software and other kinds of works.++ The licenses for most software and other practical works are designed+to take away your freedom to share and change the works. By contrast,+the GNU General Public License is intended to guarantee your freedom to+share and change all versions of a program--to make sure it remains free+software for all its users. We, the Free Software Foundation, use the+GNU General Public License for most of our software; it applies also to+any other work released this way by its authors. You can apply it to+your programs, too.++ When we speak of free software, we are referring to freedom, not+price. Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+them if you wish), that you receive source code or can get it if you+want it, that you can change the software or use pieces of it in new+free programs, and that you know you can do these things.++ To protect your rights, we need to prevent others from denying you+these rights or asking you to surrender the rights. Therefore, you have+certain responsibilities if you distribute copies of the software, or if+you modify it: responsibilities to respect the freedom of others.++ For example, if you distribute copies of such a program, whether+gratis or for a fee, you must pass on to the recipients the same+freedoms that you received. You must make sure that they, too, receive+or can get the source code. And you must show them these terms so they+know their rights.++ Developers that use the GNU GPL protect your rights with two steps:+(1) assert copyright on the software, and (2) offer you this License+giving you legal permission to copy, distribute and/or modify it.++ For the developers' and authors' protection, the GPL clearly explains+that there is no warranty for this free software. For both users' and+authors' sake, the GPL requires that modified versions be marked as+changed, so that their problems will not be attributed erroneously to+authors of previous versions.++ Some devices are designed to deny users access to install or run+modified versions of the software inside them, although the manufacturer+can do so. This is fundamentally incompatible with the aim of+protecting users' freedom to change the software. The systematic+pattern of such abuse occurs in the area of products for individuals to+use, which is precisely where it is most unacceptable. Therefore, we+have designed this version of the GPL to prohibit the practice for those+products. If such problems arise substantially in other domains, we+stand ready to extend this provision to those domains in future versions+of the GPL, as needed to protect the freedom of users.++ Finally, every program is threatened constantly by software patents.+States should not allow patents to restrict development and use of+software on general-purpose computers, but in those that do, we wish to+avoid the special danger that patents applied to a free program could+make it effectively proprietary. To prevent this, the GPL assures that+patents cannot be used to render the program non-free.++ The precise terms and conditions for copying, distribution and+modification follow.++ TERMS AND CONDITIONS++ 0. Definitions.++ "This License" refers to version 3 of the GNU General Public License.++ "Copyright" also means copyright-like laws that apply to other kinds of+works, such as semiconductor masks.++ "The Program" refers to any copyrightable work licensed under this+License. Each licensee is addressed as "you". "Licensees" and+"recipients" may be individuals or organizations.++ To "modify" a work means to copy from or adapt all or part of the work+in a fashion requiring copyright permission, other than the making of an+exact copy. The resulting work is called a "modified version" of the+earlier work or a work "based on" the earlier work.++ A "covered work" means either the unmodified Program or a work based+on the Program.++ To "propagate" a work means to do anything with it that, without+permission, would make you directly or secondarily liable for+infringement under applicable copyright law, except executing it on a+computer or modifying a private copy. Propagation includes copying,+distribution (with or without modification), making available to the+public, and in some countries other activities as well.++ To "convey" a work means any kind of propagation that enables other+parties to make or receive copies. Mere interaction with a user through+a computer network, with no transfer of a copy, is not conveying.++ An interactive user interface displays "Appropriate Legal Notices"+to the extent that it includes a convenient and prominently visible+feature that (1) displays an appropriate copyright notice, and (2)+tells the user that there is no warranty for the work (except to the+extent that warranties are provided), that licensees may convey the+work under this License, and how to view a copy of this License. If+the interface presents a list of user commands or options, such as a+menu, a prominent item in the list meets this criterion.++ 1. Source Code.++ The "source code" for a work means the preferred form of the work+for making modifications to it. "Object code" means any non-source+form of a work.++ A "Standard Interface" means an interface that either is an official+standard defined by a recognized standards body, or, in the case of+interfaces specified for a particular programming language, one that+is widely used among developers working in that language.++ The "System Libraries" of an executable work include anything, other+than the work as a whole, that (a) is included in the normal form of+packaging a Major Component, but which is not part of that Major+Component, and (b) serves only to enable use of the work with that+Major Component, or to implement a Standard Interface for which an+implementation is available to the public in source code form. A+"Major Component", in this context, means a major essential component+(kernel, window system, and so on) of the specific operating system+(if any) on which the executable work runs, or a compiler used to+produce the work, or an object code interpreter used to run it.++ The "Corresponding Source" for a work in object code form means all+the source code needed to generate, install, and (for an executable+work) run the object code and to modify the work, including scripts to+control those activities. However, it does not include the work's+System Libraries, or general-purpose tools or generally available free+programs which are used unmodified in performing those activities but+which are not part of the work. For example, Corresponding Source+includes interface definition files associated with source files for+the work, and the source code for shared libraries and dynamically+linked subprograms that the work is specifically designed to require,+such as by intimate data communication or control flow between those+subprograms and other parts of the work.++ The Corresponding Source need not include anything that users+can regenerate automatically from other parts of the Corresponding+Source.++ The Corresponding Source for a work in source code form is that+same work.++ 2. Basic Permissions.++ All rights granted under this License are granted for the term of+copyright on the Program, and are irrevocable provided the stated+conditions are met. This License explicitly affirms your unlimited+permission to run the unmodified Program. The output from running a+covered work is covered by this License only if the output, given its+content, constitutes a covered work. This License acknowledges your+rights of fair use or other equivalent, as provided by copyright law.++ You may make, run and propagate covered works that you do not+convey, without conditions so long as your license otherwise remains+in force. You may convey covered works to others for the sole purpose+of having them make modifications exclusively for you, or provide you+with facilities for running those works, provided that you comply with+the terms of this License in conveying all material for which you do+not control copyright. Those thus making or running the covered works+for you must do so exclusively on your behalf, under your direction+and control, on terms that prohibit them from making any copies of+your copyrighted material outside their relationship with you.++ Conveying under any other circumstances is permitted solely under+the conditions stated below. Sublicensing is not allowed; section 10+makes it unnecessary.++ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.++ No covered work shall be deemed part of an effective technological+measure under any applicable law fulfilling obligations under article+11 of the WIPO copyright treaty adopted on 20 December 1996, or+similar laws prohibiting or restricting circumvention of such+measures.++ When you convey a covered work, you waive any legal power to forbid+circumvention of technological measures to the extent such circumvention+is effected by exercising rights under this License with respect to+the covered work, and you disclaim any intention to limit operation or+modification of the work as a means of enforcing, against the work's+users, your or third parties' legal rights to forbid circumvention of+technological measures.++ 4. Conveying Verbatim Copies.++ You may convey verbatim copies of the Program's source code as you+receive it, in any medium, provided that you conspicuously and+appropriately publish on each copy an appropriate copyright notice;+keep intact all notices stating that this License and any+non-permissive terms added in accord with section 7 apply to the code;+keep intact all notices of the absence of any warranty; and give all+recipients a copy of this License along with the Program.++ You may charge any price or no price for each copy that you convey,+and you may offer support or warranty protection for a fee.++ 5. Conveying Modified Source Versions.++ You may convey a work based on the Program, or the modifications to+produce it from the Program, in the form of source code under the+terms of section 4, provided that you also meet all of these conditions:++ a) The work must carry prominent notices stating that you modified+ it, and giving a relevant date.++ b) The work must carry prominent notices stating that it is+ released under this License and any conditions added under section+ 7. This requirement modifies the requirement in section 4 to+ "keep intact all notices".++ c) You must license the entire work, as a whole, under this+ License to anyone who comes into possession of a copy. This+ License will therefore apply, along with any applicable section 7+ additional terms, to the whole of the work, and all its parts,+ regardless of how they are packaged. This License gives no+ permission to license the work in any other way, but it does not+ invalidate such permission if you have separately received it.++ d) If the work has interactive user interfaces, each must display+ Appropriate Legal Notices; however, if the Program has interactive+ interfaces that do not display Appropriate Legal Notices, your+ work need not make them do so.++ A compilation of a covered work with other separate and independent+works, which are not by their nature extensions of the covered work,+and which are not combined with it such as to form a larger program,+in or on a volume of a storage or distribution medium, is called an+"aggregate" if the compilation and its resulting copyright are not+used to limit the access or legal rights of the compilation's users+beyond what the individual works permit. Inclusion of a covered work+in an aggregate does not cause this License to apply to the other+parts of the aggregate.++ 6. Conveying Non-Source Forms.++ You may convey a covered work in object code form under the terms+of sections 4 and 5, provided that you also convey the+machine-readable Corresponding Source under the terms of this License,+in one of these ways:++ a) Convey the object code in, or embodied in, a physical product+ (including a physical distribution medium), accompanied by the+ Corresponding Source fixed on a durable physical medium+ customarily used for software interchange.++ b) Convey the object code in, or embodied in, a physical product+ (including a physical distribution medium), accompanied by a+ written offer, valid for at least three years and valid for as+ long as you offer spare parts or customer support for that product+ model, to give anyone who possesses the object code either (1) a+ copy of the Corresponding Source for all the software in the+ product that is covered by this License, on a durable physical+ medium customarily used for software interchange, for a price no+ more than your reasonable cost of physically performing this+ conveying of source, or (2) access to copy the+ Corresponding Source from a network server at no charge.++ c) Convey individual copies of the object code with a copy of the+ written offer to provide the Corresponding Source. This+ alternative is allowed only occasionally and noncommercially, and+ only if you received the object code with such an offer, in accord+ with subsection 6b.++ d) Convey the object code by offering access from a designated+ place (gratis or for a charge), and offer equivalent access to the+ Corresponding Source in the same way through the same place at no+ further charge. You need not require recipients to copy the+ Corresponding Source along with the object code. If the place to+ copy the object code is a network server, the Corresponding Source+ may be on a different server (operated by you or a third party)+ that supports equivalent copying facilities, provided you maintain+ clear directions next to the object code saying where to find the+ Corresponding Source. Regardless of what server hosts the+ Corresponding Source, you remain obligated to ensure that it is+ available for as long as needed to satisfy these requirements.++ e) Convey the object code using peer-to-peer transmission, provided+ you inform other peers where the object code and Corresponding+ Source of the work are being offered to the general public at no+ charge under subsection 6d.++ A separable portion of the object code, whose source code is excluded+from the Corresponding Source as a System Library, need not be+included in conveying the object code work.++ A "User Product" is either (1) a "consumer product", which means any+tangible personal property which is normally used for personal, family,+or household purposes, or (2) anything designed or sold for incorporation+into a dwelling. In determining whether a product is a consumer product,+doubtful cases shall be resolved in favor of coverage. For a particular+product received by a particular user, "normally used" refers to a+typical or common use of that class of product, regardless of the status+of the particular user or of the way in which the particular user+actually uses, or expects or is expected to use, the product. A product+is a consumer product regardless of whether the product has substantial+commercial, industrial or non-consumer uses, unless such uses represent+the only significant mode of use of the product.++ "Installation Information" for a User Product means any methods,+procedures, authorization keys, or other information required to install+and execute modified versions of a covered work in that User Product from+a modified version of its Corresponding Source. The information must+suffice to ensure that the continued functioning of the modified object+code is in no case prevented or interfered with solely because+modification has been made.++ If you convey an object code work under this section in, or with, or+specifically for use in, a User Product, and the conveying occurs as+part of a transaction in which the right of possession and use of the+User Product is transferred to the recipient in perpetuity or for a+fixed term (regardless of how the transaction is characterized), the+Corresponding Source conveyed under this section must be accompanied+by the Installation Information. But this requirement does not apply+if neither you nor any third party retains the ability to install+modified object code on the User Product (for example, the work has+been installed in ROM).++ The requirement to provide Installation Information does not include a+requirement to continue to provide support service, warranty, or updates+for a work that has been modified or installed by the recipient, or for+the User Product in which it has been modified or installed. Access to a+network may be denied when the modification itself materially and+adversely affects the operation of the network or violates the rules and+protocols for communication across the network.++ Corresponding Source conveyed, and Installation Information provided,+in accord with this section must be in a format that is publicly+documented (and with an implementation available to the public in+source code form), and must require no special password or key for+unpacking, reading or copying.++ 7. Additional Terms.++ "Additional permissions" are terms that supplement the terms of this+License by making exceptions from one or more of its conditions.+Additional permissions that are applicable to the entire Program shall+be treated as though they were included in this License, to the extent+that they are valid under applicable law. If additional permissions+apply only to part of the Program, that part may be used separately+under those permissions, but the entire Program remains governed by+this License without regard to the additional permissions.++ When you convey a copy of a covered work, you may at your option+remove any additional permissions from that copy, or from any part of+it. (Additional permissions may be written to require their own+removal in certain cases when you modify the work.) You may place+additional permissions on material, added by you to a covered work,+for which you have or can give appropriate copyright permission.++ Notwithstanding any other provision of this License, for material you+add to a covered work, you may (if authorized by the copyright holders of+that material) supplement the terms of this License with terms:++ a) Disclaiming warranty or limiting liability differently from the+ terms of sections 15 and 16 of this License; or++ b) Requiring preservation of specified reasonable legal notices or+ author attributions in that material or in the Appropriate Legal+ Notices displayed by works containing it; or++ c) Prohibiting misrepresentation of the origin of that material, or+ requiring that modified versions of such material be marked in+ reasonable ways as different from the original version; or++ d) Limiting the use for publicity purposes of names of licensors or+ authors of the material; or++ e) Declining to grant rights under trademark law for use of some+ trade names, trademarks, or service marks; or++ f) Requiring indemnification of licensors and authors of that+ material by anyone who conveys the material (or modified versions of+ it) with contractual assumptions of liability to the recipient, for+ any liability that these contractual assumptions directly impose on+ those licensors and authors.++ All other non-permissive additional terms are considered "further+restrictions" within the meaning of section 10. If the Program as you+received it, or any part of it, contains a notice stating that it is+governed by this License along with a term that is a further+restriction, you may remove that term. If a license document contains+a further restriction but permits relicensing or conveying under this+License, you may add to a covered work material governed by the terms+of that license document, provided that the further restriction does+not survive such relicensing or conveying.++ If you add terms to a covered work in accord with this section, you+must place, in the relevant source files, a statement of the+additional terms that apply to those files, or a notice indicating+where to find the applicable terms.++ Additional terms, permissive or non-permissive, may be stated in the+form of a separately written license, or stated as exceptions;+the above requirements apply either way.++ 8. Termination.++ You may not propagate or modify a covered work except as expressly+provided under this License. Any attempt otherwise to propagate or+modify it is void, and will automatically terminate your rights under+this License (including any patent licenses granted under the third+paragraph of section 11).++ However, if you cease all violation of this License, then your+license from a particular copyright holder is reinstated (a)+provisionally, unless and until the copyright holder explicitly and+finally terminates your license, and (b) permanently, if the copyright+holder fails to notify you of the violation by some reasonable means+prior to 60 days after the cessation.++ Moreover, your license from a particular copyright holder is+reinstated permanently if the copyright holder notifies you of the+violation by some reasonable means, this is the first time you have+received notice of violation of this License (for any work) from that+copyright holder, and you cure the violation prior to 30 days after+your receipt of the notice.++ Termination of your rights under this section does not terminate the+licenses of parties who have received copies or rights from you under+this License. If your rights have been terminated and not permanently+reinstated, you do not qualify to receive new licenses for the same+material under section 10.++ 9. Acceptance Not Required for Having Copies.++ You are not required to accept this License in order to receive or+run a copy of the Program. Ancillary propagation of a covered work+occurring solely as a consequence of using peer-to-peer transmission+to receive a copy likewise does not require acceptance. However,+nothing other than this License grants you permission to propagate or+modify any covered work. These actions infringe copyright if you do+not accept this License. Therefore, by modifying or propagating a+covered work, you indicate your acceptance of this License to do so.++ 10. Automatic Licensing of Downstream Recipients.++ Each time you convey a covered work, the recipient automatically+receives a license from the original licensors, to run, modify and+propagate that work, subject to this License. You are not responsible+for enforcing compliance by third parties with this License.++ An "entity transaction" is a transaction transferring control of an+organization, or substantially all assets of one, or subdividing an+organization, or merging organizations. If propagation of a covered+work results from an entity transaction, each party to that+transaction who receives a copy of the work also receives whatever+licenses to the work the party's predecessor in interest had or could+give under the previous paragraph, plus a right to possession of the+Corresponding Source of the work from the predecessor in interest, if+the predecessor has it or can get it with reasonable efforts.++ You may not impose any further restrictions on the exercise of the+rights granted or affirmed under this License. For example, you may+not impose a license fee, royalty, or other charge for exercise of+rights granted under this License, and you may not initiate litigation+(including a cross-claim or counterclaim in a lawsuit) alleging that+any patent claim is infringed by making, using, selling, offering for+sale, or importing the Program or any portion of it.++ 11. Patents.++ A "contributor" is a copyright holder who authorizes use under this+License of the Program or a work on which the Program is based. The+work thus licensed is called the contributor's "contributor version".++ A contributor's "essential patent claims" are all patent claims+owned or controlled by the contributor, whether already acquired or+hereafter acquired, that would be infringed by some manner, permitted+by this License, of making, using, or selling its contributor version,+but do not include claims that would be infringed only as a+consequence of further modification of the contributor version. For+purposes of this definition, "control" includes the right to grant+patent sublicenses in a manner consistent with the requirements of+this License.++ Each contributor grants you a non-exclusive, worldwide, royalty-free+patent license under the contributor's essential patent claims, to+make, use, sell, offer for sale, import and otherwise run, modify and+propagate the contents of its contributor version.++ In the following three paragraphs, a "patent license" is any express+agreement or commitment, however denominated, not to enforce a patent+(such as an express permission to practice a patent or covenant not to+sue for patent infringement). To "grant" such a patent license to a+party means to make such an agreement or commitment not to enforce a+patent against the party.++ If you convey a covered work, knowingly relying on a patent license,+and the Corresponding Source of the work is not available for anyone+to copy, free of charge and under the terms of this License, through a+publicly available network server or other readily accessible means,+then you must either (1) cause the Corresponding Source to be so+available, or (2) arrange to deprive yourself of the benefit of the+patent license for this particular work, or (3) arrange, in a manner+consistent with the requirements of this License, to extend the patent+license to downstream recipients. "Knowingly relying" means you have+actual knowledge that, but for the patent license, your conveying the+covered work in a country, or your recipient's use of the covered work+in a country, would infringe one or more identifiable patents in that+country that you have reason to believe are valid.++ If, pursuant to or in connection with a single transaction or+arrangement, you convey, or propagate by procuring conveyance of, a+covered work, and grant a patent license to some of the parties+receiving the covered work authorizing them to use, propagate, modify+or convey a specific copy of the covered work, then the patent license+you grant is automatically extended to all recipients of the covered+work and works based on it.++ A patent license is "discriminatory" if it does not include within+the scope of its coverage, prohibits the exercise of, or is+conditioned on the non-exercise of one or more of the rights that are+specifically granted under this License. You may not convey a covered+work if you are a party to an arrangement with a third party that is+in the business of distributing software, under which you make payment+to the third party based on the extent of your activity of conveying+the work, and under which the third party grants, to any of the+parties who would receive the covered work from you, a discriminatory+patent license (a) in connection with copies of the covered work+conveyed by you (or copies made from those copies), or (b) primarily+for and in connection with specific products or compilations that+contain the covered work, unless you entered into that arrangement,+or that patent license was granted, prior to 28 March 2007.++ Nothing in this License shall be construed as excluding or limiting+any implied license or other defenses to infringement that may+otherwise be available to you under applicable patent law.++ 12. No Surrender of Others' Freedom.++ If conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License. If you cannot convey a+covered work so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you may+not convey it at all. For example, if you agree to terms that obligate you+to collect a royalty for further conveying from those to whom you convey+the Program, the only way you could satisfy both those terms and this+License would be to refrain entirely from conveying the Program.++ 13. Use with the GNU Affero General Public License.++ Notwithstanding any other provision of this License, you have+permission to link or combine any covered work with a work licensed+under version 3 of the GNU Affero General Public License into a single+combined work, and to convey the resulting work. The terms of this+License will continue to apply to the part which is the covered work,+but the special requirements of the GNU Affero General Public License,+section 13, concerning interaction through a network will apply to the+combination as such.++ 14. Revised Versions of this License.++ The Free Software Foundation may publish revised and/or new versions of+the GNU General Public License from time to time. Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++ Each version is given a distinguishing version number. If the+Program specifies that a certain numbered version of the GNU General+Public License "or any later version" applies to it, you have the+option of following the terms and conditions either of that numbered+version or of any later version published by the Free Software+Foundation. If the Program does not specify a version number of the+GNU General Public License, you may choose any version ever published+by the Free Software Foundation.++ If the Program specifies that a proxy can decide which future+versions of the GNU General Public License can be used, that proxy's+public statement of acceptance of a version permanently authorizes you+to choose that version for the Program.++ Later license versions may give you additional or different+permissions. However, no additional obligations are imposed on any+author or copyright holder as a result of your choosing to follow a+later version.++ 15. Disclaimer of Warranty.++ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.++ 16. Limitation of Liability.++ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF+SUCH DAMAGES.++ 17. Interpretation of Sections 15 and 16.++ If the disclaimer of warranty and limitation of liability provided+above cannot be given local legal effect according to their terms,+reviewing courts shall apply local law that most closely approximates+an absolute waiver of all civil liability in connection with the+Program, unless a warranty or assumption of liability accompanies a+copy of the Program in return for a fee.++ END OF TERMS AND CONDITIONS++ How to Apply These Terms to Your New Programs++ If you develop a new program, and you want it to be of the greatest+possible use to the public, the best way to achieve this is to make it+free software which everyone can redistribute and change under these terms.++ To do so, attach the following notices to the program. It is safest+to attach them to the start of each source file to most effectively+state the exclusion of warranty; and each file should have at least+the "copyright" line and a pointer to where the full notice is found.++ <one line to give the program's name and a brief idea of what it does.>+ Copyright (C) <year> <name of author>++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <https://www.gnu.org/licenses/>.++Also add information on how to contact you by electronic and paper mail.++ If the program does terminal interaction, make it output a short+notice like this when it starts in an interactive mode:++ <program> Copyright (C) <year> <name of author>+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+ This is free software, and you are welcome to redistribute it+ under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License. Of course, your program's commands+might be different; for a GUI interface, you would use an "about box".++ You should also get your employer (if you work as a programmer) or school,+if any, to sign a "copyright disclaimer" for the program, if necessary.+For more information on this, and how to apply and follow the GNU GPL, see+<https://www.gnu.org/licenses/>.++ The GNU General Public License does not permit incorporating your program+into proprietary programs. If your program is a subroutine library, you+may consider it more useful to permit linking proprietary applications with+the library. If this is what you want to do, use the GNU Lesser General+Public License instead of this License. But first, please read+<https://www.gnu.org/licenses/why-not-lgpl.html>.
+ README.md view
@@ -0,0 +1,6 @@+# tidal-link++Ableton Link integration for Tidal++Requires fixes to GHC on Windows (see https://gitlab.haskell.org/ghc/ghc/-/issues/20918)+which are available from GHC 9.2.4.
+ link/examples/linkaudio/AudioEngine.hpp view
@@ -0,0 +1,81 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++// Make sure to define this before <cmath> is included for Windows+#define _USE_MATH_DEFINES+#include <ableton/Link.hpp>+#include <atomic>+#include <mutex>++namespace ableton+{+namespace linkaudio+{++class AudioEngine+{+public:+ AudioEngine(Link& link);+ void startPlaying();+ void stopPlaying();+ bool isPlaying() const;+ double beatTime() const;+ void setTempo(double tempo);+ double quantum() const;+ void setQuantum(double quantum);+ bool isStartStopSyncEnabled() const;+ void setStartStopSyncEnabled(bool enabled);++private:+ struct EngineData+ {+ double requestedTempo;+ bool requestStart;+ bool requestStop;+ double quantum;+ bool startStopSyncOn;+ };++ void setBufferSize(std::size_t size);+ void setSampleRate(double sampleRate);+ EngineData pullEngineData();+ void renderMetronomeIntoBuffer(Link::SessionState sessionState,+ double quantum,+ std::chrono::microseconds beginHostTime,+ std::size_t numSamples);+ void audioCallback(const std::chrono::microseconds hostTime, std::size_t numSamples);++ Link& mLink;+ double mSampleRate;+ std::atomic<std::chrono::microseconds> mOutputLatency;+ std::vector<double> mBuffer;+ EngineData mSharedEngineData;+ EngineData mLockfreeEngineData;+ std::chrono::microseconds mTimeAtLastClick;+ bool mIsPlaying;+ std::mutex mEngineDataGuard;++ friend class AudioPlatform;+};+++} // namespace linkaudio+} // namespace ableton
+ link/examples/linkaudio/AudioPlatform.hpp view
@@ -0,0 +1,44 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#if defined(LINKHUT_AUDIO_PLATFORM_ASIO)+#include "AudioPlatform_Asio.hpp"+#endif++#if defined(LINKHUT_AUDIO_PLATFORM_COREAUDIO)+#include "AudioPlatform_CoreAudio.hpp"+#endif++#if defined(LINKHUT_AUDIO_PLATFORM_DUMMY)+#include "AudioPlatform_Dummy.hpp"+#endif++#if defined(LINKHUT_AUDIO_PLATFORM_JACK)+#include "AudioPlatform_Jack.hpp"+#endif++#if defined(LINKHUT_AUDIO_PLATFORM_PORTAUDIO)+#include "AudioPlatform_Portaudio.hpp"+#endif++#if defined(LINKHUT_AUDIO_PLATFORM_WASAPI)+#include "AudioPlatform_Wasapi.hpp"+#endif
+ link/examples/linkaudio/AudioPlatform_Asio.hpp view
@@ -0,0 +1,103 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include "AudioEngine.hpp"++#include <ableton/Link.hpp>+#include <ableton/link/HostTimeFilter.hpp>++#include "asiosys.h" // Should be included before asio.h++#include "asio.h"+#include "asiodrivers.h"++// External functions in the ASIO SDK which aren't declared in the SDK headers+extern AsioDrivers* asioDrivers;+bool loadAsioDriver(char* name);++namespace ableton+{+namespace linkaudio+{++#ifndef LINK_ASIO_DRIVER_NAME+#define LINK_ASIO_DRIVER_NAME "ASIO4ALL v2"+#endif+#ifndef LINK_ASIO_INPUT_CHANNELS+#define LINK_ASIO_INPUT_CHANNELS 0+#endif+#ifndef LINK_ASIO_OUTPUT_CHANNELS+#define LINK_ASIO_OUTPUT_CHANNELS 2+#endif++struct DriverInfo+{+ ASIODriverInfo driverInfo;+ long inputChannels;+ long outputChannels;+ long preferredSize;+ ASIOSampleRate sampleRate;+ bool outputReady;+ long numBuffers;+ ASIOBufferInfo bufferInfos[LINK_ASIO_INPUT_CHANNELS + LINK_ASIO_OUTPUT_CHANNELS];+ ASIOChannelInfo channelInfos[LINK_ASIO_INPUT_CHANNELS + LINK_ASIO_OUTPUT_CHANNELS];+};++// Helper functions++// Convenience function to print out an ASIO error code along with the function called+void fatalError(const ASIOError result, const std::string& function);+double asioSamplesToDouble(const ASIOSamples& samples);++ASIOTime* bufferSwitchTimeInfo(ASIOTime* timeInfo, long index, ASIOBool);+void bufferSwitch(long index, ASIOBool processNow);++class AudioPlatform+{+public:+ AudioPlatform(Link& link);+ ~AudioPlatform();++ void audioCallback(ASIOTime* timeInfo, long index);++ AudioEngine mEngine;++ // Unfortunately, the ASIO SDK does not allow passing void* user data to callback+ // functions, so we need to keep a singleton instance of the audio engine+ static AudioPlatform* singleton();+ static void setSingleton(AudioPlatform* platform);++private:+ void createAsioBuffers();+ void initializeDriverInfo();+ void initialize();+ void start();+ void stop();++ DriverInfo mDriverInfo;+ ASIOCallbacks mAsioCallbacks;+ link::HostTimeFilter<platforms::windows::Clock> mHostTimeFilter;++ static AudioPlatform* _singleton;+};++} // namespace linkaudio+} // namespace ableton
+ link/examples/linkaudio/AudioPlatform_CoreAudio.hpp view
@@ -0,0 +1,54 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include "AudioEngine.hpp"+#include <AudioToolbox/AudioToolbox.h>++namespace ableton+{+namespace linkaudio+{++class AudioPlatform+{+public:+ AudioPlatform(Link& link);+ ~AudioPlatform();+ AudioEngine mEngine;++private:+ static OSStatus audioCallback(void* inRefCon,+ AudioUnitRenderActionFlags*,+ const AudioTimeStamp* inTimeStamp,+ UInt32,+ UInt32 inNumberFrames,+ AudioBufferList* ioData);++ void initialize();+ void uninitialize();+ void start();+ void stop();++ AudioUnit mIoUnit;+};++} // namespace linkaudio+} // namespace ableton
+ link/examples/linkaudio/AudioPlatform_Dummy.hpp view
@@ -0,0 +1,112 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/Link.hpp>++namespace ableton+{+namespace linkaudio+{++class AudioPlatform+{+ class AudioEngine+ {+ public:+ AudioEngine(Link& link)+ : mLink(link)+ , mQuantum(4.)+ {+ }++ void startPlaying()+ {+ auto sessionState = mLink.captureAppSessionState();+ sessionState.setIsPlayingAndRequestBeatAtTime(true, now(), 0., mQuantum);+ mLink.commitAppSessionState(sessionState);+ }++ void stopPlaying()+ {+ auto sessionState = mLink.captureAppSessionState();+ sessionState.setIsPlaying(false, now());+ mLink.commitAppSessionState(sessionState);+ }++ bool isPlaying() const+ {+ return mLink.captureAppSessionState().isPlaying();+ }++ double beatTime() const+ {+ auto sessionState = mLink.captureAppSessionState();+ return sessionState.beatAtTime(now(), mQuantum);+ }++ void setTempo(double tempo)+ {+ auto sessionState = mLink.captureAppSessionState();+ sessionState.setTempo(tempo, now());+ mLink.commitAppSessionState(sessionState);+ }++ double quantum() const+ {+ return mQuantum;+ }++ void setQuantum(double quantum)+ {+ mQuantum = quantum;+ }++ bool isStartStopSyncEnabled() const+ {+ return mLink.isStartStopSyncEnabled();+ }++ void setStartStopSyncEnabled(bool enabled)+ {+ mLink.enableStartStopSync(enabled);+ }++ private:+ std::chrono::microseconds now() const+ {+ return mLink.clock().micros();+ }++ Link& mLink;+ double mQuantum;+ };++public:+ AudioPlatform(Link& link)+ : mEngine(link)+ {+ }++ AudioEngine mEngine;+};++} // namespace linkaudio+} // namespace ableton
+ link/examples/linkaudio/AudioPlatform_Jack.hpp view
@@ -0,0 +1,58 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include "AudioEngine.hpp"+#include <ableton/link/HostTimeFilter.hpp>+#include <ableton/platforms/Config.hpp>+#include <jack/jack.h>++namespace ableton+{+namespace linkaudio+{++class AudioPlatform+{+public:+ AudioPlatform(Link& link);+ ~AudioPlatform();++ AudioEngine mEngine;++private:+ static int audioCallback(jack_nframes_t nframes, void* pvUserData);+ int audioCallback(jack_nframes_t nframes);+ static void latencyCallback(jack_latency_callback_mode_t mode, void* pvUserData);+ void updateLatency();++ void initialize();+ void uninitialize();+ void start();+ void stop();++ link::HostTimeFilter<link::platform::Clock> mHostTimeFilter;+ double mSampleTime;+ jack_client_t* mpJackClient;+ jack_port_t** mpJackPorts;+};++} // namespace linkaudio+} // namespace ableton
+ link/examples/linkaudio/AudioPlatform_Portaudio.hpp view
@@ -0,0 +1,59 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include "AudioEngine.hpp"+#include <ableton/link/HostTimeFilter.hpp>+#include <ableton/platforms/Config.hpp>+#include <portaudio.h>++namespace ableton+{+namespace linkaudio+{++class AudioPlatform+{+public:+ AudioPlatform(Link& link);+ ~AudioPlatform();++ AudioEngine mEngine;++private:+ static int audioCallback(const void* inputBuffer,+ void* outputBuffer,+ unsigned long inNumFrames,+ const PaStreamCallbackTimeInfo* timeInfo,+ PaStreamCallbackFlags statusFlags,+ void* userData);++ void initialize();+ void uninitialize();+ void start();+ void stop();++ link::HostTimeFilter<link::platform::Clock> mHostTimeFilter;+ double mSampleTime;+ PaStream* pStream;+};++} // namespace linkaudio+} // namespace ableton
+ link/examples/linkaudio/AudioPlatform_Wasapi.hpp view
@@ -0,0 +1,72 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include "AudioEngine.hpp"+#include <Audioclient.h>+#include <Mmdeviceapi.h>+#include <ableton/link/HostTimeFilter.hpp>+#include <atomic>++// WARNING: This file provides an audio driver for Windows using WASAPI. This driver is+// considered experimental and has problems with low-latency playback. Please consider+// using the ASIO driver instead.++namespace ableton+{+namespace linkaudio+{++// Convenience function to look up the human-readable WinAPI error code, print it out,+// and then terminate the application.+void fatalError(HRESULT result, LPCTSTR context);++DWORD renderAudioRunloop(LPVOID);++class AudioPlatform+{+public:+ AudioPlatform(Link& link);+ ~AudioPlatform();++ DWORD audioRunloop();++ AudioEngine mEngine;++private:+ UINT32 bufferSize();++ void initialize();+ void start();++ link::HostTimeFilter<platforms::windows::Clock> mHostTimeFilter;+ double mSampleTime;++ IMMDevice* mDevice;+ IAudioClient* mAudioClient;+ IAudioRenderClient* mRenderClient;+ WAVEFORMATEX* mStreamFormat;+ HANDLE mEventHandle;+ HANDLE mAudioThreadHandle;+ std::atomic<bool> mIsRunning;+};++} // namespace linkaudio+} // namespace ableton
+ link/extensions/abl_link/include/abl_link.h view
@@ -0,0 +1,352 @@+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#include <stdbool.h>+#include <stdint.h>++#ifdef __cplusplus+extern "C"+{+#endif // __cplusplus++ /*!+ * @discussion Each abl_link instance has its own session state which+ * represents a beat timeline and a transport start/stop state. The+ * timeline starts running from beat 0 at the initial tempo when+ * constructed. The timeline always advances at a speed defined by+ * its current tempo, even if transport is stopped. Synchronizing to the+ * transport start/stop state of Link is optional for every peer.+ * The transport start/stop state is only shared with other peers when+ * start/stop synchronization is enabled.+ *+ * An abl_link instance is initially disabled after construction, which+ * means that it will not communicate on the network. Once enabled,+ * an abl_link instance initiates network communication in an effort to+ * discover other peers. When peers are discovered, they immediately+ * become part of a shared Link session.+ *+ * Each function documents its thread-safety and+ * realtime-safety properties. When a function is marked thread-safe,+ * it means it is safe to call from multiple threads+ * concurrently. When a function is marked realtime-safe, it means that+ * it does not block and is appropriate for use in the thread that+ * performs audio IO.+ *+ * One session state capture/commit function pair for use+ * in the audio thread and one for all other application contexts is provided.+ * In general, modifying the session state should be done in the audio+ * thread for the most accurate timing results. The ability to modify+ * the session state from application threads should only be used in+ * cases where an application's audio thread is not actively running+ * or if it doesn't generate audio at all. Modifying the Link session+ * state from both the audio thread and an application thread+ * concurrently is not advised and will potentially lead to unexpected+ * behavior.+ */++ /*! @brief The representation of an abl_link instance*/+ typedef struct abl_link+ {+ void *impl;+ } abl_link;++ /*! @brief Construct a new abl_link instance with an initial tempo.+ * Thread-safe: yes+ * Realtime-safe: no+ */+ abl_link abl_link_create(double bpm);++ /*! @brief Delete an abl_link instance.+ * Thread-safe: yes+ * Realtime-safe: no+ */+ void abl_link_destroy(abl_link link);++ /*! @brief Is Link currently enabled?+ * Thread-safe: yes+ * Realtime-safe: yes+ */+ bool abl_link_is_enabled(abl_link link);++ /*! @brief Enable/disable Link.+ * Thread-safe: yes+ * Realtime-safe: no+ */+ void abl_link_enable(abl_link link, bool enable);++ /*! @brief: Is start/stop synchronization enabled?+ * Thread-safe: yes+ * Realtime-safe: no+ */+ bool abl_link_is_start_stop_sync_enabled(abl_link link);++ /*! @brief: Enable start/stop synchronization.+ * Thread-safe: yes+ * Realtime-safe: no+ */+ void abl_link_enable_start_stop_sync(abl_link link, bool enabled);++ /*! @brief How many peers are currently connected in a Link session?+ * Thread-safe: yes+ * Realtime-safe: yes+ */+ uint64_t abl_link_num_peers(abl_link link);++ /*! @brief Register a callback to be notified when the number of+ * peers in the Link session changes.+ * Thread-safe: yes+ * Realtime-safe: no+ *+ * @discussion The callback is invoked on a Link-managed thread.+ */+ typedef void (*abl_link_num_peers_callback)(uint64_t num_peers, void *context);+ void abl_link_set_num_peers_callback(+ abl_link link, abl_link_num_peers_callback callback, void *context);++ /*! @brief Register a callback to be notified when the session+ * tempo changes.+ * Thread-safe: yes+ * Realtime-safe: no+ *+ * @discussion The callback is invoked on a Link-managed thread.+ */+ typedef void (*abl_link_tempo_callback)(double tempo, void *context);+ void abl_link_set_tempo_callback(+ abl_link link, abl_link_tempo_callback callback, void *context);++ /*! brief: Register a callback to be notified when the state of+ * start/stop isPlaying changes.+ * Thread-safe: yes+ * Realtime-safe: no+ *+ * @discussion The callback is invoked on a Link-managed thread.+ */+ typedef void (*abl_link_start_stop_callback)(bool is_playing, void *context);+ void abl_link_set_start_stop_callback(+ abl_link link, abl_link_start_stop_callback callback, void *context);++ /*! brief: Get the current link clock time in microseconds.+ * Thread-safe: yes+ * Realtime-safe: yes+ */+ int64_t abl_link_clock_micros(abl_link link);++ /*! @brief The representation of the current local state of a client in a Link Session+ *+ * @discussion A session state represents a timeline and the start/stop+ * state. The timeline is a representation of a mapping between time and+ * beats for varying quanta. The start/stop state represents the user+ * intention to start or stop transport at a specific time. Start stop+ * synchronization is an optional feature that allows to share the user+ * request to start or stop transport between a subgroup of peers in a+ * Link session. When observing a change of start/stop state, audio+ * playback of a peer should be started or stopped the same way it would+ * have happened if the user had requested that change at the according+ * time locally. The start/stop state can only be changed by the user.+ * This means that the current local start/stop state persists when+ * joining or leaving a Link session. After joining a Link session+ * start/stop change requests will be communicated to all connected peers.+ */+ typedef struct abl_link_session_state+ {+ void *impl;+ } abl_link_session_state;++ /*! @brief Create a new session_state instance.+ * Thread-safe: yes+ * Realtime-safe: no+ *+ * @discussion The session_state is to be used with the abl_link_capture... and+ * abl_link_commit... functions to capture snapshots of the current link state and pass+ * changes to the link session.+ */+ abl_link_session_state abl_link_create_session_state(void);++ /*! @brief Delete a session_state instance.+ * Thread-safe: yes+ * Realtime-safe: no+ */+ void abl_link_destroy_session_state(abl_link_session_state abl_link_session_state);++ /*! @brief Capture the current Link Session State from the audio thread.+ * Thread-safe: no+ * Realtime-safe: yes+ *+ * @discussion This function should ONLY be called in the audio thread and must not be+ * accessed from any other threads. After capturing the session_state holds a snapshot+ * of the current Link Session State, so it should be used in a local scope. The+ * session_state should not be created on the audio thread.+ */+ void abl_link_capture_audio_session_state(+ abl_link link, abl_link_session_state session_state);++ /*! @brief Commit the given Session State to the Link session from the+ * audio thread.+ * Thread-safe: no+ * Realtime-safe: yes+ *+ * @discussion This function should ONLY be called in the audio thread. The given+ * session_state will replace the current Link state. Modifications will be+ * communicated to other peers in the session.+ */+ void abl_link_commit_audio_session_state(+ abl_link link, abl_link_session_state session_state);++ /*! @brief Capture the current Link Session State from an application thread.+ * Thread-safe: no+ * Realtime-safe: yes+ *+ * @discussion Provides a mechanism for capturing the Link Session State from an+ * application thread (other than the audio thread). After capturing the session_state+ * contains a snapshot of the current Link state, so it should be used in a local+ * scope.+ */+ void abl_link_capture_app_session_state(+ abl_link link, abl_link_session_state session_state);++ /*! @brief Commit the given Session State to the Link session from an+ * application thread.+ * Thread-safe: yes+ * Realtime-safe: no+ *+ * @discussion The given session_state will replace the current Link Session State.+ * Modifications of the Session State will be communicated to other peers in the+ * session.+ */+ void abl_link_commit_app_session_state(+ abl_link link, abl_link_session_state session_state);++ /*! @brief: The tempo of the timeline, in Beats Per Minute.+ *+ * @discussion This is a stable value that is appropriate for display to the user. Beat+ * time progress will not necessarily match this tempo exactly because of clock drift+ * compensation.+ */+ double abl_link_tempo(abl_link_session_state session_state);++ /*! @brief: Set the timeline tempo to the given bpm value, taking effect at the given+ * time.+ */+ void abl_link_set_tempo(+ abl_link_session_state session_state, double bpm, int64_t at_time);++ /*! @brief: Get the beat value corresponding to the given time for the given quantum.+ *+ * @discussion: The magnitude of the resulting beat value is unique to this Link+ * client, but its phase with respect to the provided quantum is shared among all+ * session peers. For non-negative beat values, the following property holds:+ * fmod(beatAtTime(t, q), q) == phaseAtTime(t, q)+ */+ double abl_link_beat_at_time(+ abl_link_session_state session_state, int64_t time, double quantum);++ /*! @brief: Get the session phase at the given time for the given quantum.+ *+ * @discussion: The result is in the interval [0, quantum). The result is equivalent to+ * fmod(beatAtTime(t, q), q) for non-negative beat values. This function is convenient+ * if the client application is only interested in the phase and not the beat+ * magnitude. Also, unlike fmod, it handles negative beat values correctly.+ */+ double abl_link_phase_at_time(+ abl_link_session_state session_state, int64_t time, double quantum);++ /*! @brief: Get the time at which the given beat occurs for the given quantum.+ *+ * @discussion: The inverse of beatAtTime, assuming a constant tempo.+ * beatAtTime(timeAtBeat(b, q), q) === b.+ */+ int64_t abl_link_time_at_beat(+ abl_link_session_state session_state, double beat, double quantum);++ /*! @brief: Attempt to map the given beat to the given time in the context of the given+ * quantum.+ *+ * @discussion: This function behaves differently depending on the state of the+ * session. If no other peers are connected, then this abl_link instance is in a+ * session by itself and is free to re-map the beat/time relationship whenever it+ * pleases. In this case, beatAtTime(time, quantum) == beat after this funtion has been+ * called.+ *+ * If there are other peers in the session, this abl_link instance should not abruptly+ * re-map the beat/time relationship in the session because that would lead to beat+ * discontinuities among the other peers. In this case, the given beat will be mapped+ * to the next time value greater than the given time with the same phase as the given+ * beat.+ *+ * This function is specifically designed to enable the concept of "quantized launch"+ * in client applications. If there are no other peers in the session, then an event+ * (such as starting transport) happens immediately when it is requested. If there are+ * other peers, however, we wait until the next time at which the session phase matches+ * the phase of the event, thereby executing the event in-phase with the other peers in+ * the session. The client application only needs to invoke this function to achieve+ * this behavior and should not need to explicitly check the number of peers.+ */+ void abl_link_request_beat_at_time(+ abl_link_session_state session_state, double beat, int64_t time, double quantum);++ /*! @brief: Rudely re-map the beat/time relationship for all peers in a session.+ *+ * @discussion: DANGER: This function should only be needed in certain special+ * circumstances. Most applications should not use it. It is very similar to+ * requestBeatAtTime except that it does not fall back to the quantizing behavior when+ * it is in a session with other peers. Calling this function will unconditionally map+ * the given beat to the given time and broadcast the result to the session. This is+ * very anti-social behavior and should be avoided.+ *+ * One of the few legitimate uses of this function is to synchronize a Link session+ * with an external clock source. By periodically forcing the beat/time mapping+ * according to an external clock source, a peer can effectively bridge that clock into+ * a Link session. Much care must be taken at the application layer when implementing+ * such a feature so that users do not accidentally disrupt Link sessions that they may+ * join.+ */+ void abl_link_force_beat_at_time(+ abl_link_session_state session_state, double beat, uint64_t time, double quantum);++ /*! @brief: Set if transport should be playing or stopped, taking effect at the given+ * time.+ */+ void abl_link_set_is_playing(+ abl_link_session_state session_state, bool is_playing, uint64_t time);++ /*! @brief: Is transport playing? */+ bool abl_link_is_playing(abl_link_session_state session_state);++ /*! @brief: Get the time at which a transport start/stop occurs */+ uint64_t abl_link_time_for_is_playing(abl_link_session_state session_state);++ /*! @brief: Convenience function to attempt to map the given beat to the time+ * when transport is starting to play in context of the given quantum.+ * This function evaluates to a no-op if abl_link_is_playing equals false.+ */+ void abl_link_request_beat_at_start_playing_time(+ abl_link_session_state session_state, double beat, double quantum);++ /*! @brief: Convenience function to start or stop transport at a given time and attempt+ * to map the given beat to this time in context of the given quantum. */+ void abl_link_set_is_playing_and_request_beat_at_time(+ abl_link_session_state session_state,+ bool is_playing,+ uint64_t time,+ double beat,+ double quantum);++#ifdef __cplusplus+} // extern "C"+#endif // __cplusplus
+ link/extensions/abl_link/src/abl_link.cpp view
@@ -0,0 +1,214 @@+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#include <abl_link.h>+#include <ableton/Link.hpp>++extern "C"+{+ abl_link abl_link_create(double bpm)+ {+ return abl_link{reinterpret_cast<void *>(new ableton::Link(bpm))};+ }++ void abl_link_destroy(abl_link link)+ {+ delete reinterpret_cast<ableton::Link *>(link.impl);+ }++ bool abl_link_is_enabled(abl_link link)+ {+ return reinterpret_cast<ableton::Link *>(link.impl)->isEnabled();+ }++ void abl_link_enable(abl_link link, bool enabled)+ {+ reinterpret_cast<ableton::Link *>(link.impl)->enable(enabled);+ }++ bool abl_link_is_start_stop_sync_enabled(abl_link link)+ {+ return reinterpret_cast<ableton::Link *>(link.impl)->isStartStopSyncEnabled();+ }++ void abl_link_enable_start_stop_sync(abl_link link, bool enabled)+ {+ reinterpret_cast<ableton::Link *>(link.impl)->enableStartStopSync(enabled);+ }++ uint64_t abl_link_num_peers(abl_link link)+ {+ return reinterpret_cast<ableton::Link *>(link.impl)->numPeers();+ }++ void abl_link_set_num_peers_callback(+ abl_link link, abl_link_num_peers_callback callback, void *context)+ {+ reinterpret_cast<ableton::Link *>(link.impl)->setNumPeersCallback(+ [callback, context](+ std::size_t numPeers) { (*callback)(static_cast<uint64_t>(numPeers), context); });+ }++ void abl_link_set_tempo_callback(+ abl_link link, abl_link_tempo_callback callback, void *context)+ {+ reinterpret_cast<ableton::Link *>(link.impl)->setTempoCallback(+ [callback, context](double tempo) { (*callback)(tempo, context); });+ }++ void abl_link_set_start_stop_callback(+ abl_link link, abl_link_start_stop_callback callback, void *context)+ {+ reinterpret_cast<ableton::Link *>(link.impl)->setStartStopCallback(+ [callback, context](bool isPlaying) { (*callback)(isPlaying, context); });+ }++ int64_t abl_link_clock_micros(abl_link link)+ {+ return reinterpret_cast<ableton::Link *>(link.impl)->clock().micros().count();+ }++ abl_link_session_state abl_link_create_session_state(void)+ {+ return abl_link_session_state{reinterpret_cast<void *>(+ new ableton::Link::SessionState{ableton::link::ApiState{}, {}})};+ }++ void abl_link_destroy_session_state(abl_link_session_state session_state)+ {+ delete reinterpret_cast<ableton::Link::SessionState *>(session_state.impl);+ }++ void abl_link_capture_app_session_state(+ abl_link link, abl_link_session_state session_state)+ {+ *reinterpret_cast<ableton::Link::SessionState *>(session_state.impl) =+ reinterpret_cast<ableton::Link *>(link.impl)->captureAppSessionState();+ }++ void abl_link_commit_app_session_state(+ abl_link link, abl_link_session_state session_state)+ {+ reinterpret_cast<ableton::Link *>(link.impl)->commitAppSessionState(+ *reinterpret_cast<ableton::Link::SessionState *>(session_state.impl));+ }++ void abl_link_capture_audio_session_state(+ abl_link link, abl_link_session_state session_state)+ {+ *reinterpret_cast<ableton::Link::SessionState *>(session_state.impl) =+ reinterpret_cast<ableton::Link *>(link.impl)->captureAudioSessionState();+ }++ void abl_link_commit_audio_session_state(+ abl_link link, abl_link_session_state session_state)+ {+ reinterpret_cast<ableton::Link *>(link.impl)->commitAudioSessionState(+ *reinterpret_cast<ableton::Link::SessionState *>(session_state.impl));+ }++ double abl_link_tempo(abl_link_session_state session_state)+ {+ return reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)->tempo();+ }++ void abl_link_set_tempo(+ abl_link_session_state session_state, double bpm, int64_t at_time)+ {+ reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)+ ->setTempo(bpm, std::chrono::microseconds{at_time});+ }++ double abl_link_beat_at_time(+ abl_link_session_state session_state, int64_t time, double quantum)+ {+ auto micros = std::chrono::microseconds{time};+ return reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)+ ->beatAtTime(micros, quantum);+ }++ double abl_link_phase_at_time(+ abl_link_session_state session_state, int64_t time, double quantum)+ {+ return reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)+ ->phaseAtTime(std::chrono::microseconds{time}, quantum);+ }++ int64_t abl_link_time_at_beat(+ abl_link_session_state session_state, double beat, double quantum)+ {+ return reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)+ ->timeAtBeat(beat, quantum)+ .count();+ }++ void abl_link_request_beat_at_time(+ abl_link_session_state session_state, double beat, int64_t time, double quantum)+ {+ reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)+ ->requestBeatAtTime(beat, std::chrono::microseconds{time}, quantum);+ }++ void abl_link_force_beat_at_time(+ abl_link_session_state session_state, double beat, uint64_t time, double quantum)+ {+ reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)+ ->forceBeatAtTime(beat, std::chrono::microseconds{time}, quantum);+ }++ void abl_link_set_is_playing(+ abl_link_session_state session_state, bool is_playing, uint64_t time)+ {+ reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)+ ->setIsPlaying(is_playing, std::chrono::microseconds(time));+ }++ bool abl_link_is_playing(abl_link_session_state session_state)+ {+ return reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)+ ->isPlaying();+ }++ uint64_t abl_link_time_for_is_playing(abl_link_session_state session_state)+ {+ return static_cast<uint64_t>(+ reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)+ ->timeForIsPlaying()+ .count());+ }++ void abl_link_request_beat_at_start_playing_time(+ abl_link_session_state session_state, double beat, double quantum)+ {+ reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)+ ->requestBeatAtStartPlayingTime(beat, quantum);+ }++ void abl_link_set_is_playing_and_request_beat_at_time(+ abl_link_session_state session_state,+ bool is_playing,+ uint64_t time,+ double beat,+ double quantum)+ {+ reinterpret_cast<ableton::Link::SessionState *>(session_state.impl)+ ->setIsPlayingAndRequestBeatAtTime(+ is_playing, std::chrono::microseconds{time}, beat, quantum);+ }+}
+ link/include/ableton/Link.hpp view
@@ -0,0 +1,403 @@+/*! @file Link.hpp+ * @copyright 2016, Ableton AG, Berlin. All rights reserved.+ * @brief Library for cross-device shared tempo and quantized beat grid+ *+ * @license:+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/platforms/Config.hpp>+#include <chrono>+#include <mutex>++namespace ableton+{++/*! @class Link and BasicLink+ * @brief Classes representing a participant in a Link session.+ * The BasicLink type allows to customize the clock. The Link type+ * uses the recommended platform-dependent representation of the+ * system clock as defined in platforms/Config.hpp.+ * It's preferred to use Link instead of BasicLink.+ *+ * @discussion Each Link instance has its own session state which+ * represents a beat timeline and a transport start/stop state. The+ * timeline starts running from beat 0 at the initial tempo when+ * constructed. The timeline always advances at a speed defined by+ * its current tempo, even if transport is stopped. Synchronizing to the+ * transport start/stop state of Link is optional for every peer.+ * The transport start/stop state is only shared with other peers when+ * start/stop synchronization is enabled.+ *+ * A Link instance is initially disabled after construction, which+ * means that it will not communicate on the network. Once enabled,+ * a Link instance initiates network communication in an effort to+ * discover other peers. When peers are discovered, they immediately+ * become part of a shared Link session.+ *+ * Each method of the Link type documents its thread-safety and+ * realtime-safety properties. When a method is marked thread-safe,+ * it means it is safe to call from multiple threads+ * concurrently. When a method is marked realtime-safe, it means that+ * it does not block and is appropriate for use in the thread that+ * performs audio IO.+ *+ * Link provides one session state capture/commit method pair for use+ * in the audio thread and one for all other application contexts. In+ * general, modifying the session state should be done in the audio+ * thread for the most accurate timing results. The ability to modify+ * the session state from application threads should only be used in+ * cases where an application's audio thread is not actively running+ * or if it doesn't generate audio at all. Modifying the Link session+ * state from both the audio thread and an application thread+ * concurrently is not advised and will potentially lead to unexpected+ * behavior.+ *+ * Only use the BasicLink class if the default platform clock does not+ * fulfill other requirements of the client application. Please note this+ * will require providing a custom Clock implementation. See the clock()+ * documentation for details.+ */+template <typename Clock>+class BasicLink+{+public:+ class SessionState;++ /*! @brief Construct with an initial tempo. */+ BasicLink(double bpm);++ /*! @brief Link instances cannot be copied or moved */+ BasicLink(const BasicLink<Clock>&) = delete;+ BasicLink& operator=(const BasicLink<Clock>&) = delete;+ BasicLink(BasicLink<Clock>&&) = delete;+ BasicLink& operator=(BasicLink<Clock>&&) = delete;++ /*! @brief Is Link currently enabled?+ * Thread-safe: yes+ * Realtime-safe: yes+ */+ bool isEnabled() const;++ /*! @brief Enable/disable Link.+ * Thread-safe: yes+ * Realtime-safe: no+ */+ void enable(bool bEnable);++ /*! @brief: Is start/stop synchronization enabled?+ * Thread-safe: yes+ * Realtime-safe: no+ */+ bool isStartStopSyncEnabled() const;++ /*! @brief: Enable start/stop synchronization.+ * Thread-safe: yes+ * Realtime-safe: no+ */+ void enableStartStopSync(bool bEnable);++ /*! @brief How many peers are currently connected in a Link session?+ * Thread-safe: yes+ * Realtime-safe: yes+ */+ std::size_t numPeers() const;++ /*! @brief Register a callback to be notified when the number of+ * peers in the Link session changes.+ * Thread-safe: yes+ * Realtime-safe: no+ *+ * @discussion The callback is invoked on a Link-managed thread.+ *+ * @param callback The callback signature is:+ * void (std::size_t numPeers)+ */+ template <typename Callback>+ void setNumPeersCallback(Callback callback);++ /*! @brief Register a callback to be notified when the session+ * tempo changes.+ * Thread-safe: yes+ * Realtime-safe: no+ *+ * @discussion The callback is invoked on a Link-managed thread.+ *+ * @param callback The callback signature is: void (double bpm)+ */+ template <typename Callback>+ void setTempoCallback(Callback callback);++ /*! brief: Register a callback to be notified when the state of+ * start/stop isPlaying changes.+ * Thread-safe: yes+ * Realtime-safe: no+ *+ * @discussion The callback is invoked on a Link-managed thread.+ *+ * @param callback The callback signature is:+ * void (bool isPlaying)+ */+ template <typename Callback>+ void setStartStopCallback(Callback callback);++ /*! @brief The clock used by Link.+ * Thread-safe: yes+ * Realtime-safe: yes+ *+ * @discussion The Clock type is a platform-dependent representation+ * of the system clock. It exposes a micros() method, which is a+ * normalized representation of the current system time in+ * std::chrono::microseconds.+ */+ Clock clock() const;++ /*! @brief Capture the current Link Session State from the audio thread.+ * Thread-safe: no+ * Realtime-safe: yes+ *+ * @discussion This method should ONLY be called in the audio thread+ * and must not be accessed from any other threads. The returned+ * object stores a snapshot of the current Link Session State, so it+ * should be captured and used in a local scope. Storing the+ * Session State for later use in a different context is not advised+ * because it will provide an outdated view.+ */+ SessionState captureAudioSessionState() const;++ /*! @brief Commit the given Session State to the Link session from the+ * audio thread.+ * Thread-safe: no+ * Realtime-safe: yes+ *+ * @discussion This method should ONLY be called in the audio+ * thread. The given Session State will replace the current Link+ * state. Modifications will be communicated to other peers in the+ * session.+ */+ void commitAudioSessionState(SessionState state);++ /*! @brief Capture the current Link Session State from an application+ * thread.+ * Thread-safe: yes+ * Realtime-safe: no+ *+ * @discussion Provides a mechanism for capturing the Link Session+ * State from an application thread (other than the audio thread).+ * The returned Session State stores a snapshot of the current Link+ * state, so it should be captured and used in a local scope.+ * Storing the it for later use in a different context is not+ * advised because it will provide an outdated view.+ */+ SessionState captureAppSessionState() const;++ /*! @brief Commit the given Session State to the Link session from an+ * application thread.+ * Thread-safe: yes+ * Realtime-safe: no+ *+ * @discussion The given Session State will replace the current Link+ * Session State. Modifications of the Session State will be+ * communicated to other peers in the session.+ */+ void commitAppSessionState(SessionState state);++ /*! @class SessionState+ * @brief Representation of a timeline and the start/stop state+ *+ * @discussion A SessionState object is intended for use in a local scope within+ * a single thread - none of its methods are thread-safe. All of its methods are+ * non-blocking, so it is safe to use from a realtime thread.+ * It provides functions to observe and manipulate the timeline and start/stop+ * state.+ *+ * The timeline is a representation of a mapping between time and beats for varying+ * quanta.+ * The start/stop state represents the user intention to start or stop transport at+ * a specific time. Start stop synchronization is an optional feature that allows to+ * share the user request to start or stop transport between a subgroup of peers in+ * a Link session. When observing a change of start/stop state, audio playback of a+ * peer should be started or stopped the same way it would have happened if the user+ * had requested that change at the according time locally. The start/stop state can+ * only be changed by the user. This means that the current local start/stop state+ * persists when joining or leaving a Link session. After joining a Link session+ * start/stop change requests will be communicated to all connected peers.+ */+ class SessionState+ {+ public:+ SessionState(const link::ApiState state, const bool bRespectQuantum);++ /*! @brief: The tempo of the timeline, in Beats Per Minute.+ *+ * @discussion This is a stable value that is appropriate for display+ * to the user. Beat time progress will not necessarily match this tempo+ * exactly because of clock drift compensation.+ */+ double tempo() const;++ /*! @brief: Set the timeline tempo to the given bpm value, taking+ * effect at the given time.+ */+ void setTempo(double bpm, std::chrono::microseconds atTime);++ /*! @brief: Get the beat value corresponding to the given time+ * for the given quantum.+ *+ * @discussion: The magnitude of the resulting beat value is+ * unique to this Link instance, but its phase with respect to+ * the provided quantum is shared among all session+ * peers. For non-negative beat values, the following+ * property holds: fmod(beatAtTime(t, q), q) == phaseAtTime(t, q)+ */+ double beatAtTime(std::chrono::microseconds time, double quantum) const;++ /*! @brief: Get the session phase at the given time for the given+ * quantum.+ *+ * @discussion: The result is in the interval [0, quantum). The+ * result is equivalent to fmod(beatAtTime(t, q), q) for+ * non-negative beat values. This method is convenient if the+ * client is only interested in the phase and not the beat+ * magnitude. Also, unlike fmod, it handles negative beat values+ * correctly.+ */+ double phaseAtTime(std::chrono::microseconds time, double quantum) const;++ /*! @brief: Get the time at which the given beat occurs for the+ * given quantum.+ *+ * @discussion: The inverse of beatAtTime, assuming a constant+ * tempo. beatAtTime(timeAtBeat(b, q), q) === b.+ */+ std::chrono::microseconds timeAtBeat(double beat, double quantum) const;++ /*! @brief: Attempt to map the given beat to the given time in the+ * context of the given quantum.+ *+ * @discussion: This method behaves differently depending on the+ * state of the session. If no other peers are connected,+ * then this instance is in a session by itself and is free to+ * re-map the beat/time relationship whenever it pleases. In this+ * case, beatAtTime(time, quantum) == beat after this method has+ * been called.+ *+ * If there are other peers in the session, this instance+ * should not abruptly re-map the beat/time relationship in the+ * session because that would lead to beat discontinuities among+ * the other peers. In this case, the given beat will be mapped+ * to the next time value greater than the given time with the+ * same phase as the given beat.+ *+ * This method is specifically designed to enable the concept of+ * "quantized launch" in client applications. If there are no other+ * peers in the session, then an event (such as starting+ * transport) happens immediately when it is requested. If there+ * are other peers, however, we wait until the next time at which+ * the session phase matches the phase of the event, thereby+ * executing the event in-phase with the other peers in the+ * session. The client only needs to invoke this method to+ * achieve this behavior and should not need to explicitly check+ * the number of peers.+ */+ void requestBeatAtTime(double beat, std::chrono::microseconds time, double quantum);++ /*! @brief: Rudely re-map the beat/time relationship for all peers+ * in a session.+ *+ * @discussion: DANGER: This method should only be needed in+ * certain special circumstances. Most applications should not+ * use it. It is very similar to requestBeatAtTime except that it+ * does not fall back to the quantizing behavior when it is in a+ * session with other peers. Calling this method will+ * unconditionally map the given beat to the given time and+ * broadcast the result to the session. This is very anti-social+ * behavior and should be avoided.+ *+ * One of the few legitimate uses of this method is to+ * synchronize a Link session with an external clock source. By+ * periodically forcing the beat/time mapping according to an+ * external clock source, a peer can effectively bridge that+ * clock into a Link session. Much care must be taken at the+ * application layer when implementing such a feature so that+ * users do not accidentally disrupt Link sessions that they may+ * join.+ */+ void forceBeatAtTime(double beat, std::chrono::microseconds time, double quantum);++ /*! @brief: Set if transport should be playing or stopped, taking effect+ * at the given time.+ */+ void setIsPlaying(bool isPlaying, std::chrono::microseconds time);++ /*! @brief: Is transport playing? */+ bool isPlaying() const;++ /*! @brief: Get the time at which a transport start/stop occurs */+ std::chrono::microseconds timeForIsPlaying() const;++ /*! @brief: Convenience function to attempt to map the given beat to the time+ * when transport is starting to play in context of the given quantum.+ * This function evaluates to a no-op if isPlaying() equals false.+ */+ void requestBeatAtStartPlayingTime(double beat, double quantum);++ /*! @brief: Convenience function to start or stop transport at a given time and+ * attempt to map the given beat to this time in context of the given quantum.+ */+ void setIsPlayingAndRequestBeatAtTime(+ bool isPlaying, std::chrono::microseconds time, double beat, double quantum);++ private:+ friend BasicLink<Clock>;+ link::ApiState mOriginalState;+ link::ApiState mState;+ bool mbRespectQuantum;+ };++private:+ using Controller = ableton::link::Controller<link::PeerCountCallback,+ link::TempoCallback,+ link::StartStopStateCallback,+ Clock,+ link::platform::Random,+ link::platform::IoContext>;++ std::mutex mCallbackMutex;+ link::PeerCountCallback mPeerCountCallback = [](std::size_t) {};+ link::TempoCallback mTempoCallback = [](link::Tempo) {};+ link::StartStopStateCallback mStartStopCallback = [](bool) {};+ Clock mClock;+ Controller mController;+};++class Link : public BasicLink<link::platform::Clock>+{+public:+ using Clock = link::platform::Clock;++ Link(double bpm)+ : BasicLink(bpm)+ {+ }+};++} // namespace ableton++#include <ableton/Link.ipp>
+ link/include/ableton/Link.ipp view
@@ -0,0 +1,280 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/Phase.hpp>++namespace ableton+{+namespace detail+{++template <typename Clock>+inline typename BasicLink<Clock>::SessionState toSessionState(+ const link::ClientState& state, const bool isConnected)+{+ return {{state.timeline, {state.startStopState.isPlaying, state.startStopState.time}},+ isConnected};+}++inline link::IncomingClientState toIncomingClientState(const link::ApiState& state,+ const link::ApiState& originalState,+ const std::chrono::microseconds timestamp)+{+ const auto timeline = originalState.timeline != state.timeline+ ? link::OptionalTimeline{state.timeline}+ : link::OptionalTimeline{};+ const auto startStopState =+ originalState.startStopState != state.startStopState+ ? link::OptionalClientStartStopState{{state.startStopState.isPlaying,+ state.startStopState.time, timestamp}}+ : link::OptionalClientStartStopState{};+ return {timeline, startStopState, timestamp};+}++} // namespace detail++template <typename Clock>+inline BasicLink<Clock>::BasicLink(const double bpm)+ : mController(link::Tempo(bpm),+ [this](const std::size_t peers) {+ std::lock_guard<std::mutex> lock(mCallbackMutex);+ mPeerCountCallback(peers);+ },+ [this](const link::Tempo tempo) {+ std::lock_guard<std::mutex> lock(mCallbackMutex);+ mTempoCallback(tempo);+ },+ [this](const bool isPlaying) {+ std::lock_guard<std::mutex> lock(mCallbackMutex);+ mStartStopCallback(isPlaying);+ },+ mClock)+{+}++template <typename Clock>+inline bool BasicLink<Clock>::isEnabled() const+{+ return mController.isEnabled();+}++template <typename Clock>+inline void BasicLink<Clock>::enable(const bool bEnable)+{+ mController.enable(bEnable);+}++template <typename Clock>+inline bool BasicLink<Clock>::isStartStopSyncEnabled() const+{+ return mController.isStartStopSyncEnabled();+}++template <typename Clock>+inline void BasicLink<Clock>::enableStartStopSync(bool bEnable)+{+ mController.enableStartStopSync(bEnable);+}++template <typename Clock>+inline std::size_t BasicLink<Clock>::numPeers() const+{+ return mController.numPeers();+}++template <typename Clock>+template <typename Callback>+void BasicLink<Clock>::setNumPeersCallback(Callback callback)+{+ std::lock_guard<std::mutex> lock(mCallbackMutex);+ mPeerCountCallback = [callback](const std::size_t numPeers) { callback(numPeers); };+}++template <typename Clock>+template <typename Callback>+void BasicLink<Clock>::setTempoCallback(Callback callback)+{+ std::lock_guard<std::mutex> lock(mCallbackMutex);+ mTempoCallback = [callback](const link::Tempo tempo) { callback(tempo.bpm()); };+}++template <typename Clock>+template <typename Callback>+void BasicLink<Clock>::setStartStopCallback(Callback callback)+{+ std::lock_guard<std::mutex> lock(mCallbackMutex);+ mStartStopCallback = callback;+}++template <typename Clock>+inline Clock BasicLink<Clock>::clock() const+{+ return mClock;+}++template <typename Clock>+inline typename BasicLink<Clock>::SessionState BasicLink<+ Clock>::captureAudioSessionState() const+{+ return detail::toSessionState<Clock>(mController.clientStateRtSafe(), numPeers() > 0);+}++template <typename Clock>+inline void BasicLink<Clock>::commitAudioSessionState(+ const typename BasicLink<Clock>::SessionState state)+{+ mController.setClientStateRtSafe(+ detail::toIncomingClientState(state.mState, state.mOriginalState, mClock.micros()));+}++template <typename Clock>+inline typename BasicLink<Clock>::SessionState BasicLink<Clock>::captureAppSessionState()+ const+{+ return detail::toSessionState<Clock>(mController.clientState(), numPeers() > 0);+}++template <typename Clock>+inline void BasicLink<Clock>::commitAppSessionState(+ const typename BasicLink<Clock>::SessionState state)+{+ mController.setClientState(+ detail::toIncomingClientState(state.mState, state.mOriginalState, mClock.micros()));+}++// Link::SessionState++template <typename Clock>+inline BasicLink<Clock>::SessionState::SessionState(+ const link::ApiState state, const bool bRespectQuantum)+ : mOriginalState(state)+ , mState(state)+ , mbRespectQuantum(bRespectQuantum)+{+}++template <typename Clock>+inline double BasicLink<Clock>::SessionState::tempo() const+{+ return mState.timeline.tempo.bpm();+}++template <typename Clock>+inline void BasicLink<Clock>::SessionState::setTempo(+ const double bpm, const std::chrono::microseconds atTime)+{+ const auto desiredTl = link::clampTempo(+ link::Timeline{link::Tempo(bpm), mState.timeline.toBeats(atTime), atTime});+ mState.timeline.tempo = desiredTl.tempo;+ mState.timeline.timeOrigin = desiredTl.fromBeats(mState.timeline.beatOrigin);+}++template <typename Clock>+inline double BasicLink<Clock>::SessionState::beatAtTime(+ const std::chrono::microseconds time, const double quantum) const+{+ return link::toPhaseEncodedBeats(mState.timeline, time, link::Beats{quantum})+ .floating();+}++template <typename Clock>+inline double BasicLink<Clock>::SessionState::phaseAtTime(+ const std::chrono::microseconds time, const double quantum) const+{+ return link::phase(link::Beats{beatAtTime(time, quantum)}, link::Beats{quantum})+ .floating();+}++template <typename Clock>+inline std::chrono::microseconds BasicLink<Clock>::SessionState::timeAtBeat(+ const double beat, const double quantum) const+{+ return link::fromPhaseEncodedBeats(+ mState.timeline, link::Beats{beat}, link::Beats{quantum});+}++template <typename Clock>+inline void BasicLink<Clock>::SessionState::requestBeatAtTime(+ const double beat, std::chrono::microseconds time, const double quantum)+{+ if (mbRespectQuantum)+ {+ time = timeAtBeat(link::nextPhaseMatch(link::Beats{beatAtTime(time, quantum)},+ link::Beats{beat}, link::Beats{quantum})+ .floating(),+ quantum);+ }+ forceBeatAtTime(beat, time, quantum);+}++template <typename Clock>+inline void BasicLink<Clock>::SessionState::forceBeatAtTime(+ const double beat, const std::chrono::microseconds time, const double quantum)+{+ // There are two components to the beat adjustment: a phase shift+ // and a beat magnitude adjustment.+ const auto curBeatAtTime = link::Beats{beatAtTime(time, quantum)};+ const auto closestInPhase =+ link::closestPhaseMatch(curBeatAtTime, link::Beats{beat}, link::Beats{quantum});+ mState.timeline = shiftClientTimeline(mState.timeline, closestInPhase - curBeatAtTime);+ // Now adjust the magnitude+ mState.timeline.beatOrigin =+ mState.timeline.beatOrigin + (link::Beats{beat} - closestInPhase);+}++template <typename Clock>+inline void BasicLink<Clock>::SessionState::setIsPlaying(+ const bool isPlaying, const std::chrono::microseconds time)+{+ mState.startStopState = {isPlaying, time};+}++template <typename Clock>+inline bool BasicLink<Clock>::SessionState::isPlaying() const+{+ return mState.startStopState.isPlaying;+}++template <typename Clock>+inline std::chrono::microseconds BasicLink<Clock>::SessionState::timeForIsPlaying() const+{+ return mState.startStopState.time;+}++template <typename Clock>+inline void BasicLink<Clock>::SessionState::requestBeatAtStartPlayingTime(+ const double beat, const double quantum)+{+ if (isPlaying())+ {+ requestBeatAtTime(beat, mState.startStopState.time, quantum);+ }+}++template <typename Clock>+inline void BasicLink<Clock>::SessionState::setIsPlayingAndRequestBeatAtTime(+ bool isPlaying, std::chrono::microseconds time, double beat, double quantum)+{+ mState.startStopState = {isPlaying, time};+ requestBeatAtStartPlayingTime(beat, quantum);+}++} // namespace ableton
+ link/include/ableton/discovery/InterfaceScanner.hpp view
@@ -0,0 +1,102 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/util/Injected.hpp>+#include <chrono>+#include <vector>++namespace ableton+{+namespace discovery+{++// Callback takes a range of asio::ip:address which is+// guaranteed to be sorted and unique+template <typename Callback, typename IoContext>+class InterfaceScanner+{+public:+ using Timer = typename util::Injected<IoContext>::type::Timer;++ InterfaceScanner(const std::chrono::seconds period,+ util::Injected<Callback> callback,+ util::Injected<IoContext> io)+ : mPeriod(period)+ , mCallback(std::move(callback))+ , mIo(std::move(io))+ , mTimer(mIo->makeTimer())+ {+ }++ void enable(const bool bEnable)+ {+ if (bEnable)+ {+ scan();+ }+ else+ {+ mTimer.cancel();+ }+ }++ void scan()+ {+ using namespace std;+ debug(mIo->log()) << "Scanning network interfaces";+ // Rescan the hardware for available network interface addresses+ vector<asio::ip::address> addrs = mIo->scanNetworkInterfaces();+ // Sort and unique them to guarantee consistent comparison+ sort(begin(addrs), end(addrs));+ addrs.erase(unique(begin(addrs), end(addrs)), end(addrs));+ // Pass them to the callback+ (*mCallback)(std::move(addrs));+ // setup the next scanning+ mTimer.expires_from_now(mPeriod);+ using ErrorCode = typename Timer::ErrorCode;+ mTimer.async_wait([this](const ErrorCode e) {+ if (!e)+ {+ scan();+ }+ });+ }++private:+ const std::chrono::seconds mPeriod;+ util::Injected<Callback> mCallback;+ util::Injected<IoContext> mIo;+ Timer mTimer;+};++// Factory function+template <typename Callback, typename IoContext>+InterfaceScanner<Callback, IoContext> makeInterfaceScanner(+ const std::chrono::seconds period,+ util::Injected<Callback> callback,+ util::Injected<IoContext> io)+{+ return {period, std::move(callback), std::move(io)};+}++} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/IpV4Interface.hpp view
@@ -0,0 +1,123 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/util/Injected.hpp>++namespace ableton+{+namespace discovery+{++inline asio::ip::udp::endpoint multicastEndpoint()+{+ return {asio::ip::address_v4::from_string("224.76.78.75"), 20808};+}++// Type tags for dispatching between unicast and multicast packets+struct MulticastTag+{+};+struct UnicastTag+{+};++template <typename IoContext, std::size_t MaxPacketSize>+class IpV4Interface+{+public:+ using Socket = typename util::Injected<IoContext>::type::template Socket<MaxPacketSize>;++ IpV4Interface(util::Injected<IoContext> io, const asio::ip::address_v4& addr)+ : mIo(std::move(io))+ , mMulticastReceiveSocket(mIo->template openMulticastSocket<MaxPacketSize>(addr))+ , mSendSocket(mIo->template openUnicastSocket<MaxPacketSize>(addr))+ {+ }++ IpV4Interface(const IpV4Interface&) = delete;+ IpV4Interface& operator=(const IpV4Interface&) = delete;++ IpV4Interface(IpV4Interface&& rhs)+ : mIo(std::move(rhs.mIo))+ , mMulticastReceiveSocket(std::move(rhs.mMulticastReceiveSocket))+ , mSendSocket(std::move(rhs.mSendSocket))+ {+ }+++ std::size_t send(+ const uint8_t* const pData, const size_t numBytes, const asio::ip::udp::endpoint& to)+ {+ return mSendSocket.send(pData, numBytes, to);+ }++ template <typename Handler>+ void receive(Handler handler, UnicastTag)+ {+ mSendSocket.receive(SocketReceiver<UnicastTag, Handler>{std::move(handler)});+ }++ template <typename Handler>+ void receive(Handler handler, MulticastTag)+ {+ mMulticastReceiveSocket.receive(+ SocketReceiver<MulticastTag, Handler>(std::move(handler)));+ }++ asio::ip::udp::endpoint endpoint() const+ {+ return mSendSocket.endpoint();+ }++private:+ template <typename Tag, typename Handler>+ struct SocketReceiver+ {+ SocketReceiver(Handler handler)+ : mHandler(std::move(handler))+ {+ }++ template <typename It>+ void operator()(+ const asio::ip::udp::endpoint& from, const It messageBegin, const It messageEnd)+ {+ mHandler(Tag{}, from, messageBegin, messageEnd);+ }++ Handler mHandler;+ };++ util::Injected<IoContext> mIo;+ Socket mMulticastReceiveSocket;+ Socket mSendSocket;+};++template <std::size_t MaxPacketSize, typename IoContext>+IpV4Interface<IoContext, MaxPacketSize> makeIpV4Interface(+ util::Injected<IoContext> io, const asio::ip::address_v4& addr)+{+ return {std::move(io), addr};+}++} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/MessageTypes.hpp view
@@ -0,0 +1,50 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++namespace ableton+{+namespace discovery+{++// Message types used in the Ableton service discovery protocol. There+// are two logical messages: a state dump and a bye bye.+//+// A state dump provides all relevant information about the peer's+// current state as well as a Time To Live (TTL) value that indicates+// how many seconds this state should be considered valid.+//+// The bye bye indicates that the sender is leaving the session.++template <typename NodeState>+struct PeerState+{+ NodeState peerState;+ int ttl;+};++template <typename NodeId>+struct ByeBye+{+ NodeId peerId;+};++} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/NetworkByteStreamSerializable.hpp view
@@ -0,0 +1,462 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/platforms/asio/AsioWrapper.hpp>+#if defined(LINK_PLATFORM_MACOSX)+#include <ableton/platforms/darwin/Darwin.hpp>+#elif defined(LINK_PLATFORM_LINUX)+#include <ableton/platforms/linux/Linux.hpp>+#elif defined(LINK_PLATFORM_WINDOWS)+#include <ableton/platforms/windows/Windows.hpp>+#elif defined(ESP_PLATFORM)+#include <ableton/platforms/esp32/Esp32.hpp>+#endif++#include <chrono>+#include <cstdint>+#include <type_traits>+#include <utility>+#include <vector>++#if defined(LINK_PLATFORM_WINDOWS)+#include <WS2tcpip.h>+#include <WinSock2.h>+#include <Windows.h>+#endif++namespace ableton+{+namespace discovery+{++// Concept: NetworkByteStreamSerializable+//+// A type that can be encoded to a stream of bytes and decoded from a+// stream of bytes in network byte order. The following type is for+// documentation purposes only.++struct NetworkByteStreamSerializable+{+ friend std::uint32_t sizeInByteStream(const NetworkByteStreamSerializable&);++ // The byte stream pointed to by 'out' must have sufficient space to+ // hold this object, as defined by sizeInByteStream.+ template <typename It>+ friend It toNetworkByteStream(const NetworkByteStreamSerializable&, It out);+};++// Deserialization aspect of the concept. Outside of the demonstration+// type above because clients must specify the type+// explicitly. Default implementation just defers to a class static+// method on T. For types that can't provide such a method, specialize+// this template.+template <typename T>+struct Deserialize+{+ // Throws std::runtime_exception if parsing the type from the given+ // byte range fails. Returns a pair of the correctly parsed value+ // and an iterator to the next byte to parse.+ template <typename It>+ static std::pair<T, It> fromNetworkByteStream(It begin, It end)+ {+ return T::fromNetworkByteStream(std::move(begin), std::move(end));+ }+};+++// Default size implementation. Works for primitive types.++template <typename T,+ typename std::enable_if<std::is_fundamental<T>::value>::type* = nullptr>+std::uint32_t sizeInByteStream(T)+{+ return sizeof(T);+}++namespace detail+{++// utilities for implementing concept for primitive types++template <typename T, typename It>+It copyToByteStream(T t, It out)+{+ using namespace std;+ return copy_n(+ reinterpret_cast<typename iterator_traits<It>::pointer>(&t), sizeof(t), out);+}++template <typename T, typename It>+std::pair<T, It> copyFromByteStream(It begin, const It end)+{+ using namespace std;+ using ItDiff = typename iterator_traits<It>::difference_type;++ if (distance(begin, end) < static_cast<ItDiff>(sizeof(T)))+ {+ throw range_error("Parsing type from byte stream failed");+ }+ else+ {+ T t;+ const auto n = sizeof(t);+ copy_n(begin, n, reinterpret_cast<uint8_t*>(&t));+ return make_pair(t, begin + n);+ }+}++} // namespace detail+++// Model the concept for unsigned integral types++// uint8_t+template <typename It>+It toNetworkByteStream(const uint8_t byte, It out)+{+ return detail::copyToByteStream(byte, std::move(out));+}++template <>+struct Deserialize<uint8_t>+{+ template <typename It>+ static std::pair<uint8_t, It> fromNetworkByteStream(It begin, It end)+ {+ return detail::copyFromByteStream<uint8_t>(std::move(begin), std::move(end));+ }+};++// uint16_t+template <typename It>+It toNetworkByteStream(uint16_t s, It out)+{+ return detail::copyToByteStream(htons(s), std::move(out));+}++template <>+struct Deserialize<uint16_t>+{+ template <typename It>+ static std::pair<uint16_t, It> fromNetworkByteStream(It begin, It end)+ {+ auto result = detail::copyFromByteStream<uint16_t>(std::move(begin), std::move(end));+ result.first = ntohs(result.first);+ return result;+ }+};++// uint32_t+template <typename It>+It toNetworkByteStream(uint32_t l, It out)+{+ return detail::copyToByteStream(htonl(l), std::move(out));+}++template <>+struct Deserialize<uint32_t>+{+ template <typename It>+ static std::pair<uint32_t, It> fromNetworkByteStream(It begin, It end)+ {+ auto result = detail::copyFromByteStream<uint32_t>(std::move(begin), std::move(end));+ result.first = ntohl(result.first);+ return result;+ }+};++// int32_t in terms of uint32_t+template <typename It>+It toNetworkByteStream(int32_t l, It out)+{+ return toNetworkByteStream(reinterpret_cast<const uint32_t&>(l), std::move(out));+}++template <>+struct Deserialize<int32_t>+{+ template <typename It>+ static std::pair<int32_t, It> fromNetworkByteStream(It begin, It end)+ {+ auto result =+ Deserialize<uint32_t>::fromNetworkByteStream(std::move(begin), std::move(end));+ return std::make_pair(reinterpret_cast<const int32_t&>(result.first), result.second);+ }+};++// uint64_t+template <typename It>+It toNetworkByteStream(uint64_t ll, It out)+{+ return detail::copyToByteStream(htonll(ll), std::move(out));+}++template <>+struct Deserialize<uint64_t>+{+ template <typename It>+ static std::pair<uint64_t, It> fromNetworkByteStream(It begin, It end)+ {+ auto result = detail::copyFromByteStream<uint64_t>(std::move(begin), std::move(end));+ result.first = ntohll(result.first);+ return result;+ }+};++// int64_t in terms of uint64_t+template <typename It>+It toNetworkByteStream(int64_t ll, It out)+{+ return toNetworkByteStream(reinterpret_cast<const uint64_t&>(ll), std::move(out));+}++template <>+struct Deserialize<int64_t>+{+ template <typename It>+ static std::pair<int64_t, It> fromNetworkByteStream(It begin, It end)+ {+ auto result =+ Deserialize<uint64_t>::fromNetworkByteStream(std::move(begin), std::move(end));+ return std::make_pair(reinterpret_cast<const int64_t&>(result.first), result.second);+ }+};++// bool+inline std::uint32_t sizeInByteStream(bool)+{+ return sizeof(uint8_t);+}++template <typename It>+It toNetworkByteStream(bool bl, It out)+{+ return toNetworkByteStream(static_cast<uint8_t>(bl), std::move(out));+}++template <>+struct Deserialize<bool>+{+ template <typename It>+ static std::pair<bool, It> fromNetworkByteStream(It begin, It end)+ {+ auto result =+ Deserialize<uint8_t>::fromNetworkByteStream(std::move(begin), std::move(end));+ return std::make_pair(result.first != 0, result.second);+ }+};++// std::chrono::microseconds+inline std::uint32_t sizeInByteStream(const std::chrono::microseconds micros)+{+ return sizeInByteStream(micros.count());+}++template <typename It>+It toNetworkByteStream(const std::chrono::microseconds micros, It out)+{+ static_assert(sizeof(int64_t) == sizeof(std::chrono::microseconds::rep),+ "The size of microseconds::rep must matche the size of int64_t.");+ return toNetworkByteStream(static_cast<int64_t>(micros.count()), std::move(out));+}++template <>+struct Deserialize<std::chrono::microseconds>+{+ template <typename It>+ static std::pair<std::chrono::microseconds, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ auto result =+ Deserialize<int64_t>::fromNetworkByteStream(std::move(begin), std::move(end));+ return make_pair(chrono::microseconds{result.first}, result.second);+ }+};++namespace detail+{++// Generic serialize/deserialize utilities for containers++template <typename Container>+std::uint32_t containerSizeInByteStream(const Container& container)+{+ std::uint32_t totalSize = 0;+ for (const auto& val : container)+ {+ totalSize += sizeInByteStream(val);+ }+ return totalSize;+}++template <typename Container, typename It>+It containerToNetworkByteStream(const Container& container, It out)+{+ for (const auto& val : container)+ {+ out = toNetworkByteStream(val, out);+ }+ return out;+}++template <typename T, typename BytesIt, typename InsertIt>+BytesIt deserializeContainer(BytesIt bytesBegin,+ const BytesIt bytesEnd,+ InsertIt contBegin,+ const std::uint32_t maxElements)+{+ using namespace std;+ std::uint32_t numElements = 0;+ while (bytesBegin < bytesEnd && numElements < maxElements)+ {+ T newVal;+ tie(newVal, bytesBegin) = Deserialize<T>::fromNetworkByteStream(bytesBegin, bytesEnd);+ *contBegin++ = newVal;+ ++numElements;+ }+ return bytesBegin;+}++} // namespace detail++// Need specific overloads for each container type, but use above+// utilities for common implementation++// array+template <typename T, std::size_t Size>+std::uint32_t sizeInByteStream(const std::array<T, Size>& arr)+{+ return detail::containerSizeInByteStream(arr);+}++template <typename T, std::size_t Size, typename It>+It toNetworkByteStream(const std::array<T, Size>& arr, It out)+{+ return detail::containerToNetworkByteStream(arr, std::move(out));+}++template <typename T, std::size_t Size>+struct Deserialize<std::array<T, Size>>+{+ template <typename It>+ static std::pair<std::array<T, Size>, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ array<T, Size> result{};+ auto resultIt = detail::deserializeContainer<T>(+ std::move(begin), std::move(end), std::move(result.begin()), Size);+ return make_pair(std::move(result), std::move(resultIt));+ }+};++// vector+template <typename T, typename Alloc>+std::uint32_t sizeInByteStream(const std::vector<T, Alloc>& vec)+{+ return sizeof(uint32_t) + detail::containerSizeInByteStream(vec);+}++template <typename T, typename Alloc, typename It>+It toNetworkByteStream(const std::vector<T, Alloc>& vec, It out)+{+ out = toNetworkByteStream(static_cast<uint32_t>(vec.size()), out);+ return detail::containerToNetworkByteStream(vec, std::move(out));+}++template <typename T, typename Alloc>+struct Deserialize<std::vector<T, Alloc>>+{+ template <typename It>+ static std::pair<std::vector<T, Alloc>, It> fromNetworkByteStream(+ It bytesBegin, It bytesEnd)+ {+ using namespace std;+ auto result_size =+ Deserialize<uint32_t>::fromNetworkByteStream(std::move(bytesBegin), bytesEnd);+ vector<T, Alloc> result;+ auto resultIt = detail::deserializeContainer<T>(std::move(result_size.second),+ std::move(bytesEnd), back_inserter(result), result_size.first);+ return make_pair(std::move(result), std::move(resultIt));+ }+};++// 2-tuple+template <typename X, typename Y>+std::uint32_t sizeInByteStream(const std::tuple<X, Y>& tup)+{+ return sizeInByteStream(std::get<0>(tup)) + sizeInByteStream(std::get<1>(tup));+}++template <typename X, typename Y, typename It>+It toNetworkByteStream(const std::tuple<X, Y>& tup, It out)+{+ return toNetworkByteStream(+ std::get<1>(tup), toNetworkByteStream(std::get<0>(tup), std::move(out)));+}++template <typename X, typename Y>+struct Deserialize<std::tuple<X, Y>>+{+ template <typename It>+ static std::pair<std::tuple<X, Y>, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ auto xres = Deserialize<X>::fromNetworkByteStream(begin, end);+ auto yres = Deserialize<Y>::fromNetworkByteStream(xres.second, end);+ return make_pair(+ make_tuple(std::move(xres.first), std::move(yres.first)), std::move(yres.second));+ }+};++// 3-tuple+template <typename X, typename Y, typename Z>+std::uint32_t sizeInByteStream(const std::tuple<X, Y, Z>& tup)+{+ return sizeInByteStream(std::get<0>(tup)) + sizeInByteStream(std::get<1>(tup))+ + sizeInByteStream(std::get<2>(tup));+}++template <typename X, typename Y, typename Z, typename It>+It toNetworkByteStream(const std::tuple<X, Y, Z>& tup, It out)+{+ return toNetworkByteStream(+ std::get<2>(tup), toNetworkByteStream(std::get<1>(tup),+ toNetworkByteStream(std::get<0>(tup), std::move(out))));+}++template <typename X, typename Y, typename Z>+struct Deserialize<std::tuple<X, Y, Z>>+{+ template <typename It>+ static std::pair<std::tuple<X, Y, Z>, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ auto xres = Deserialize<X>::fromNetworkByteStream(begin, end);+ auto yres = Deserialize<Y>::fromNetworkByteStream(xres.second, end);+ auto zres = Deserialize<Z>::fromNetworkByteStream(yres.second, end);+ return make_pair(+ make_tuple(std::move(xres.first), std::move(yres.first), std::move(zres.first)),+ std::move(zres.second));+ }+};++} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/Payload.hpp view
@@ -0,0 +1,296 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/NetworkByteStreamSerializable.hpp>+#include <functional>+#include <sstream>+#include <unordered_map>++namespace ableton+{+namespace discovery+{++struct PayloadEntryHeader+{+ using Key = std::uint32_t;+ using Size = std::uint32_t;++ Key key;+ Size size;++ friend Size sizeInByteStream(const PayloadEntryHeader& header)+ {+ return sizeInByteStream(header.key) + sizeInByteStream(header.size);+ }++ template <typename It>+ friend It toNetworkByteStream(const PayloadEntryHeader& header, It out)+ {+ return toNetworkByteStream(+ header.size, toNetworkByteStream(header.key, std::move(out)));+ }++ template <typename It>+ static std::pair<PayloadEntryHeader, It> fromNetworkByteStream(It begin, const It end)+ {+ using namespace std;+ Key key;+ Size size;+ tie(key, begin) = Deserialize<Key>::fromNetworkByteStream(begin, end);+ tie(size, begin) = Deserialize<Size>::fromNetworkByteStream(begin, end);+ return make_pair(+ PayloadEntryHeader{std::move(key), std::move(size)}, std::move(begin));+ }+};++template <typename EntryType>+struct PayloadEntry+{+ PayloadEntry(EntryType entryVal)+ : value(std::move(entryVal))+ {+ header = {EntryType::key, sizeInByteStream(value)};+ }++ PayloadEntryHeader header;+ EntryType value;++ friend std::uint32_t sizeInByteStream(const PayloadEntry& entry)+ {+ return sizeInByteStream(entry.header) + sizeInByteStream(entry.value);+ }++ template <typename It>+ friend It toNetworkByteStream(const PayloadEntry& entry, It out)+ {+ return toNetworkByteStream(+ entry.value, toNetworkByteStream(entry.header, std::move(out)));+ }+};++namespace detail+{++template <typename It>+using HandlerMap =+ std::unordered_map<typename PayloadEntryHeader::Key, std::function<void(It, It)>>;++// Given an index of handlers and a byte range, parse the bytes as a+// sequence of payload entries and invoke the appropriate handler for+// each entry type. Entries that are encountered that do not have a+// corresponding handler in the map are ignored. Throws+// std::runtime_error if parsing fails for any entry. Note that if an+// exception is thrown, some of the handlers may have already been called.+template <typename It>+void parseByteStream(HandlerMap<It>& map, It bsBegin, const It bsEnd)+{+ using namespace std;++ while (bsBegin < bsEnd)+ {+ // Try to parse an entry header at this location in the byte stream+ PayloadEntryHeader header;+ It valueBegin;+ tie(header, valueBegin) =+ Deserialize<PayloadEntryHeader>::fromNetworkByteStream(bsBegin, bsEnd);++ // Ensure that the reported size of the entry does not exceed the+ // length of the byte stream+ It valueEnd = valueBegin + header.size;+ if (bsEnd < valueEnd)+ {+ throw range_error("Payload with incorrect size.");+ }++ // The next entry will start at the end of this one+ bsBegin = valueEnd;++ // Use the appropriate handler for this entry, if available+ auto handlerIt = map.find(header.key);+ if (handlerIt != end(map))+ {+ handlerIt->second(std::move(valueBegin), std::move(valueEnd));+ }+ }+}++} // namespace detail+++// Payload encoding+template <typename... Entries>+struct Payload;++template <typename First, typename Rest>+struct Payload<First, Rest>+{+ Payload(First first, Rest rest)+ : mFirst(std::move(first))+ , mRest(std::move(rest))+ {+ }++ Payload(PayloadEntry<First> first, Rest rest)+ : mFirst(std::move(first))+ , mRest(std::move(rest))+ {+ }++ template <typename RhsFirst, typename RhsRest>+ using PayloadSum =+ Payload<First, typename Rest::template PayloadSum<RhsFirst, RhsRest>>;++ // Concatenate payloads together into a single payload+ template <typename RhsFirst, typename RhsRest>+ friend PayloadSum<RhsFirst, RhsRest> operator+(+ Payload lhs, Payload<RhsFirst, RhsRest> rhs)+ {+ return {std::move(lhs.mFirst), std::move(lhs.mRest) + std::move(rhs)};+ }++ friend std::size_t sizeInByteStream(const Payload& payload)+ {+ return sizeInByteStream(payload.mFirst) + sizeInByteStream(payload.mRest);+ }++ template <typename It>+ friend It toNetworkByteStream(const Payload& payload, It streamIt)+ {+ return toNetworkByteStream(+ payload.mRest, toNetworkByteStream(payload.mFirst, std::move(streamIt)));+ }++ PayloadEntry<First> mFirst;+ Rest mRest;+};++template <>+struct Payload<>+{+ template <typename RhsFirst, typename RhsRest>+ using PayloadSum = Payload<RhsFirst, RhsRest>;++ template <typename RhsFirst, typename RhsRest>+ friend PayloadSum<RhsFirst, RhsRest> operator+(Payload, Payload<RhsFirst, RhsRest> rhs)+ {+ return rhs;+ }++ friend std::size_t sizeInByteStream(const Payload&)+ {+ return 0;+ }++ template <typename It>+ friend It toNetworkByteStream(const Payload&, It streamIt)+ {+ return streamIt;+ }+};++template <typename... Entries>+struct PayloadBuilder;++// Payload factory function+template <typename... Entries>+auto makePayload(Entries... entries)+ -> decltype(PayloadBuilder<Entries...>{}(std::move(entries)...))+{+ return PayloadBuilder<Entries...>{}(std::move(entries)...);+}++template <typename First, typename... Rest>+struct PayloadBuilder<First, Rest...>+{+ auto operator()(First first, Rest... rest)+ -> Payload<First, decltype(makePayload(std::move(rest)...))>+ {+ return {std::move(first), makePayload(std::move(rest)...)};+ }+};++template <>+struct PayloadBuilder<>+{+ Payload<> operator()()+ {+ return {};+ }+};++// Parse payloads to values+template <typename... Entries>+struct ParsePayload;++template <typename First, typename... Rest>+struct ParsePayload<First, Rest...>+{+ template <typename It, typename... Handlers>+ static void parse(It begin, It end, Handlers... handlers)+ {+ detail::HandlerMap<It> map;+ collectHandlers(map, std::move(handlers)...);+ detail::parseByteStream(map, std::move(begin), std::move(end));+ }++ template <typename It, typename FirstHandler, typename... RestHandlers>+ static void collectHandlers(+ detail::HandlerMap<It>& map, FirstHandler handler, RestHandlers... rest)+ {+ using namespace std;+ map[First::key] = [handler](const It begin, const It end) {+ const auto res = First::fromNetworkByteStream(begin, end);+ if (res.second != end)+ {+ std::ostringstream stringStream;+ stringStream << "Parsing payload entry " << First::key+ << " did not consume the expected number of bytes. "+ << " Expected: " << distance(begin, end)+ << ", Actual: " << distance(begin, res.second);+ throw range_error(stringStream.str());+ }+ handler(res.first);+ };++ ParsePayload<Rest...>::collectHandlers(map, std::move(rest)...);+ }+};++template <>+struct ParsePayload<>+{+ template <typename It>+ static void collectHandlers(detail::HandlerMap<It>&)+ {+ }+};++template <typename... Entries, typename It, typename... Handlers>+void parsePayload(It begin, It end, Handlers... handlers)+{+ using namespace std;+ ParsePayload<Entries...>::parse(+ std::move(begin), std::move(end), std::move(handlers)...);+}++} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/PeerGateway.hpp view
@@ -0,0 +1,251 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/UdpMessenger.hpp>+#include <ableton/discovery/v1/Messages.hpp>+#include <ableton/util/SafeAsyncHandler.hpp>+#include <memory>++namespace ableton+{+namespace discovery+{++template <typename Messenger, typename PeerObserver, typename IoContext>+class PeerGateway+{+public:+ // The peer types are defined by the observer but must match with those+ // used by the Messenger+ using ObserverT = typename util::Injected<PeerObserver>::type;+ using NodeState = typename ObserverT::GatewayObserverNodeState;+ using NodeId = typename ObserverT::GatewayObserverNodeId;+ using Timer = typename util::Injected<IoContext>::type::Timer;+ using TimerError = typename Timer::ErrorCode;++ PeerGateway(util::Injected<Messenger> messenger,+ util::Injected<PeerObserver> observer,+ util::Injected<IoContext> io)+ : mpImpl(new Impl(std::move(messenger), std::move(observer), std::move(io)))+ {+ mpImpl->listen();+ }++ PeerGateway(const PeerGateway&) = delete;+ PeerGateway& operator=(const PeerGateway&) = delete;++ PeerGateway(PeerGateway&& rhs)+ : mpImpl(std::move(rhs.mpImpl))+ {+ }++ void updateState(NodeState state)+ {+ mpImpl->updateState(std::move(state));+ }++private:+ using PeerTimeout = std::pair<std::chrono::system_clock::time_point, NodeId>;+ using PeerTimeouts = std::vector<PeerTimeout>;++ struct Impl : std::enable_shared_from_this<Impl>+ {+ Impl(util::Injected<Messenger> messenger,+ util::Injected<PeerObserver> observer,+ util::Injected<IoContext> io)+ : mMessenger(std::move(messenger))+ , mObserver(std::move(observer))+ , mIo(std::move(io))+ , mPruneTimer(mIo->makeTimer())+ {+ }++ void updateState(NodeState state)+ {+ mMessenger->updateState(std::move(state));+ try+ {+ mMessenger->broadcastState();+ }+ catch (const std::runtime_error& err)+ {+ info(mIo->log()) << "State broadcast failed on gateway: " << err.what();+ }+ }++ void listen()+ {+ mMessenger->receive(util::makeAsyncSafe(this->shared_from_this()));+ }++ // Operators for handling incoming messages+ void operator()(const PeerState<NodeState>& msg)+ {+ onPeerState(msg.peerState, msg.ttl);+ listen();+ }++ void operator()(const ByeBye<NodeId>& msg)+ {+ onByeBye(msg.peerId);+ listen();+ }++ void onPeerState(const NodeState& nodeState, const int ttl)+ {+ using namespace std;+ const auto peerId = nodeState.ident();+ const auto existing = findPeer(peerId);+ if (existing != end(mPeerTimeouts))+ {+ // If the peer is already present in our timeout list, remove it+ // as it will be re-inserted below.+ mPeerTimeouts.erase(existing);+ }++ auto newTo = make_pair(mPruneTimer.now() + std::chrono::seconds(ttl), peerId);+ mPeerTimeouts.insert(+ upper_bound(begin(mPeerTimeouts), end(mPeerTimeouts), newTo, TimeoutCompare{}),+ std::move(newTo));++ sawPeer(*mObserver, nodeState);+ scheduleNextPruning();+ }++ void onByeBye(const NodeId& peerId)+ {+ const auto it = findPeer(peerId);+ if (it != mPeerTimeouts.end())+ {+ peerLeft(*mObserver, it->second);+ mPeerTimeouts.erase(it);+ }+ }++ void pruneExpiredPeers()+ {+ using namespace std;++ const auto test = make_pair(mPruneTimer.now(), NodeId{});+ debug(mIo->log()) << "pruning peers @ " << test.first.time_since_epoch().count();++ const auto endExpired =+ lower_bound(begin(mPeerTimeouts), end(mPeerTimeouts), test, TimeoutCompare{});++ for_each(begin(mPeerTimeouts), endExpired, [this](const PeerTimeout& pto) {+ info(mIo->log()) << "pruning peer " << pto.second;+ peerTimedOut(*mObserver, pto.second);+ });+ mPeerTimeouts.erase(begin(mPeerTimeouts), endExpired);+ scheduleNextPruning();+ }++ void scheduleNextPruning()+ {+ // Find the next peer to expire and set the timer based on it+ if (!mPeerTimeouts.empty())+ {+ // Add a second of padding to the timer to avoid over-eager timeouts+ const auto t = mPeerTimeouts.front().first + std::chrono::seconds(1);++ debug(mIo->log()) << "scheduling next pruning for "+ << t.time_since_epoch().count() << " because of peer "+ << mPeerTimeouts.front().second;++ mPruneTimer.expires_at(t);+ mPruneTimer.async_wait([this](const TimerError e) {+ if (!e)+ {+ pruneExpiredPeers();+ }+ });+ }+ }++ struct TimeoutCompare+ {+ bool operator()(const PeerTimeout& lhs, const PeerTimeout& rhs) const+ {+ return lhs.first < rhs.first;+ }+ };++ typename PeerTimeouts::iterator findPeer(const NodeId& peerId)+ {+ return std::find_if(begin(mPeerTimeouts), end(mPeerTimeouts),+ [&peerId](const PeerTimeout& pto) { return pto.second == peerId; });+ }++ util::Injected<Messenger> mMessenger;+ util::Injected<PeerObserver> mObserver;+ util::Injected<IoContext> mIo;+ Timer mPruneTimer;+ PeerTimeouts mPeerTimeouts; // Invariant: sorted by time_point+ };++ std::shared_ptr<Impl> mpImpl;+};++template <typename Messenger, typename PeerObserver, typename IoContext>+PeerGateway<Messenger, PeerObserver, IoContext> makePeerGateway(+ util::Injected<Messenger> messenger,+ util::Injected<PeerObserver> observer,+ util::Injected<IoContext> io)+{+ return {std::move(messenger), std::move(observer), std::move(io)};+}++// IpV4 gateway types+template <typename StateQuery, typename IoContext>+using IpV4Messenger = UdpMessenger<+ IpV4Interface<typename util::Injected<IoContext>::type&, v1::kMaxMessageSize>,+ StateQuery,+ IoContext>;++template <typename PeerObserver, typename StateQuery, typename IoContext>+using IpV4Gateway =+ PeerGateway<IpV4Messenger<StateQuery, typename util::Injected<IoContext>::type&>,+ PeerObserver,+ IoContext>;++// Factory function to bind a PeerGateway to an IpV4Interface with the given address.+template <typename PeerObserver, typename NodeState, typename IoContext>+IpV4Gateway<PeerObserver, NodeState, IoContext> makeIpV4Gateway(+ util::Injected<IoContext> io,+ const asio::ip::address_v4& addr,+ util::Injected<PeerObserver> observer,+ NodeState state)+{+ using namespace std;+ using namespace util;++ const uint8_t ttl = 5;+ const uint8_t ttlRatio = 20;++ auto iface = makeIpV4Interface<v1::kMaxMessageSize>(injectRef(*io), addr);++ auto messenger = makeUdpMessenger(+ injectVal(std::move(iface)), std::move(state), injectRef(*io), ttl, ttlRatio);+ return {injectVal(std::move(messenger)), std::move(observer), std::move(io)};+}++} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/PeerGateways.hpp view
@@ -0,0 +1,182 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/InterfaceScanner.hpp>+#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <map>++namespace ableton+{+namespace discovery+{++// GatewayFactory must have an operator()(NodeState, IoRef, asio::ip::address)+// that constructs a new PeerGateway on a given interface address.+template <typename NodeState, typename GatewayFactory, typename IoContext>+class PeerGateways+{+public:+ using IoType = typename util::Injected<IoContext>::type;+ using Gateway = typename std::result_of<GatewayFactory(+ NodeState, util::Injected<IoType&>, asio::ip::address)>::type;+ using GatewayMap = std::map<asio::ip::address, Gateway>;++ PeerGateways(const std::chrono::seconds rescanPeriod,+ NodeState state,+ GatewayFactory factory,+ util::Injected<IoContext> io)+ : mIo(std::move(io))+ {+ mpScannerCallback =+ std::make_shared<Callback>(std::move(state), std::move(factory), *mIo);+ mpScanner = std::make_shared<Scanner>(+ rescanPeriod, util::injectShared(mpScannerCallback), util::injectRef(*mIo));+ }++ ~PeerGateways()+ {+ mpScanner.reset();+ mpScannerCallback.reset();+ }++ PeerGateways(const PeerGateways&) = delete;+ PeerGateways& operator=(const PeerGateways&) = delete;++ PeerGateways(PeerGateways&&) = delete;+ PeerGateways& operator=(PeerGateways&&) = delete;++ void enable(const bool bEnable)+ {+ mpScannerCallback->mGateways.clear();+ mpScanner->enable(bEnable);+ }++ template <typename Handler>+ void withGateways(Handler handler)+ {+ handler(mpScannerCallback->mGateways.begin(), mpScannerCallback->mGateways.end());+ }++ void updateNodeState(const NodeState& state)+ {+ mpScannerCallback->mState = state;+ for (const auto& entry : mpScannerCallback->mGateways)+ {+ entry.second->updateNodeState(state);+ }+ }++ // If a gateway has become non-responsive or is throwing exceptions,+ // this method can be invoked to either fix it or discard it.+ void repairGateway(const asio::ip::address& gatewayAddr)+ {+ if (mpScannerCallback->mGateways.erase(gatewayAddr))+ {+ // If we erased a gateway, rescan again immediately so that+ // we will re-initialize it if it's still present+ mpScanner->scan();+ }+ }++private:+ struct Callback+ {+ Callback(NodeState state, GatewayFactory factory, IoType& io)+ : mState(std::move(state))+ , mFactory(std::move(factory))+ , mIo(io)+ {+ }++ template <typename AddrRange>+ void operator()(const AddrRange& range)+ {+ using namespace std;+ // Get the set of current addresses.+ vector<asio::ip::address> curAddrs;+ curAddrs.reserve(mGateways.size());+ transform(std::begin(mGateways), std::end(mGateways), back_inserter(curAddrs),+ [](const typename GatewayMap::value_type& vt) { return vt.first; });++ // Now use set_difference to determine the set of addresses that+ // are new and the set of cur addresses that are no longer there+ vector<asio::ip::address> newAddrs;+ set_difference(std::begin(range), std::end(range), std::begin(curAddrs),+ std::end(curAddrs), back_inserter(newAddrs));++ vector<asio::ip::address> staleAddrs;+ set_difference(std::begin(curAddrs), std::end(curAddrs), std::begin(range),+ std::end(range), back_inserter(staleAddrs));++ // Remove the stale addresses+ for (const auto& addr : staleAddrs)+ {+ mGateways.erase(addr);+ }++ // Add the new addresses+ for (const auto& addr : newAddrs)+ {+ try+ {+ // Only handle v4 for now+ if (addr.is_v4())+ {+ info(mIo.log()) << "initializing peer gateway on interface " << addr;+ mGateways.emplace(addr, mFactory(mState, util::injectRef(mIo), addr.to_v4()));+ }+ }+ catch (const runtime_error& e)+ {+ warning(mIo.log()) << "failed to init gateway on interface " << addr+ << " reason: " << e.what();+ }+ }+ }++ NodeState mState;+ GatewayFactory mFactory;+ IoType& mIo;+ GatewayMap mGateways;+ };++ using Scanner = InterfaceScanner<std::shared_ptr<Callback>, IoType&>;+ std::shared_ptr<Callback> mpScannerCallback;+ std::shared_ptr<Scanner> mpScanner;+ util::Injected<IoContext> mIo;+};++// Factory function+template <typename NodeState, typename GatewayFactory, typename IoContext>+std::unique_ptr<PeerGateways<NodeState, GatewayFactory, IoContext>> makePeerGateways(+ const std::chrono::seconds rescanPeriod,+ NodeState state,+ GatewayFactory factory,+ util::Injected<IoContext> io)+{+ using namespace std;+ using Gateways = PeerGateways<NodeState, GatewayFactory, IoContext>;+ return unique_ptr<Gateways>{+ new Gateways{rescanPeriod, std::move(state), std::move(factory), std::move(io)}};+}++} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/Service.hpp view
@@ -0,0 +1,72 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/PeerGateways.hpp>++namespace ableton+{+namespace discovery+{++template <typename NodeState, typename GatewayFactory, typename IoContext>+class Service+{+public:+ using ServicePeerGateways = PeerGateways<NodeState, GatewayFactory, IoContext>;++ Service(NodeState state, GatewayFactory factory, util::Injected<IoContext> io)+ : mGateways(+ std::chrono::seconds(5), std::move(state), std::move(factory), std::move(io))+ {+ }++ void enable(const bool bEnable)+ {+ mGateways.enable(bEnable);+ }++ // Asynchronously operate on the current set of peer gateways. The+ // handler will be invoked in the service's io context.+ template <typename Handler>+ void withGateways(Handler handler)+ {+ mGateways.withGateways(std::move(handler));+ }++ void updateNodeState(const NodeState& state)+ {+ mGateways.updateNodeState(state);+ }++ // Repair the gateway with the given address if possible. Its+ // sockets may have been closed, for example, and the gateway needs+ // to be regenerated.+ void repairGateway(const asio::ip::address& gatewayAddr)+ {+ mGateways.repairGateway(gatewayAddr);+ }++private:+ ServicePeerGateways mGateways;+};++} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/UdpMessenger.hpp view
@@ -0,0 +1,330 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/IpV4Interface.hpp>+#include <ableton/discovery/MessageTypes.hpp>+#include <ableton/discovery/v1/Messages.hpp>+#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/util/Injected.hpp>+#include <ableton/util/SafeAsyncHandler.hpp>+#include <algorithm>+#include <memory>++namespace ableton+{+namespace discovery+{++// An exception thrown when sending a udp message fails. Stores the+// interface through which the sending failed.+struct UdpSendException : std::runtime_error+{+ UdpSendException(const std::runtime_error& e, asio::ip::address ifAddr)+ : std::runtime_error(e.what())+ , interfaceAddr(std::move(ifAddr))+ {+ }++ asio::ip::address interfaceAddr;+};++// Throws UdpSendException+template <typename Interface, typename NodeId, typename Payload>+void sendUdpMessage(Interface& iface,+ NodeId from,+ const uint8_t ttl,+ const v1::MessageType messageType,+ const Payload& payload,+ const asio::ip::udp::endpoint& to)+{+ using namespace std;+ v1::MessageBuffer buffer;+ const auto messageBegin = begin(buffer);+ const auto messageEnd =+ v1::detail::encodeMessage(std::move(from), ttl, messageType, payload, messageBegin);+ const auto numBytes = static_cast<size_t>(distance(messageBegin, messageEnd));+ try+ {+ iface.send(buffer.data(), numBytes, to);+ }+ catch (const std::runtime_error& err)+ {+ throw UdpSendException{err, iface.endpoint().address()};+ }+}++// UdpMessenger uses a "shared_ptr pImpl" pattern to make it movable+// and to support safe async handler callbacks when receiving messages+// on the given interface.+template <typename Interface, typename NodeStateT, typename IoContext>+class UdpMessenger+{+public:+ using NodeState = NodeStateT;+ using NodeId = typename NodeState::IdType;+ using Timer = typename util::Injected<IoContext>::type::Timer;+ using TimerError = typename Timer::ErrorCode;+ using TimePoint = typename Timer::TimePoint;++ UdpMessenger(util::Injected<Interface> iface,+ NodeState state,+ util::Injected<IoContext> io,+ const uint8_t ttl,+ const uint8_t ttlRatio)+ : mpImpl(std::make_shared<Impl>(+ std::move(iface), std::move(state), std::move(io), ttl, ttlRatio))+ {+ // We need to always listen for incoming traffic in order to+ // respond to peer state broadcasts+ mpImpl->listen(MulticastTag{});+ mpImpl->listen(UnicastTag{});+ mpImpl->broadcastState();+ }++ UdpMessenger(const UdpMessenger&) = delete;+ UdpMessenger& operator=(const UdpMessenger&) = delete;++ UdpMessenger(UdpMessenger&& rhs)+ : mpImpl(std::move(rhs.mpImpl))+ {+ }++ ~UdpMessenger()+ {+ if (mpImpl != nullptr)+ {+ try+ {+ mpImpl->sendByeBye();+ }+ catch (const UdpSendException& err)+ {+ debug(mpImpl->mIo->log()) << "Failed to send bye bye message: " << err.what();+ }+ }+ }++ void updateState(NodeState state)+ {+ mpImpl->updateState(std::move(state));+ }++ // Broadcast the current state of the system to all peers. May throw+ // std::runtime_error if assembling a broadcast message fails or if+ // there is an error at the transport layer. Throws on failure.+ void broadcastState()+ {+ mpImpl->broadcastState();+ }++ // Asynchronous receive function for incoming messages from peers. Will+ // return immediately and the handler will be invoked when a message+ // is received. Handler must have operator() overloads for PeerState and+ // ByeBye messages.+ template <typename Handler>+ void receive(Handler handler)+ {+ mpImpl->setReceiveHandler(std::move(handler));+ }++private:+ struct Impl : std::enable_shared_from_this<Impl>+ {+ Impl(util::Injected<Interface> iface,+ NodeState state,+ util::Injected<IoContext> io,+ const uint8_t ttl,+ const uint8_t ttlRatio)+ : mIo(std::move(io))+ , mInterface(std::move(iface))+ , mState(std::move(state))+ , mTimer(mIo->makeTimer())+ , mLastBroadcastTime{}+ , mTtl(ttl)+ , mTtlRatio(ttlRatio)+ , mPeerStateHandler([](PeerState<NodeState>) {})+ , mByeByeHandler([](ByeBye<NodeId>) {})+ {+ }++ template <typename Handler>+ void setReceiveHandler(Handler handler)+ {+ mPeerStateHandler = [handler](+ PeerState<NodeState> state) { handler(std::move(state)); };++ mByeByeHandler = [handler](ByeBye<NodeId> byeBye) { handler(std::move(byeBye)); };+ }++ void sendByeBye()+ {+ sendUdpMessage(+ *mInterface, mState.ident(), 0, v1::kByeBye, makePayload(), multicastEndpoint());+ }++ void updateState(NodeState state)+ {+ mState = std::move(state);+ }++ void broadcastState()+ {+ using namespace std::chrono;++ const auto minBroadcastPeriod = milliseconds{50};+ const auto nominalBroadcastPeriod = milliseconds(mTtl * 1000 / mTtlRatio);+ const auto timeSinceLastBroadcast =+ duration_cast<milliseconds>(mTimer.now() - mLastBroadcastTime);++ // The rate is limited to maxBroadcastRate to prevent flooding the network.+ const auto delay = minBroadcastPeriod - timeSinceLastBroadcast;++ // Schedule the next broadcast before we actually send the+ // message so that if sending throws an exception we are still+ // scheduled to try again. We want to keep trying at our+ // interval as long as this instance is alive.+ mTimer.expires_from_now(delay > milliseconds{0} ? delay : nominalBroadcastPeriod);+ mTimer.async_wait([this](const TimerError e) {+ if (!e)+ {+ broadcastState();+ }+ });++ // If we're not delaying, broadcast now+ if (delay < milliseconds{1})+ {+ debug(mIo->log()) << "Broadcasting state";+ sendPeerState(v1::kAlive, multicastEndpoint());+ }+ }++ void sendPeerState(+ const v1::MessageType messageType, const asio::ip::udp::endpoint& to)+ {+ sendUdpMessage(+ *mInterface, mState.ident(), mTtl, messageType, toPayload(mState), to);+ mLastBroadcastTime = mTimer.now();+ }++ void sendResponse(const asio::ip::udp::endpoint& to)+ {+ sendPeerState(v1::kResponse, to);+ }++ template <typename Tag>+ void listen(Tag tag)+ {+ mInterface->receive(util::makeAsyncSafe(this->shared_from_this()), tag);+ }++ template <typename Tag, typename It>+ void operator()(Tag tag,+ const asio::ip::udp::endpoint& from,+ const It messageBegin,+ const It messageEnd)+ {+ auto result = v1::parseMessageHeader<NodeId>(messageBegin, messageEnd);++ const auto& header = result.first;+ // Ignore messages from self and other groups+ if (header.ident != mState.ident() && header.groupId == 0)+ {+ debug(mIo->log()) << "Received message type "+ << static_cast<int>(header.messageType) << " from peer "+ << header.ident;++ switch (header.messageType)+ {+ case v1::kAlive:+ sendResponse(from);+ receivePeerState(std::move(result.first), result.second, messageEnd);+ break;+ case v1::kResponse:+ receivePeerState(std::move(result.first), result.second, messageEnd);+ break;+ case v1::kByeBye:+ receiveByeBye(std::move(result.first.ident));+ break;+ default:+ info(mIo->log()) << "Unknown message received of type: " << header.messageType;+ }+ }+ listen(tag);+ }++ template <typename It>+ void receivePeerState(+ v1::MessageHeader<NodeId> header, It payloadBegin, It payloadEnd)+ {+ try+ {+ auto state = NodeState::fromPayload(+ std::move(header.ident), std::move(payloadBegin), std::move(payloadEnd));++ // Handlers must only be called once+ auto handler = std::move(mPeerStateHandler);+ mPeerStateHandler = [](PeerState<NodeState>) {};+ handler(PeerState<NodeState>{std::move(state), header.ttl});+ }+ catch (const std::runtime_error& err)+ {+ info(mIo->log()) << "Ignoring peer state message: " << err.what();+ }+ }++ void receiveByeBye(NodeId nodeId)+ {+ // Handlers must only be called once+ auto byeByeHandler = std::move(mByeByeHandler);+ mByeByeHandler = [](ByeBye<NodeId>) {};+ byeByeHandler(ByeBye<NodeId>{std::move(nodeId)});+ }++ util::Injected<IoContext> mIo;+ util::Injected<Interface> mInterface;+ NodeState mState;+ Timer mTimer;+ TimePoint mLastBroadcastTime;+ uint8_t mTtl;+ uint8_t mTtlRatio;+ std::function<void(PeerState<NodeState>)> mPeerStateHandler;+ std::function<void(ByeBye<NodeId>)> mByeByeHandler;+ };++ std::shared_ptr<Impl> mpImpl;+};++// Factory function+template <typename Interface, typename NodeState, typename IoContext>+UdpMessenger<Interface, NodeState, IoContext> makeUdpMessenger(+ util::Injected<Interface> iface,+ NodeState state,+ util::Injected<IoContext> io,+ const uint8_t ttl,+ const uint8_t ttlRatio)+{+ return UdpMessenger<Interface, NodeState, IoContext>{+ std::move(iface), std::move(state), std::move(io), ttl, ttlRatio};+}++} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/test/Interface.hpp view
@@ -0,0 +1,75 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/util/Log.hpp>++namespace ableton+{+namespace discovery+{+namespace test+{++class Interface+{+public:+ void send(const uint8_t* const bytes,+ const size_t numBytes,+ const asio::ip::udp::endpoint& endpoint)+ {+ sentMessages.push_back(+ std::make_pair(std::vector<uint8_t>{bytes, bytes + numBytes}, endpoint));+ }++ template <typename Callback, typename Tag>+ void receive(Callback callback, Tag tag)+ {+ mCallback = [callback, tag](const asio::ip::udp::endpoint& from,+ const std::vector<uint8_t>& buffer) {+ callback(tag, from, begin(buffer), end(buffer));+ };+ }++ template <typename It>+ void incomingMessage(+ const asio::ip::udp::endpoint& from, It messageBegin, It messageEnd)+ {+ std::vector<uint8_t> buffer{messageBegin, messageEnd};+ mCallback(from, buffer);+ }++ asio::ip::udp::endpoint endpoint() const+ {+ return asio::ip::udp::endpoint({}, 0);+ }++ using SentMessage = std::pair<std::vector<uint8_t>, asio::ip::udp::endpoint>;+ std::vector<SentMessage> sentMessages;++private:+ using ReceiveCallback =+ std::function<void(const asio::ip::udp::endpoint&, const std::vector<uint8_t>&)>;+ ReceiveCallback mCallback;+};++} // namespace test+} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/test/PayloadEntries.hpp view
@@ -0,0 +1,133 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/NetworkByteStreamSerializable.hpp>+#include <cstdint>+#include <tuple>+#include <utility>++namespace ableton+{+namespace discovery+{+namespace test+{++// Test payload entries++// A fixed-size entry type+struct Foo+{+ static const std::int32_t key = '_foo';+ static_assert(key == 0x5f666f6f, "Unexpected byte order");++ std::int32_t fooVal;++ friend std::uint32_t sizeInByteStream(const Foo& foo)+ {+ // Namespace qualification is needed to avoid ambiguous function definitions+ return discovery::sizeInByteStream(foo.fooVal);+ }++ template <typename It>+ friend It toNetworkByteStream(const Foo& foo, It out)+ {+ return discovery::toNetworkByteStream(foo.fooVal, std::move(out));+ }++ template <typename It>+ static std::pair<Foo, It> fromNetworkByteStream(It begin, It end)+ {+ auto result = Deserialize<decltype(fooVal)>::fromNetworkByteStream(+ std::move(begin), std::move(end));+ return std::make_pair(Foo{std::move(result.first)}, std::move(result.second));+ }+};++// A variable-size entry type+struct Bar+{+ static const std::int32_t key = '_bar';+ static_assert(key == 0x5f626172, "Unexpected byte order");++ std::vector<std::uint64_t> barVals;++ friend std::uint32_t sizeInByteStream(const Bar& bar)+ {+ return discovery::sizeInByteStream(bar.barVals);+ }++ template <typename It>+ friend It toNetworkByteStream(const Bar& bar, It out)+ {+ return discovery::toNetworkByteStream(bar.barVals, out);+ }++ template <typename It>+ static std::pair<Bar, It> fromNetworkByteStream(It begin, It end)+ {+ auto result = Deserialize<decltype(barVals)>::fromNetworkByteStream(+ std::move(begin), std::move(end));+ return std::make_pair(Bar{std::move(result.first)}, std::move(result.second));+ }+};++// An entry type with two vectors+struct Foobar+{+ static const std::int32_t key = 'fbar';+ static_assert(key == 0x66626172, "Unexpected byte order");++ using FoobarVector = std::vector<std::uint64_t>;+ using FoobarTuple = std::tuple<FoobarVector, FoobarVector>;++ FoobarVector fooVals;+ FoobarVector barVals;++ friend std::uint32_t sizeInByteStream(const Foobar& foobar)+ {+ return discovery::sizeInByteStream(foobar.asTuple());+ }++ template <typename It>+ friend It toNetworkByteStream(const Foobar& foobar, It out)+ {+ return discovery::toNetworkByteStream(foobar.asTuple(), out);+ }++ template <typename It>+ static std::pair<Foobar, It> fromNetworkByteStream(It begin, It end)+ {+ const auto result =+ Deserialize<FoobarTuple>::fromNetworkByteStream(std::move(begin), std::move(end));+ const auto foobar = Foobar{std::get<0>(result.first), std::get<1>(result.first)};+ return std::make_pair(std::move(foobar), std::move(result.second));+ }++ FoobarTuple asTuple() const+ {+ return std::make_tuple(fooVals, barVals);+ }+};++} // namespace test+} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/test/Socket.hpp view
@@ -0,0 +1,85 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/util/Log.hpp>+#include <ableton/util/test/IoService.hpp>++namespace ableton+{+namespace discovery+{+namespace test+{++class Socket+{+public:+ Socket(util::test::IoService&)+ {+ }++ friend void configureUnicastSocket(Socket&, const asio::ip::address_v4&)+ {+ }++ std::size_t send(+ const uint8_t* const pData, const size_t numBytes, const asio::ip::udp::endpoint& to)+ {+ sentMessages.push_back(+ std::make_pair(std::vector<uint8_t>{pData, pData + numBytes}, to));+ return numBytes;+ }++ template <typename Handler>+ void receive(Handler handler)+ {+ mCallback = [handler](const asio::ip::udp::endpoint& from,+ const std::vector<uint8_t>& buffer) {+ handler(from, begin(buffer), end(buffer));+ };+ }++ template <typename It>+ void incomingMessage(+ const asio::ip::udp::endpoint& from, It messageBegin, It messageEnd)+ {+ std::vector<uint8_t> buffer{messageBegin, messageEnd};+ mCallback(from, buffer);+ }++ asio::ip::udp::endpoint endpoint() const+ {+ return asio::ip::udp::endpoint({}, 0);+ }++ using SentMessage = std::pair<std::vector<uint8_t>, asio::ip::udp::endpoint>;+ std::vector<SentMessage> sentMessages;++private:+ using ReceiveCallback =+ std::function<void(const asio::ip::udp::endpoint&, const std::vector<uint8_t>&)>;+ ReceiveCallback mCallback;+};++} // namespace test+} // namespace discovery+} // namespace ableton
+ link/include/ableton/discovery/v1/Messages.hpp view
@@ -0,0 +1,168 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/Payload.hpp>+#include <array>++namespace ableton+{+namespace discovery+{+namespace v1+{++// The maximum size of a message, in bytes+const std::size_t kMaxMessageSize = 512;+// Utility typedef for an array of bytes of maximum message size+using MessageBuffer = std::array<uint8_t, v1::kMaxMessageSize>;++using MessageType = uint8_t;+using SessionGroupId = uint16_t;++const MessageType kInvalid = 0;+const MessageType kAlive = 1;+const MessageType kResponse = 2;+const MessageType kByeBye = 3;++template <typename NodeId>+struct MessageHeader+{+ MessageType messageType;+ uint8_t ttl;+ SessionGroupId groupId;+ NodeId ident;++ friend std::uint32_t sizeInByteStream(const MessageHeader& header)+ {+ return discovery::sizeInByteStream(header.messageType)+ + discovery::sizeInByteStream(header.ttl)+ + discovery::sizeInByteStream(header.groupId)+ + discovery::sizeInByteStream(header.ident);+ }++ template <typename It>+ friend It toNetworkByteStream(const MessageHeader& header, It out)+ {+ return discovery::toNetworkByteStream(header.ident,+ discovery::toNetworkByteStream(header.groupId,+ discovery::toNetworkByteStream(header.ttl,+ discovery::toNetworkByteStream(header.messageType, std::move(out)))));+ }++ template <typename It>+ static std::pair<MessageHeader, It> fromNetworkByteStream(It begin, const It end)+ {+ using namespace std;++ MessageHeader header;+ tie(header.messageType, begin) =+ Deserialize<decltype(header.messageType)>::fromNetworkByteStream(begin, end);+ tie(header.ttl, begin) =+ Deserialize<decltype(header.ttl)>::fromNetworkByteStream(begin, end);+ tie(header.groupId, begin) =+ Deserialize<decltype(header.groupId)>::fromNetworkByteStream(begin, end);+ tie(header.ident, begin) =+ Deserialize<decltype(header.ident)>::fromNetworkByteStream(begin, end);++ return make_pair(std::move(header), std::move(begin));+ }+};++namespace detail+{++// Types that are only used in the sending/parsing of messages, not+// publicly exposed.+using ProtocolHeader = std::array<char, 8>;+const ProtocolHeader kProtocolHeader = {{'_', 'a', 's', 'd', 'p', '_', 'v', 1}};++// Must have at least kMaxMessageSize bytes available in the output stream+template <typename NodeId, typename Payload, typename It>+It encodeMessage(NodeId from,+ const uint8_t ttl,+ const MessageType messageType,+ const Payload& payload,+ It out)+{+ using namespace std;+ const MessageHeader<NodeId> header = {messageType, ttl, 0, std::move(from)};+ const auto messageSize =+ kProtocolHeader.size() + sizeInByteStream(header) + sizeInByteStream(payload);++ if (messageSize < kMaxMessageSize)+ {+ return toNetworkByteStream(+ payload, toNetworkByteStream(header,+ copy(begin(kProtocolHeader), end(kProtocolHeader), std::move(out))));+ }+ else+ {+ throw range_error("Exceeded maximum message size");+ }+}++} // namespace detail++template <typename NodeId, typename Payload, typename It>+It aliveMessage(NodeId from, const uint8_t ttl, const Payload& payload, It out)+{+ return detail::encodeMessage(std::move(from), ttl, kAlive, payload, std::move(out));+}++template <typename NodeId, typename Payload, typename It>+It responseMessage(NodeId from, const uint8_t ttl, const Payload& payload, It out)+{+ return detail::encodeMessage(std::move(from), ttl, kResponse, payload, std::move(out));+}++template <typename NodeId, typename It>+It byeByeMessage(NodeId from, It out)+{+ return detail::encodeMessage(+ std::move(from), 0, kByeBye, makePayload(), std::move(out));+}++template <typename NodeId, typename It>+std::pair<MessageHeader<NodeId>, It> parseMessageHeader(It bytesBegin, const It bytesEnd)+{+ using namespace std;+ using ItDiff = typename iterator_traits<It>::difference_type;++ MessageHeader<NodeId> header = {};+ const auto protocolHeaderSize = discovery::sizeInByteStream(detail::kProtocolHeader);+ const auto minMessageSize =+ static_cast<ItDiff>(protocolHeaderSize + sizeInByteStream(header));++ // If there are enough bytes in the stream to make a header and if+ // the first bytes in the stream are the protocol header, then+ // proceed to parse the stream.+ if (distance(bytesBegin, bytesEnd) >= minMessageSize+ && equal(begin(detail::kProtocolHeader), end(detail::kProtocolHeader), bytesBegin))+ {+ tie(header, bytesBegin) = MessageHeader<NodeId>::fromNetworkByteStream(+ bytesBegin + protocolHeaderSize, bytesEnd);+ }+ return make_pair(std::move(header), std::move(bytesBegin));+}++} // namespace v1+} // namespace discovery+} // namespace ableton
+ link/include/ableton/link/Beats.hpp view
@@ -0,0 +1,125 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/NetworkByteStreamSerializable.hpp>+#include <cmath>+#include <cstdint>++namespace ableton+{+namespace link+{++struct Beats+{+ Beats() = default;++ explicit Beats(const double beats)+ : mValue(std::llround(beats * 1e6))+ {+ }++ explicit Beats(const std::int64_t microBeats)+ : mValue(microBeats)+ {+ }++ double floating() const+ {+ return static_cast<double>(mValue) / 1e6;+ }++ std::int64_t microBeats() const+ {+ return mValue;+ }++ Beats operator-() const+ {+ return Beats{-mValue};+ }++ friend Beats abs(const Beats b)+ {+ return Beats{std::abs(b.mValue)};+ }++ friend Beats operator+(const Beats lhs, const Beats rhs)+ {+ return Beats{lhs.mValue + rhs.mValue};+ }++ friend Beats operator-(const Beats lhs, const Beats rhs)+ {+ return Beats{lhs.mValue - rhs.mValue};+ }++ friend Beats operator%(const Beats lhs, const Beats rhs)+ {+ return Beats{rhs.mValue == 0 ? 0 : (lhs.mValue % rhs.mValue)};+ }++ friend bool operator<(const Beats lhs, const Beats rhs)+ {+ return lhs.mValue < rhs.mValue;+ }++ friend bool operator>(const Beats lhs, const Beats rhs)+ {+ return lhs.mValue > rhs.mValue;+ }++ friend bool operator==(const Beats lhs, const Beats rhs)+ {+ return lhs.mValue == rhs.mValue;+ }++ friend bool operator!=(const Beats lhs, const Beats rhs)+ {+ return lhs.mValue != rhs.mValue;+ }++ // Model the NetworkByteStreamSerializable concept+ friend std::uint32_t sizeInByteStream(const Beats beats)+ {+ return discovery::sizeInByteStream(beats.microBeats());+ }++ template <typename It>+ friend It toNetworkByteStream(const Beats beats, It out)+ {+ return discovery::toNetworkByteStream(beats.microBeats(), std::move(out));+ }++ template <typename It>+ static std::pair<Beats, It> fromNetworkByteStream(It begin, It end)+ {+ auto result = discovery::Deserialize<std::int64_t>::fromNetworkByteStream(+ std::move(begin), std::move(end));+ return std::make_pair(Beats{result.first}, std::move(result.second));+ }++private:+ std::int64_t mValue = 0;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/ClientSessionTimelines.hpp view
@@ -0,0 +1,115 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/GhostXForm.hpp>+#include <ableton/link/Timeline.hpp>++namespace ableton+{+namespace link+{++// Clamp the tempo of the given timeline to the valid Link range+inline Timeline clampTempo(const Timeline timeline)+{+ const double kMinBpm = 20.0;+ const double kMaxBpm = 999.0;+ return {Tempo{(std::min)((std::max)(timeline.tempo.bpm(), kMinBpm), kMaxBpm)},+ timeline.beatOrigin, timeline.timeOrigin};+}++// Given an existing client timeline, a session timeline, and the+// global host transform of the session, return a new version of the client+// timeline. The resulting new client timeline is continuous with the+// previous timeline so that curClient.toBeats(atTime) ==+// result.toBeats(atTime).+inline Timeline updateClientTimelineFromSession(const Timeline curClient,+ const Timeline session,+ const std::chrono::microseconds atTime,+ const GhostXForm xform)+{+ // An intermediate timeline representing the continuation of the+ // existing client timeline with the tempo from the session timeline.+ const auto tempTl = Timeline{session.tempo, curClient.toBeats(atTime), atTime};+ // The host time corresponding to beat 0 on the session+ // timeline. Beat 0 on the session timeline is important because it+ // serves as the origin of the quantization grid for all participants.+ const auto hostBeatZero = xform.ghostToHost(session.fromBeats(Beats{INT64_C(0)}));+ // The new client timeline becomes the result of sliding the+ // intermediate timeline back so that it's anchor corresponds to+ // beat zero on the session timeline. The result preserves the+ // magnitude of beats on the client timeline while encoding the+ // quantization reference point in the time and beatOrigins.+ return {tempTl.tempo, tempTl.toBeats(hostBeatZero), hostBeatZero};+}+++inline Timeline updateSessionTimelineFromClient(const Timeline curSession,+ const Timeline client,+ const std::chrono::microseconds atTime,+ const GhostXForm xform)+{+ // The client timeline was constructed so that it's timeOrigin+ // corresponds to beat 0 on the session timeline.+ const auto ghostBeat0 = xform.hostToGhost(client.timeOrigin);++ const auto zero = Beats{INT64_C(0)};+ // If beat 0 was not shifted and there is not a new tempo, an update+ // of the session timeline is not required. Don't create an+ // equivalent timeline with different anchor points if not needed as+ // this will trigger other unnecessary changes.+ if (curSession.toBeats(ghostBeat0) == zero && client.tempo == curSession.tempo)+ {+ return curSession;+ }+ else+ {+ // An intermediate timeline representing the new tempo, the+ // effective time, and a possibly adjusted origin.+ const auto tempTl = Timeline{client.tempo, zero, ghostBeat0};+ // The final session timeline must have the beat corresponding to+ // atTime on the old session timeline as its beatOrigin because this is+ // used for prioritization of timelines among peers - we can't let a+ // modification applied by the client artificially increase or+ // reduce the timeline's priority in the session. The new beat+ // origin should be as close as possible to lining up with atTime,+ // but we must also make sure that it's > curSession.beatOrigin+ // because otherwise it will get ignored.+ const auto newBeatOrigin = (std::max)(curSession.toBeats(xform.hostToGhost(atTime)),+ curSession.beatOrigin + Beats{INT64_C(1)});+ return {client.tempo, newBeatOrigin, tempTl.fromBeats(newBeatOrigin)};+ }+}++// Shift timeline so result.toBeats(t) == client.toBeats(t) ++// shift. This takes into account the fact that the timeOrigin+// corresponds to beat 0 on the session timeline. Using this function+// and then setting the session timeline with the result will change+// the phase of the session by the given shift amount.+inline Timeline shiftClientTimeline(Timeline client, const Beats shift)+{+ const auto timeDelta = client.fromBeats(shift) - client.fromBeats(Beats{INT64_C(0)});+ client.timeOrigin = client.timeOrigin - timeDelta;+ return client;+}++} // namespace link+} // namespace ableton
+ link/include/ableton/link/Controller.hpp view
@@ -0,0 +1,792 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/Service.hpp>+#include <ableton/link/ClientSessionTimelines.hpp>+#include <ableton/link/Gateway.hpp>+#include <ableton/link/GhostXForm.hpp>+#include <ableton/link/NodeState.hpp>+#include <ableton/link/Peers.hpp>+#include <ableton/link/SessionState.hpp>+#include <ableton/link/Sessions.hpp>+#include <ableton/link/StartStopState.hpp>+#include <ableton/link/TripleBuffer.hpp>+#include <condition_variable>+#include <mutex>++namespace ableton+{+namespace link+{+namespace detail+{++template <typename Clock>+GhostXForm initXForm(const Clock& clock)+{+ // Make the current time map to a ghost time of 0 with ghost time+ // increasing at the same rate as clock time+ return {1.0, -clock.micros()};+}++template <typename Clock>+inline SessionState initSessionState(const Tempo tempo, const Clock& clock)+{+ using namespace std::chrono;+ return {clampTempo(Timeline{tempo, Beats{0.}, microseconds{0}}),+ StartStopState{false, Beats{0.}, microseconds{0}}, initXForm(clock)};+}++inline ClientState initClientState(const SessionState& sessionState)+{+ const auto hostTime = sessionState.ghostXForm.ghostToHost(std::chrono::microseconds{0});+ return {+ Timeline{sessionState.timeline.tempo, sessionState.timeline.beatOrigin, hostTime},+ ClientStartStopState{sessionState.startStopState.isPlaying, hostTime, hostTime}};+}++inline RtClientState initRtClientState(const ClientState& clientState)+{+ using namespace std::chrono;+ return {+ clientState.timeline, clientState.startStopState, microseconds{0}, microseconds{0}};+}++// The timespan in which local modifications to the timeline will be+// preferred over any modifications coming from the network.+const auto kLocalModGracePeriod = std::chrono::milliseconds(1000);+const auto kRtHandlerFallbackPeriod = kLocalModGracePeriod / 2;++inline ClientStartStopState selectPreferredStartStopState(+ const ClientStartStopState currentStartStopState,+ const ClientStartStopState startStopState)+{+ return startStopState.timestamp > currentStartStopState.timestamp+ ? startStopState+ : currentStartStopState;+}++inline ClientStartStopState mapStartStopStateFromSessionToClient(+ const StartStopState& sessionStartStopState,+ const Timeline& sessionTimeline,+ const GhostXForm& xForm)+{+ const auto time =+ xForm.ghostToHost(sessionTimeline.fromBeats(sessionStartStopState.beats));+ const auto timestamp = xForm.ghostToHost(sessionStartStopState.timestamp);+ return ClientStartStopState{sessionStartStopState.isPlaying, time, timestamp};+}++inline StartStopState mapStartStopStateFromClientToSession(+ const ClientStartStopState& clientStartStopState,+ const Timeline& sessionTimeline,+ const GhostXForm& xForm)+{+ const auto sessionBeats =+ sessionTimeline.toBeats(xForm.hostToGhost(clientStartStopState.time));+ const auto timestamp = xForm.hostToGhost(clientStartStopState.timestamp);+ return StartStopState{clientStartStopState.isPlaying, sessionBeats, timestamp};+}++} // namespace detail++// function types corresponding to the Controller callback type params+using PeerCountCallback = std::function<void(std::size_t)>;+using TempoCallback = std::function<void(ableton::link::Tempo)>;+using StartStopStateCallback = std::function<void(bool)>;+++// The main Link controller+template <typename PeerCountCallback,+ typename TempoCallback,+ typename StartStopStateCallback,+ typename Clock,+ typename Random,+ typename IoContext>+class Controller+{+public:+ Controller(Tempo tempo,+ PeerCountCallback peerCallback,+ TempoCallback tempoCallback,+ StartStopStateCallback startStopStateCallback,+ Clock clock)+ : mTempoCallback(std::move(tempoCallback))+ , mStartStopStateCallback(std::move(startStopStateCallback))+ , mClock(std::move(clock))+ , mNodeId(NodeId::random<Random>())+ , mSessionId(mNodeId)+ , mSessionState(detail::initSessionState(tempo, mClock))+ , mClientState(detail::initClientState(mSessionState))+ , mLastIsPlayingForStartStopStateCallback(false)+ , mRtClientState(detail::initRtClientState(mClientState.get()))+ , mHasPendingRtClientStates(false)+ , mSessionPeerCounter(*this, std::move(peerCallback))+ , mEnabled(false)+ , mStartStopSyncEnabled(false)+ , mIo(IoContext{UdpSendExceptionHandler{this}})+ , mRtClientStateSetter(*this)+ , mPeers(util::injectRef(*mIo),+ std::ref(mSessionPeerCounter),+ SessionTimelineCallback{*this},+ SessionStartStopStateCallback{*this})+ , mSessions(+ {mSessionId, mSessionState.timeline, {mSessionState.ghostXForm, mClock.micros()}},+ util::injectRef(mPeers),+ MeasurePeer{*this},+ JoinSessionCallback{*this},+ util::injectRef(*mIo),+ mClock)+ , mDiscovery(std::make_pair(NodeState{mNodeId, mSessionId, mSessionState.timeline,+ mSessionState.startStopState},+ mSessionState.ghostXForm),+ GatewayFactory{*this},+ util::injectRef(*mIo))+ {+ }++ Controller(const Controller&) = delete;+ Controller(Controller&&) = delete;++ Controller& operator=(const Controller&) = delete;+ Controller& operator=(Controller&&) = delete;++ ~Controller()+ {+ std::mutex mutex;+ std::condition_variable condition;+ auto stopped = false;++ mIo->async([this, &mutex, &condition, &stopped]() {+ enable(false);+ std::unique_lock<std::mutex> lock(mutex);+ stopped = true;+ condition.notify_one();+ });++ std::unique_lock<std::mutex> lock(mutex);+ condition.wait(lock, [&stopped] { return stopped; });++ mIo->stop();+ }++ void enable(const bool bEnable)+ {+ const bool bWasEnabled = mEnabled.exchange(bEnable);+ if (bWasEnabled != bEnable)+ {+ mIo->async([this, bEnable] {+ if (bEnable)+ {+ // Process the pending client states to make sure we don't push one after we+ // have joined a running session+ mRtClientStateSetter.processPendingClientStates();+ // Always reset when first enabling to avoid hijacking+ // tempo in existing sessions+ resetState();+ }+ mDiscovery.enable(bEnable);+ });+ }+ }++ bool isEnabled() const+ {+ return mEnabled;+ }++ void enableStartStopSync(const bool bEnable)+ {+ mStartStopSyncEnabled = bEnable;+ }++ bool isStartStopSyncEnabled() const+ {+ return mStartStopSyncEnabled;+ }++ std::size_t numPeers() const+ {+ return mSessionPeerCounter.mSessionPeerCount;+ }++ // Get the current Link client state. Thread-safe but may block, so+ // it cannot be used from audio thread.+ ClientState clientState() const+ {+ return mClientState.get();+ }++ // Set the client state to be used, starting at the given time.+ // Thread-safe but may block, so it cannot be used from audio thread.+ void setClientState(IncomingClientState newClientState)+ {+ mClientState.update([&](ClientState& clientState) {+ if (newClientState.timeline)+ {+ *newClientState.timeline = clampTempo(*newClientState.timeline);+ clientState.timeline = *newClientState.timeline;+ }+ if (newClientState.startStopState)+ {+ // Prevent updating client start stop state with an outdated start stop state+ *newClientState.startStopState = detail::selectPreferredStartStopState(+ clientState.startStopState, *newClientState.startStopState);+ clientState.startStopState = *newClientState.startStopState;+ }+ });+ mIo->async([this, newClientState] { handleClientState(newClientState); });+ }++ // Non-blocking client state access for a realtime context. NOT+ // thread-safe. Must not be called from multiple threads+ // concurrently and must not be called concurrently with setClientStateRtSafe.+ ClientState clientStateRtSafe() const+ {+ // Respect the session state guard and the client state guard but don't+ // block on them. If we can't access one or both because of concurrent modification+ // we fall back to our cached version of the timeline and/or start stop state.++ if (!mHasPendingRtClientStates)+ {+ const auto now = mClock.micros();+ const auto timelineGracePeriodOver =+ now - mRtClientState.timelineTimestamp > detail::kLocalModGracePeriod;+ const auto startStopStateGracePeriodOver =+ now - mRtClientState.startStopStateTimestamp > detail::kLocalModGracePeriod;++ if (timelineGracePeriodOver || startStopStateGracePeriodOver)+ {+ const auto clientState = mClientState.getRt();++ if (timelineGracePeriodOver && clientState.timeline != mRtClientState.timeline)+ {+ mRtClientState.timeline = clientState.timeline;+ }++ if (startStopStateGracePeriodOver+ && clientState.startStopState != mRtClientState.startStopState)+ {+ mRtClientState.startStopState = clientState.startStopState;+ }+ }+ }++ return {mRtClientState.timeline, mRtClientState.startStopState};+ }++ // should only be called from the audio thread+ void setClientStateRtSafe(IncomingClientState newClientState)+ {+ if (!newClientState.timeline && !newClientState.startStopState)+ {+ return;+ }++ if (newClientState.timeline)+ {+ *newClientState.timeline = clampTempo(*newClientState.timeline);+ }++ if (newClientState.startStopState)+ {+ // Prevent updating client start stop state with an outdated start stop state+ *newClientState.startStopState = detail::selectPreferredStartStopState(+ mRtClientState.startStopState, *newClientState.startStopState);+ }++ // This flag ensures that mRtClientState is only updated after all incoming+ // client states were processed+ mHasPendingRtClientStates = true;+ mRtClientStateSetter.push(newClientState);+ const auto now = mClock.micros();+ // Cache the new timeline and StartStopState for serving back to the client+ if (newClientState.timeline)+ {+ // Cache the new timeline and StartStopState for serving back to the client+ mRtClientState.timeline = *newClientState.timeline;+ mRtClientState.timelineTimestamp = makeRtTimestamp(now);+ }+ if (newClientState.startStopState)+ {+ mRtClientState.startStopState = *newClientState.startStopState;+ mRtClientState.startStopStateTimestamp = makeRtTimestamp(now);+ }+ }++private:+ std::chrono::microseconds makeRtTimestamp(const std::chrono::microseconds now) const+ {+ return isEnabled() ? now : std::chrono::microseconds(0);+ }++ void invokeStartStopStateCallbackIfChanged()+ {+ bool shouldInvokeCallback = false;++ mClientState.update([&](ClientState& clientState) {+ shouldInvokeCallback =+ mLastIsPlayingForStartStopStateCallback != clientState.startStopState.isPlaying;+ mLastIsPlayingForStartStopStateCallback = clientState.startStopState.isPlaying;+ });++ if (shouldInvokeCallback)+ {+ mStartStopStateCallback(mLastIsPlayingForStartStopStateCallback);+ }+ }++ void updateDiscovery()+ {+ // Push the change to the discovery service+ mDiscovery.updateNodeState(+ std::make_pair(NodeState{mNodeId, mSessionId, mSessionState.timeline,+ mSessionState.startStopState},+ mSessionState.ghostXForm));+ }++ void updateSessionTiming(Timeline newTimeline, const GhostXForm newXForm)+ {+ // Clamp the session tempo because it may slightly overshoot (999 bpm is+ // transferred as 60606 us/beat and received as 999.000999... bpm).+ newTimeline = clampTempo(newTimeline);+ const auto oldTimeline = mSessionState.timeline;+ const auto oldXForm = mSessionState.ghostXForm;++ if (oldTimeline != newTimeline || oldXForm != newXForm)+ {+ {+ std::lock_guard<std::mutex> lock(mSessionStateGuard);+ mSessionState.timeline = newTimeline;+ mSessionState.ghostXForm = newXForm;+ }++ // Update the client timeline and start stop state based on the new session timing+ mClientState.update([&](ClientState& clientState) {+ clientState.timeline = updateClientTimelineFromSession(clientState.timeline,+ mSessionState.timeline, mClock.micros(), mSessionState.ghostXForm);+ // Don't pass the start stop state to the client when start stop sync is disabled+ // or when we have a default constructed start stop state+ if (mStartStopSyncEnabled && mSessionState.startStopState != StartStopState{})+ {+ std::lock_guard<std::mutex> startStopStateLock(mSessionStateGuard);+ clientState.startStopState =+ detail::mapStartStopStateFromSessionToClient(mSessionState.startStopState,+ mSessionState.timeline, mSessionState.ghostXForm);+ }+ });++ if (oldTimeline.tempo != newTimeline.tempo)+ {+ mTempoCallback(newTimeline.tempo);+ }+ }+ }++ void handleTimelineFromSession(SessionId id, Timeline timeline)+ {+ debug(mIo->log()) << "Received timeline with tempo: " << timeline.tempo.bpm()+ << " for session: " << id;+ updateSessionTiming(mSessions.sawSessionTimeline(std::move(id), std::move(timeline)),+ mSessionState.ghostXForm);+ updateDiscovery();+ }++ void resetSessionStartStopState()+ {+ mSessionState.startStopState = StartStopState{};+ }++ void handleStartStopStateFromSession(SessionId sessionId, StartStopState startStopState)+ {+ debug(mIo->log()) << "Received start stop state. isPlaying: "+ << startStopState.isPlaying+ << ", beats: " << startStopState.beats.floating()+ << ", time: " << startStopState.timestamp.count()+ << " for session: " << sessionId;+ if (sessionId == mSessionId+ && startStopState.timestamp > mSessionState.startStopState.timestamp)+ {+ mSessionState.startStopState = startStopState;++ // Always propagate the session start stop state so even a client that doesn't have+ // the feature enabled can function as a relay.+ updateDiscovery();++ if (mStartStopSyncEnabled)+ {+ mClientState.update([&](ClientState& clientState) {+ clientState.startStopState = detail::mapStartStopStateFromSessionToClient(+ startStopState, mSessionState.timeline, mSessionState.ghostXForm);+ });+ invokeStartStopStateCallbackIfChanged();+ }+ }+ }++ void handleClientState(const IncomingClientState clientState)+ {+ auto mustUpdateDiscovery = false;++ if (clientState.timeline)+ {+ auto sessionTimeline = updateSessionTimelineFromClient(mSessionState.timeline,+ *clientState.timeline, clientState.timelineTimestamp, mSessionState.ghostXForm);++ mSessions.resetTimeline(sessionTimeline);+ mPeers.setSessionTimeline(mSessionId, sessionTimeline);+ updateSessionTiming(std::move(sessionTimeline), mSessionState.ghostXForm);++ mustUpdateDiscovery = true;+ }++ if (mStartStopSyncEnabled && clientState.startStopState)+ {+ // Prevent updating with an outdated start stop state+ const auto newGhostTime =+ mSessionState.ghostXForm.hostToGhost(clientState.startStopState->timestamp);+ if (newGhostTime > mSessionState.startStopState.timestamp)+ {+ mClientState.update([&](ClientState& currentClientState) {+ mSessionState.startStopState =+ detail::mapStartStopStateFromClientToSession(*clientState.startStopState,+ mSessionState.timeline, mSessionState.ghostXForm);+ currentClientState.startStopState = *clientState.startStopState;+ });++ mustUpdateDiscovery = true;+ }+ }++ if (mustUpdateDiscovery)+ {+ updateDiscovery();+ }++ invokeStartStopStateCallbackIfChanged();+ }++ void handleRtClientState(IncomingClientState clientState)+ {+ mClientState.update([&](ClientState& currentClientState) {+ if (clientState.timeline)+ {+ currentClientState.timeline = *clientState.timeline;+ }+ if (clientState.startStopState)+ {+ // Prevent updating client start stop state with an outdated start stop state+ *clientState.startStopState = detail::selectPreferredStartStopState(+ currentClientState.startStopState, *clientState.startStopState);+ currentClientState.startStopState = *clientState.startStopState;+ }+ });++ handleClientState(clientState);+ mHasPendingRtClientStates = false;+ }++ void joinSession(const Session& session)+ {+ const bool sessionIdChanged = mSessionId != session.sessionId;+ mSessionId = session.sessionId;++ // Prevent passing the state of the previous session to the new one.+ if (sessionIdChanged)+ {+ mRtClientStateSetter.processPendingClientStates();+ resetSessionStartStopState();+ }++ updateSessionTiming(session.timeline, session.measurement.xform);+ updateDiscovery();++ if (sessionIdChanged)+ {+ debug(mIo->log()) << "Joining session " << session.sessionId << " with tempo "+ << session.timeline.tempo.bpm();+ mSessionPeerCounter();+ }+ }++ void resetState()+ {+ mNodeId = NodeId::random<Random>();+ mSessionId = mNodeId;++ const auto xform = detail::initXForm(mClock);+ const auto hostTime = -xform.intercept;+ // When creating the new timeline, make it continuous by finding+ // the beat on the old session timeline corresponding to the+ // current host time and mapping it to the new ghost time+ // representation of the current host time.+ const auto newTl = Timeline{mSessionState.timeline.tempo,+ mSessionState.timeline.toBeats(mSessionState.ghostXForm.hostToGhost(hostTime)),+ xform.hostToGhost(hostTime)};++ resetSessionStartStopState();++ updateSessionTiming(newTl, xform);+ updateDiscovery();++ mSessions.resetSession({mNodeId, newTl, {xform, hostTime}});+ mPeers.resetPeers();+ }++ struct SessionTimelineCallback+ {+ void operator()(SessionId id, Timeline timeline)+ {+ mController.handleTimelineFromSession(std::move(id), std::move(timeline));+ }++ Controller& mController;+ };++ struct RtClientStateSetter+ {+ using CallbackDispatcher =+ typename IoContext::template LockFreeCallbackDispatcher<std::function<void()>,+ std::chrono::milliseconds>;++ RtClientStateSetter(Controller& controller)+ : mController(controller)+ , mCallbackDispatcher(+ [this] { mController.mIo->async([this]() { processPendingClientStates(); }); },+ detail::kRtHandlerFallbackPeriod)+ {+ }++ void push(const IncomingClientState clientState)+ {+ if (clientState.timeline)+ {+ mTimelineBuffer.write(+ std::make_pair(clientState.timelineTimestamp, *clientState.timeline));+ }++ if (clientState.startStopState)+ {+ mStartStopStateBuffer.write(*clientState.startStopState);+ }++ if (clientState.timeline || clientState.startStopState)+ {+ mCallbackDispatcher.invoke();+ }+ }++ void processPendingClientStates()+ {+ const auto clientState = buildMergedPendingClientState();+ mController.handleRtClientState(clientState);+ }++ private:+ IncomingClientState buildMergedPendingClientState()+ {+ auto clientState = IncomingClientState{};+ if (auto tl = mTimelineBuffer.readNew())+ {+ clientState.timelineTimestamp = (*tl).first;+ clientState.timeline = OptionalTimeline{(*tl).second};+ }+ if (auto sss = mStartStopStateBuffer.readNew())+ {+ clientState.startStopState = sss;+ }+ return clientState;+ }++ Controller& mController;+ // Use separate TripleBuffers for the Timeline and the StartStopState so we read the+ // latest set value from either optional.+ TripleBuffer<std::pair<std::chrono::microseconds, Timeline>> mTimelineBuffer;+ TripleBuffer<ClientStartStopState> mStartStopStateBuffer;+ CallbackDispatcher mCallbackDispatcher;+ };++ struct SessionStartStopStateCallback+ {+ void operator()(SessionId sessionId, StartStopState startStopState)+ {+ mController.handleStartStopStateFromSession(sessionId, startStopState);+ }++ Controller& mController;+ };++ struct SessionPeerCounter+ {+ SessionPeerCounter(Controller& controller, PeerCountCallback callback)+ : mController(controller)+ , mCallback(std::move(callback))+ , mSessionPeerCount(0)+ {+ }++ void operator()()+ {+ const auto count =+ mController.mPeers.uniqueSessionPeerCount(mController.mSessionId);+ const auto oldCount = mSessionPeerCount.exchange(count);+ if (oldCount != count)+ {+ if (count == 0)+ {+ // When the count goes down to zero, completely reset the+ // state, effectively founding a new session+ mController.mIo->async([this] { mController.resetState(); });+ }+ mCallback(count);+ }+ }++ Controller& mController;+ PeerCountCallback mCallback;+ std::atomic<std::size_t> mSessionPeerCount;+ };++ struct MeasurePeer+ {+ template <typename Peer, typename Handler>+ void operator()(Peer peer, Handler handler)+ {+ using It = typename Discovery::ServicePeerGateways::GatewayMap::iterator;+ using ValueType = typename Discovery::ServicePeerGateways::GatewayMap::value_type;+ mController.mDiscovery.withGateways([peer, handler](It begin, const It end) {+ const auto addr = peer.second;+ const auto it = std::find_if(+ begin, end, [&addr](const ValueType& vt) { return vt.first == addr; });+ if (it != end)+ {+ it->second->measurePeer(std::move(peer.first), std::move(handler));+ }+ else+ {+ // invoke the handler with an empty result if we couldn't+ // find the peer's gateway+ handler(GhostXForm{});+ }+ });+ }++ Controller& mController;+ };++ struct JoinSessionCallback+ {+ void operator()(Session session)+ {+ mController.joinSession(std::move(session));+ }++ Controller& mController;+ };++ using IoType = typename util::Injected<IoContext>::type;++ using ControllerPeers = Peers<IoType&,+ std::reference_wrapper<SessionPeerCounter>,+ SessionTimelineCallback,+ SessionStartStopStateCallback>;++ using ControllerGateway =+ Gateway<typename ControllerPeers::GatewayObserver, Clock, IoType&>;+ using GatewayPtr = std::shared_ptr<ControllerGateway>;++ struct GatewayFactory+ {+ GatewayPtr operator()(std::pair<NodeState, GhostXForm> state,+ util::Injected<IoType&> io,+ const asio::ip::address& addr)+ {+ if (addr.is_v4())+ {+ return GatewayPtr{new ControllerGateway{std::move(io), addr.to_v4(),+ util::injectVal(makeGatewayObserver(mController.mPeers, addr)),+ std::move(state.first), std::move(state.second), mController.mClock}};+ }+ else+ {+ throw std::runtime_error("Could not create peer gateway on non-ipV4 address");+ }+ }++ Controller& mController;+ };++ struct UdpSendExceptionHandler+ {+ using Exception = discovery::UdpSendException;++ void operator()(const Exception exception)+ {+ mpController->mIo->async([this, exception] {+ mpController->mDiscovery.repairGateway(exception.interfaceAddr);+ });+ }++ Controller* mpController;+ };++ TempoCallback mTempoCallback;+ StartStopStateCallback mStartStopStateCallback;+ Clock mClock;+ NodeId mNodeId;+ SessionId mSessionId;++ mutable std::mutex mSessionStateGuard;+ SessionState mSessionState;++ ControllerClientState mClientState;+ bool mLastIsPlayingForStartStopStateCallback;++ mutable RtClientState mRtClientState;+ std::atomic<bool> mHasPendingRtClientStates;++ SessionPeerCounter mSessionPeerCounter;++ std::atomic<bool> mEnabled;++ std::atomic<bool> mStartStopSyncEnabled;++ util::Injected<IoContext> mIo;++ RtClientStateSetter mRtClientStateSetter;++ ControllerPeers mPeers;++ using ControllerSessions = Sessions<ControllerPeers&,+ MeasurePeer,+ JoinSessionCallback,+ typename util::Injected<IoContext>::type&,+ Clock>;+ ControllerSessions mSessions;++ using Discovery = discovery::Service<std::pair<NodeState, GhostXForm>,+ GatewayFactory,+ typename util::Injected<IoContext>::type&>;+ Discovery mDiscovery;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/Gateway.hpp view
@@ -0,0 +1,93 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/PeerGateway.hpp>+#include <ableton/link/MeasurementService.hpp>+#include <ableton/link/PeerState.hpp>++namespace ableton+{+namespace link+{++template <typename PeerObserver, typename Clock, typename IoContext>+class Gateway+{+public:+ Gateway(util::Injected<IoContext> io,+ asio::ip::address_v4 addr,+ util::Injected<PeerObserver> observer,+ NodeState nodeState,+ GhostXForm ghostXForm,+ Clock clock)+ : mIo(std::move(io))+ , mMeasurement(addr,+ nodeState.sessionId,+ std::move(ghostXForm),+ std::move(clock),+ util::injectRef(*mIo))+ , mPeerGateway(discovery::makeIpV4Gateway(util::injectRef(*mIo),+ std::move(addr),+ std::move(observer),+ PeerState{std::move(nodeState), mMeasurement.endpoint()}))+ {+ }++ Gateway(const Gateway& rhs) = delete;+ Gateway& operator=(const Gateway& rhs) = delete;++ Gateway(Gateway&& rhs)+ : mIo(std::move(rhs.mIo))+ , mMeasurement(std::move(rhs.mMeasurement))+ , mPeerGateway(std::move(rhs.mPeerGateway))+ {+ }++ Gateway& operator=(Gateway&& rhs)+ {+ mIo = std::move(rhs.mIo);+ mMeasurement = std::move(rhs.mMeasurement);+ mPeerGateway = std::move(rhs.mPeerGateway);+ return *this;+ }++ void updateNodeState(std::pair<NodeState, GhostXForm> state)+ {+ mMeasurement.updateNodeState(state.first.sessionId, state.second);+ mPeerGateway.updateState(PeerState{std::move(state.first), mMeasurement.endpoint()});+ }++ template <typename Handler>+ void measurePeer(const PeerState& peer, Handler handler)+ {+ mMeasurement.measurePeer(peer, std::move(handler));+ }++private:+ util::Injected<IoContext> mIo;+ MeasurementService<Clock, typename util::Injected<IoContext>::type&> mMeasurement;+ discovery::+ IpV4Gateway<PeerObserver, PeerState, typename util::Injected<IoContext>::type&>+ mPeerGateway;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/GhostXForm.hpp view
@@ -0,0 +1,61 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <chrono>+#include <cmath>++namespace ableton+{+namespace link+{++using std::chrono::microseconds;++struct GhostXForm+{+ microseconds hostToGhost(const microseconds hostTime) const+ {+ return microseconds{llround(slope * static_cast<double>(hostTime.count()))}+ + intercept;+ }++ microseconds ghostToHost(const microseconds ghostTime) const+ {+ return microseconds{+ llround(static_cast<double>((ghostTime - intercept).count()) / slope)};+ }++ friend bool operator==(const GhostXForm lhs, const GhostXForm rhs)+ {+ return lhs.slope == rhs.slope && lhs.intercept == rhs.intercept;+ }++ friend bool operator!=(const GhostXForm lhs, const GhostXForm rhs)+ {+ return !(lhs == rhs);+ }++ double slope;+ microseconds intercept;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/HostTimeFilter.hpp view
@@ -0,0 +1,86 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/LinearRegression.hpp>+#include <chrono>+#include <cmath>+#include <utility>+#include <vector>++namespace ableton+{+namespace link+{++template <typename Clock, typename NumberType, std::size_t kNumPoints = 512>+class BasicHostTimeFilter+{+ using Points = std::vector<std::pair<NumberType, NumberType>>;+ using PointIt = typename Points::iterator;++public:+ BasicHostTimeFilter()+ : mIndex(0)+ {+ mPoints.reserve(kNumPoints);+ }++ ~BasicHostTimeFilter() = default;++ void reset()+ {+ mIndex = 0;+ mPoints.clear();+ }++ std::chrono::microseconds sampleTimeToHostTime(const NumberType sampleTime)+ {+ const auto micros = static_cast<NumberType>(mHostTimeSampler.micros().count());+ const auto point = std::make_pair(sampleTime, micros);++ if (mPoints.size() < kNumPoints)+ {+ mPoints.push_back(point);+ }+ else+ {+ mPoints[mIndex] = point;+ }+ mIndex = (mIndex + 1) % kNumPoints;++ const auto result = linearRegression(mPoints.begin(), mPoints.end());++ const auto hostTime = (result.first * sampleTime) + result.second;++ return std::chrono::microseconds(llround(hostTime));+ }++private:+ std::size_t mIndex;+ Points mPoints;+ Clock mHostTimeSampler;+};++template <typename Clock>+using HostTimeFilter = BasicHostTimeFilter<Clock, double, 512>;++} // namespace link+} // namespace ableton
+ link/include/ableton/link/LinearRegression.hpp view
@@ -0,0 +1,61 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <cassert>+#include <iterator>+#include <utility>++namespace ableton+{+namespace link+{++template <typename It>+typename std::iterator_traits<It>::value_type linearRegression(It begin, It end)+{+ using NumberType =+ typename std::tuple_element<0, typename std::iterator_traits<It>::value_type>::type;++ NumberType sumX = 0.0;+ NumberType sumXX = 0.0;+ NumberType sumXY = 0.0;+ NumberType sumY = 0.0;+ for (auto i = begin; i != end; ++i)+ {+ sumX += i->first;+ sumXX += i->first * i->first;+ sumXY += i->first * i->second;+ sumY += i->second;+ }++ const NumberType numPoints = static_cast<NumberType>(distance(begin, end));+ assert(numPoints > 0);+ const NumberType denominator = numPoints * sumXX - sumX * sumX;+ const NumberType slope = denominator == NumberType{0}+ ? NumberType{0}+ : (numPoints * sumXY - sumX * sumY) / denominator;+ const NumberType intercept = (sumY - slope * sumX) / numPoints;++ return std::make_pair(slope, intercept);+}++} // namespace link+} // namespace ableton
+ link/include/ableton/link/Measurement.hpp view
@@ -0,0 +1,250 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/Payload.hpp>+#include <ableton/link/PayloadEntries.hpp>+#include <ableton/link/PeerState.hpp>+#include <ableton/link/SessionId.hpp>+#include <ableton/link/v1/Messages.hpp>+#include <ableton/util/Injected.hpp>+#include <ableton/util/SafeAsyncHandler.hpp>+#include <chrono>+#include <memory>++namespace ableton+{+namespace link+{++template <typename Clock, typename IoContext>+struct Measurement+{+ using Callback = std::function<void(std::vector<double>&)>;+ using Micros = std::chrono::microseconds;++ static const std::size_t kNumberDataPoints = 100;+ static const std::size_t kNumberMeasurements = 5;++ Measurement(const PeerState& state,+ Callback callback,+ asio::ip::address_v4 address,+ Clock clock,+ util::Injected<IoContext> io)+ : mIo(std::move(io))+ , mpImpl(std::make_shared<Impl>(+ std::move(state), std::move(callback), std::move(address), std::move(clock), mIo))+ {+ mpImpl->listen();+ }++ Measurement(const Measurement&) = delete;+ Measurement& operator=(Measurement&) = delete;+ Measurement(const Measurement&&) = delete;+ Measurement& operator=(Measurement&&) = delete;++ struct Impl : std::enable_shared_from_this<Impl>+ {+ using Socket =+ typename util::Injected<IoContext>::type::template Socket<v1::kMaxMessageSize>;+ using Timer = typename util::Injected<IoContext>::type::Timer;+ using Log = typename util::Injected<IoContext>::type::Log;++ Impl(const PeerState& state,+ Callback callback,+ asio::ip::address_v4 address,+ Clock clock,+ util::Injected<IoContext> io)+ : mSocket(io->template openUnicastSocket<v1::kMaxMessageSize>(address))+ , mSessionId(state.nodeState.sessionId)+ , mEndpoint(state.endpoint)+ , mCallback(std::move(callback))+ , mClock(std::move(clock))+ , mTimer(io->makeTimer())+ , mMeasurementsStarted(0)+ , mLog(channel(io->log(), "Measurement on gateway@" + address.to_string()))+ , mSuccess(false)+ {+ const auto ht = HostTime{mClock.micros()};+ sendPing(mEndpoint, discovery::makePayload(ht));+ resetTimer();+ }++ void resetTimer()+ {+ mTimer.cancel();+ mTimer.expires_from_now(std::chrono::milliseconds(50));+ mTimer.async_wait([this](const typename Timer::ErrorCode e) {+ if (!e)+ {+ if (mMeasurementsStarted < kNumberMeasurements)+ {+ const auto ht = HostTime{mClock.micros()};+ sendPing(mEndpoint, discovery::makePayload(ht));+ ++mMeasurementsStarted;+ resetTimer();+ }+ else+ {+ fail();+ }+ }+ });+ }++ void listen()+ {+ mSocket.receive(util::makeAsyncSafe(this->shared_from_this()));+ }++ // Operator to handle incoming messages on the interface+ template <typename It>+ void operator()(+ const asio::ip::udp::endpoint& from, const It messageBegin, const It messageEnd)+ {+ using namespace std;+ const auto result = v1::parseMessageHeader(messageBegin, messageEnd);+ const auto& header = result.first;+ const auto payloadBegin = result.second;++ if (header.messageType == v1::kPong)+ {+ debug(mLog) << "Received Pong message from " << from;++ // parse for all entries+ SessionId sessionId{};+ std::chrono::microseconds ghostTime{0};+ std::chrono::microseconds prevGHostTime{0};+ std::chrono::microseconds prevHostTime{0};++ try+ {+ discovery::parsePayload<SessionMembership, GHostTime, PrevGHostTime, HostTime>(+ payloadBegin, messageEnd,+ [&sessionId](const SessionMembership& sms) { sessionId = sms.sessionId; },+ [&ghostTime](GHostTime gt) { ghostTime = std::move(gt.time); },+ [&prevGHostTime](PrevGHostTime gt) { prevGHostTime = std::move(gt.time); },+ [&prevHostTime](HostTime ht) { prevHostTime = std::move(ht.time); });+ }+ catch (const std::runtime_error& err)+ {+ warning(mLog) << "Failed parsing payload, caught exception: " << err.what();+ listen();+ return;+ }++ if (mSessionId == sessionId)+ {+ const auto hostTime = mClock.micros();++ const auto payload =+ discovery::makePayload(HostTime{hostTime}, PrevGHostTime{ghostTime});++ sendPing(from, payload);+ listen();+++ if (ghostTime != Micros{0} && prevHostTime != Micros{0})+ {+ mData.push_back(+ static_cast<double>(ghostTime.count())+ - (static_cast<double>((hostTime + prevHostTime).count()) * 0.5));++ if (prevGHostTime != Micros{0})+ {+ mData.push_back(+ (static_cast<double>((ghostTime + prevGHostTime).count()) * 0.5)+ - static_cast<double>(prevHostTime.count()));+ }+ }++ if (mData.size() > kNumberDataPoints)+ {+ finish();+ }+ else+ {+ resetTimer();+ }+ }+ else+ {+ fail();+ }+ }+ else+ {+ debug(mLog) << "Received invalid message from " << from;+ listen();+ }+ }++ template <typename Payload>+ void sendPing(asio::ip::udp::endpoint to, const Payload& payload)+ {+ v1::MessageBuffer buffer;+ const auto msgBegin = std::begin(buffer);+ const auto msgEnd = v1::pingMessage(payload, msgBegin);+ const auto numBytes = static_cast<size_t>(std::distance(msgBegin, msgEnd));++ try+ {+ mSocket.send(buffer.data(), numBytes, to);+ }+ catch (const std::runtime_error& err)+ {+ info(mLog) << "Failed to send Ping to " << to.address().to_string() << ": "+ << err.what();+ }+ }++ void finish()+ {+ mTimer.cancel();+ mSuccess = true;+ debug(mLog) << "Measuring " << mEndpoint << " done.";+ mCallback(mData);+ }++ void fail()+ {+ mData.clear();+ debug(mLog) << "Measuring " << mEndpoint << " failed.";+ mCallback(mData);+ }++ Socket mSocket;+ SessionId mSessionId;+ asio::ip::udp::endpoint mEndpoint;+ std::vector<double> mData;+ Callback mCallback;+ Clock mClock;+ Timer mTimer;+ std::size_t mMeasurementsStarted;+ Log mLog;+ bool mSuccess;+ };++ util::Injected<IoContext> mIo;+ std::shared_ptr<Impl> mpImpl;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/MeasurementEndpointV4.hpp view
@@ -0,0 +1,69 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/NetworkByteStreamSerializable.hpp>+#include <ableton/platforms/asio/AsioWrapper.hpp>++namespace ableton+{+namespace link+{++struct MeasurementEndpointV4+{+ static const std::int32_t key = 'mep4';+ static_assert(key == 0x6d657034, "Unexpected byte order");++ // Model the NetworkByteStreamSerializable concept+ friend std::uint32_t sizeInByteStream(const MeasurementEndpointV4 mep)+ {+ return discovery::sizeInByteStream(+ static_cast<std::uint32_t>(mep.ep.address().to_v4().to_ulong()))+ + discovery::sizeInByteStream(mep.ep.port());+ }++ template <typename It>+ friend It toNetworkByteStream(const MeasurementEndpointV4 mep, It out)+ {+ return discovery::toNetworkByteStream(mep.ep.port(),+ discovery::toNetworkByteStream(+ static_cast<std::uint32_t>(mep.ep.address().to_v4().to_ulong()), std::move(out)));+ }++ template <typename It>+ static std::pair<MeasurementEndpointV4, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ auto addrRes =+ discovery::Deserialize<std::uint32_t>::fromNetworkByteStream(std::move(begin), end);+ auto portRes = discovery::Deserialize<std::uint16_t>::fromNetworkByteStream(+ std::move(addrRes.second), end);+ return make_pair(+ MeasurementEndpointV4{+ {asio::ip::address_v4{std::move(addrRes.first)}, std::move(portRes.first)}},+ std::move(portRes.second));+ }++ asio::ip::udp::endpoint ep;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/MeasurementService.hpp view
@@ -0,0 +1,144 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/GhostXForm.hpp>+#include <ableton/link/LinearRegression.hpp>+#include <ableton/link/Measurement.hpp>+#include <ableton/link/Median.hpp>+#include <ableton/link/PeerState.hpp>+#include <ableton/link/PingResponder.hpp>+#include <ableton/link/SessionId.hpp>+#include <ableton/link/v1/Messages.hpp>+#include <map>+#include <memory>++namespace ableton+{+namespace link+{++template <typename Clock, typename IoContext>+class MeasurementService+{+public:+ using IoType = util::Injected<IoContext>;+ using MeasurementInstance = Measurement<Clock, IoContext>;++ MeasurementService(asio::ip::address_v4 address,+ SessionId sessionId,+ GhostXForm ghostXForm,+ Clock clock,+ IoType io)+ : mClock(std::move(clock))+ , mIo(std::move(io))+ , mPingResponder(std::move(address),+ std::move(sessionId),+ std::move(ghostXForm),+ mClock,+ util::injectRef(*mIo))+ {+ }++ MeasurementService(const MeasurementService&) = delete;+ MeasurementService(MeasurementService&&) = delete;++ void updateNodeState(const SessionId& sessionId, const GhostXForm& xform)+ {+ mPingResponder.updateNodeState(sessionId, xform);+ }++ asio::ip::udp::endpoint endpoint() const+ {+ return mPingResponder.endpoint();+ }++ // Measure the peer and invoke the handler with a GhostXForm+ template <typename Handler>+ void measurePeer(const PeerState& state, const Handler handler)+ {+ using namespace std;++ const auto nodeId = state.nodeState.nodeId;+ auto addr = mPingResponder.endpoint().address().to_v4();+ auto callback = CompletionCallback<Handler>{*this, nodeId, handler};++ try+ {+ mMeasurementMap[nodeId] =+ std::unique_ptr<MeasurementInstance>(new MeasurementInstance{+ state, std::move(callback), std::move(addr), mClock, mIo});+ }+ catch (const runtime_error& err)+ {+ info(mIo->log()) << "gateway@" + addr.to_string()+ << " Failed to measure. Reason: " << err.what();+ handler(GhostXForm{});+ }+ }++private:+ template <typename Handler>+ struct CompletionCallback+ {+ void operator()(std::vector<double>& data)+ {+ using namespace std;+ using std::chrono::microseconds;++ // Post this to the measurement service's IoContext so that we+ // don't delete the measurement object in its stack. Capture all+ // needed data separately from this, since this object may be+ // gone by the time the block gets executed.+ auto nodeId = mNodeId;+ auto handler = mHandler;+ auto& measurementMap = mMeasurementService.mMeasurementMap;+ const auto it = measurementMap.find(nodeId);+ if (it != measurementMap.end())+ {+ if (data.empty())+ {+ handler(GhostXForm{});+ }+ else+ {+ handler(GhostXForm{1, microseconds(llround(median(data.begin(), data.end())))});+ }+ measurementMap.erase(it);+ }+ }++ MeasurementService& mMeasurementService;+ NodeId mNodeId;+ Handler mHandler;+ };++ // Make sure the measurement map outlives the IoContext so that the rest of+ // the members are guaranteed to be valid when any final handlers+ // are begin run.+ using MeasurementMap = std::map<NodeId, std::unique_ptr<MeasurementInstance>>;+ MeasurementMap mMeasurementMap;+ Clock mClock;+ IoType mIo;+ PingResponder<Clock, IoContext> mPingResponder;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/Median.hpp view
@@ -0,0 +1,50 @@+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <algorithm>+#include <cassert>+#include <vector>++namespace ableton+{+namespace link+{++template <typename It>+double median(It begin, It end)+{+ const auto n = std::distance(begin, end);+ assert(n > 2);+ if (n % 2 == 0)+ {+ std::nth_element(begin, begin + n / 2, end);+ std::nth_element(begin, begin + (n - 1) / 2, end);+ return (*(begin + (n / 2)) + *(begin + (n - 1) / 2)) / 2.0;+ }+ else+ {+ std::nth_element(begin, begin + n / 2, end);+ return *(begin + (n / 2));+ }+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/NodeId.hpp view
@@ -0,0 +1,78 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/NetworkByteStreamSerializable.hpp>+#include <algorithm>+#include <array>+#include <cstdint>+#include <string>++namespace ableton+{+namespace link+{++using NodeIdArray = std::array<std::uint8_t, 8>;++struct NodeId : NodeIdArray+{+ NodeId() = default;++ NodeId(NodeIdArray rhs)+ : NodeIdArray(std::move(rhs))+ {+ }++ template <typename Random>+ static NodeId random()+ {+ using namespace std;+ NodeId nodeId;++ Random random;+ generate(nodeId.begin(), nodeId.end(), [&] { return random(); });++ return nodeId;+ }++ friend std::ostream& operator<<(std::ostream& stream, const NodeId& id)+ {+ return stream << std::string{id.cbegin(), id.cend()};+ }++ template <typename It>+ friend It toNetworkByteStream(const NodeId& nodeId, It out)+ {+ return discovery::toNetworkByteStream(nodeId, std::move(out));+ }++ template <typename It>+ static std::pair<NodeId, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ auto result = discovery::Deserialize<NodeIdArray>::fromNetworkByteStream(+ std::move(begin), std::move(end));+ return make_pair(NodeId(std::move(result.first)), std::move(result.second));+ }+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/NodeState.hpp view
@@ -0,0 +1,77 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/Payload.hpp>+#include <ableton/link/NodeId.hpp>+#include <ableton/link/SessionId.hpp>+#include <ableton/link/StartStopState.hpp>+#include <ableton/link/Timeline.hpp>++namespace ableton+{+namespace link+{++struct NodeState+{+ using Payload =+ decltype(discovery::makePayload(Timeline{}, SessionMembership{}, StartStopState{}));++ NodeId ident() const+ {+ return nodeId;+ }++ friend bool operator==(const NodeState& lhs, const NodeState& rhs)+ {+ return std::tie(lhs.nodeId, lhs.sessionId, lhs.timeline, lhs.startStopState)+ == std::tie(rhs.nodeId, rhs.sessionId, rhs.timeline, rhs.startStopState);+ }++ friend Payload toPayload(const NodeState& state)+ {+ return discovery::makePayload(+ state.timeline, SessionMembership{state.sessionId}, state.startStopState);+ }++ template <typename It>+ static NodeState fromPayload(NodeId nodeId, It begin, It end)+ {+ using namespace std;+ auto nodeState = NodeState{std::move(nodeId), {}, {}, {}};+ discovery::parsePayload<Timeline, SessionMembership, StartStopState>(std::move(begin),+ std::move(end), [&nodeState](Timeline tl) { nodeState.timeline = std::move(tl); },+ [&nodeState](SessionMembership membership) {+ nodeState.sessionId = std::move(membership.sessionId);+ },+ [&nodeState](+ StartStopState ststst) { nodeState.startStopState = std::move(ststst); });+ return nodeState;+ }++ NodeId nodeId;+ SessionId sessionId;+ Timeline timeline;+ StartStopState startStopState;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/Optional.hpp view
@@ -0,0 +1,97 @@+/* Copyright 2017, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <cassert>+#include <utility>++namespace ableton+{+namespace link+{++// Subset of the C++ 17 std::optional API. T has to be default constructible.+template <typename T>+struct Optional+{+ Optional()+ : mHasValue(false)+ {+ }++ explicit Optional(T value)+ : mValue(std::move(value))+ , mHasValue(true)+ {+ }++ Optional(const Optional&) = default;++ Optional(Optional&& other)+ : mValue(std::move(other.mValue))+ , mHasValue(other.mHasValue)+ {+ }++ Optional& operator=(const Optional&) = default;++ Optional& operator=(Optional&& other)+ {+ mValue = std::move(other.mValue);+ mHasValue = other.mHasValue;+ return *this;+ }++ explicit operator bool() const+ {+ return mHasValue;+ }++ const T& operator*() const+ {+ assert(mHasValue);+ return mValue;+ }++ T& operator*()+ {+ assert(mHasValue);+ return mValue;+ }++ const T* operator->() const+ {+ assert(mHasValue);+ return &mValue;+ }++ T* operator->()+ {+ assert(mHasValue);+ return &mValue;+ }++private:+ T mValue;+ bool mHasValue;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/PayloadEntries.hpp view
@@ -0,0 +1,140 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/NetworkByteStreamSerializable.hpp>+#include <cmath>+#include <cstdint>++namespace ableton+{+namespace link+{++struct HostTime+{+ static const std::int32_t key = '__ht';+ static_assert(key == 0x5f5f6874, "Unexpected byte order");++ HostTime() = default;++ HostTime(const std::chrono::microseconds tm)+ : time(tm)+ {+ }++ // Model the NetworkByteStreamSerializable concept+ friend std::uint32_t sizeInByteStream(const HostTime& sht)+ {+ return discovery::sizeInByteStream(std::move(sht.time));+ }++ template <typename It>+ friend It toNetworkByteStream(const HostTime& sht, It out)+ {+ return discovery::toNetworkByteStream(std::move(sht.time), std::move(out));+ }++ template <typename It>+ static std::pair<HostTime, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ auto result = discovery::Deserialize<chrono::microseconds>::fromNetworkByteStream(+ std::move(begin), std::move(end));+ return make_pair(HostTime{std::move(result.first)}, std::move(result.second));+ }++ std::chrono::microseconds time;+};++struct GHostTime+{+ static const std::int32_t key = '__gt';+ static_assert(key == 0x5f5f6774, "Unexpected byte order");++ GHostTime() = default;++ GHostTime(const std::chrono::microseconds tm)+ : time(tm)+ {+ }++ // Model the NetworkByteStreamSerializable concept+ friend std::uint32_t sizeInByteStream(const GHostTime& dgt)+ {+ return discovery::sizeInByteStream(std::move(dgt.time));+ }++ template <typename It>+ friend It toNetworkByteStream(const GHostTime& dgt, It out)+ {+ return discovery::toNetworkByteStream(std::move(dgt.time), std::move(out));+ }++ template <typename It>+ static std::pair<GHostTime, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ auto result = discovery::Deserialize<chrono::microseconds>::fromNetworkByteStream(+ std::move(begin), std::move(end));+ return make_pair(GHostTime{std::move(result.first)}, std::move(result.second));+ }++ std::chrono::microseconds time;+};++struct PrevGHostTime+{+ static const std::int32_t key = '_pgt';+ static_assert(key == 0x5f706774, "Unexpected byte order");++ PrevGHostTime() = default;++ PrevGHostTime(const std::chrono::microseconds tm)+ : time(tm)+ {+ }++ // Model the NetworkByteStreamSerializable concept+ friend std::uint32_t sizeInByteStream(const PrevGHostTime& dgt)+ {+ return discovery::sizeInByteStream(std::move(dgt.time));+ }++ template <typename It>+ friend It toNetworkByteStream(const PrevGHostTime& pdgt, It out)+ {+ return discovery::toNetworkByteStream(std::move(pdgt.time), std::move(out));+ }++ template <typename It>+ static std::pair<PrevGHostTime, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ auto result = discovery::Deserialize<chrono::microseconds>::fromNetworkByteStream(+ std::move(begin), std::move(end));+ return make_pair(PrevGHostTime{std::move(result.first)}, std::move(result.second));+ }++ std::chrono::microseconds time;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/PeerState.hpp view
@@ -0,0 +1,90 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/Payload.hpp>+#include <ableton/link/MeasurementEndpointV4.hpp>+#include <ableton/link/NodeState.hpp>++namespace ableton+{+namespace link+{++// A state type for peers. PeerState stores the normal NodeState plus+// additional information (the remote endpoint at which to find its+// ping/pong measurement server).++struct PeerState+{+ using IdType = NodeId;++ IdType ident() const+ {+ return nodeState.ident();+ }++ SessionId sessionId() const+ {+ return nodeState.sessionId;+ }++ Timeline timeline() const+ {+ return nodeState.timeline;+ }++ StartStopState startStopState() const+ {+ return nodeState.startStopState;+ }++ friend bool operator==(const PeerState& lhs, const PeerState& rhs)+ {+ return lhs.nodeState == rhs.nodeState && lhs.endpoint == rhs.endpoint;+ }++ friend auto toPayload(const PeerState& state)+ -> decltype(std::declval<NodeState::Payload>()+ + discovery::makePayload(MeasurementEndpointV4{{}}))+ {+ return toPayload(state.nodeState)+ + discovery::makePayload(MeasurementEndpointV4{state.endpoint});+ }++ template <typename It>+ static PeerState fromPayload(NodeId id, It begin, It end)+ {+ using namespace std;+ auto peerState = PeerState{NodeState::fromPayload(std::move(id), begin, end), {}};++ discovery::parsePayload<MeasurementEndpointV4>(+ std::move(begin), std::move(end), [&peerState](MeasurementEndpointV4 me4) {+ peerState.endpoint = std::move(me4.ep);+ });+ return peerState;+ }++ NodeState nodeState;+ asio::ip::udp::endpoint endpoint;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/Peers.hpp view
@@ -0,0 +1,368 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/PeerState.hpp>+#include <ableton/util/Injected.hpp>+#include <cassert>++namespace ableton+{+namespace link+{++// SessionMembershipCallback is invoked when any change to session+// membership occurs (when any peer joins or leaves a session)+//+// SessionTimelineCallback is invoked with a session id and a timeline+// whenever a new combination of these values is seen+//+// SessionStartStopStateCallback is invoked with a session id and a startStopState+// whenever a new combination of these values is seen++template <typename IoContext,+ typename SessionMembershipCallback,+ typename SessionTimelineCallback,+ typename SessionStartStopStateCallback>+class Peers+{+ // non-movable private implementation type+ struct Impl;++public:+ using Peer = std::pair<PeerState, asio::ip::address>;++ Peers(util::Injected<IoContext> io,+ SessionMembershipCallback membership,+ SessionTimelineCallback timeline,+ SessionStartStopStateCallback startStop)+ : mpImpl(std::make_shared<Impl>(+ std::move(io), std::move(membership), std::move(timeline), std::move(startStop)))+ {+ }++ // The set of peers for a given session, ordered by (peerId, addr).+ // The result will possibly contain multiple entries for the same+ // peer if it is visible through multiple gateways.+ std::vector<Peer> sessionPeers(const SessionId& sid) const+ {+ using namespace std;+ vector<Peer> result;+ auto& peerVec = mpImpl->mPeers;+ copy_if(begin(peerVec), end(peerVec), back_inserter(result), SessionMemberPred{sid});+ return result;+ }++ // Number of individual for a given session.+ std::size_t uniqueSessionPeerCount(const SessionId& sid) const+ {+ using namespace std;+ auto peerVec = sessionPeers(sid);+ auto last = unique(begin(peerVec), end(peerVec),+ [](const Peer& a, const Peer& b) { return a.first.ident() == b.first.ident(); });+ return static_cast<size_t>(distance(begin(peerVec), last));+ }++ void setSessionTimeline(const SessionId& sid, const Timeline& tl)+ {+ // Set the cached timeline for all peers to a new client-specified+ // timeline. When we make a timeline change, we do so+ // optimistically and clients assume that all peers in a session+ // have adopted the newly specified timeline. We must represent+ // this in our cache or else we risk failing to notify about a+ // higher-priority peer timeline that was already seen.+ for (auto& peer : mpImpl->mPeers)+ {+ if (peer.first.sessionId() == sid)+ {+ peer.first.nodeState.timeline = tl;+ }+ }+ }++ // Purge all cached peers that are members of the given session+ void forgetSession(const SessionId& sid)+ {+ using namespace std;+ auto& peerVec = mpImpl->mPeers;+ peerVec.erase(+ remove_if(begin(peerVec), end(peerVec), SessionMemberPred{sid}), end(peerVec));+ }++ void resetPeers()+ {+ mpImpl->mPeers.clear();+ }++ // Observer type that monitors peer discovery on a particular+ // gateway and relays the information to a Peers instance.+ // Models the PeerObserver concept from the discovery module.+ struct GatewayObserver+ {+ using GatewayObserverNodeState = PeerState;+ using GatewayObserverNodeId = NodeId;++ GatewayObserver(std::shared_ptr<Impl> pImpl, asio::ip::address addr)+ : mpImpl(std::move(pImpl))+ , mAddr(std::move(addr))+ {+ }+ GatewayObserver(const GatewayObserver&) = delete;++ GatewayObserver(GatewayObserver&& rhs)+ : mpImpl(std::move(rhs.mpImpl))+ , mAddr(std::move(rhs.mAddr))+ {+ }++ ~GatewayObserver()+ {+ // Check to handle the moved from case+ if (mpImpl)+ {+ mpImpl->gatewayClosed(mAddr);+ }+ }++ // model the PeerObserver concept from discovery+ friend void sawPeer(GatewayObserver& observer, const PeerState& state)+ {+ auto pImpl = observer.mpImpl;+ auto addr = observer.mAddr;+ assert(pImpl);+ pImpl->sawPeerOnGateway(std::move(state), std::move(addr));+ }++ friend void peerLeft(GatewayObserver& observer, const NodeId& id)+ {+ auto pImpl = observer.mpImpl;+ auto addr = observer.mAddr;+ pImpl->peerLeftGateway(std::move(id), std::move(addr));+ }++ friend void peerTimedOut(GatewayObserver& observer, const NodeId& id)+ {+ auto pImpl = observer.mpImpl;+ auto addr = observer.mAddr;+ pImpl->peerLeftGateway(std::move(id), std::move(addr));+ }++ std::shared_ptr<Impl> mpImpl;+ asio::ip::address mAddr;+ };++ // Factory function for the gateway observer+ friend GatewayObserver makeGatewayObserver(Peers& peers, asio::ip::address addr)+ {+ return GatewayObserver{peers.mpImpl, std::move(addr)};+ }++private:+ struct Impl+ {+ Impl(util::Injected<IoContext> io,+ SessionMembershipCallback membership,+ SessionTimelineCallback timeline,+ SessionStartStopStateCallback startStop)+ : mIo(std::move(io))+ , mSessionMembershipCallback(std::move(membership))+ , mSessionTimelineCallback(std::move(timeline))+ , mSessionStartStopStateCallback(std::move(startStop))+ {+ }++ void sawPeerOnGateway(PeerState peerState, asio::ip::address gatewayAddr)+ {+ using namespace std;++ const auto peerSession = peerState.sessionId();+ const auto peerTimeline = peerState.timeline();+ const auto peerStartStopState = peerState.startStopState();++ bool isNewSessionTimeline = !sessionTimelineExists(peerSession, peerTimeline);+ bool isNewSessionStartStopState =+ !sessionStartStopStateExists(peerSession, peerStartStopState);++ auto peer = make_pair(std::move(peerState), std::move(gatewayAddr));+ const auto idRange = equal_range(begin(mPeers), end(mPeers), peer, PeerIdComp{});++ bool didSessionMembershipChange = false;+ if (idRange.first == idRange.second)+ {+ // This peer is not currently known on any gateway+ didSessionMembershipChange = true;+ mPeers.insert(std::move(idRange.first), std::move(peer));+ }+ else+ {+ // We've seen this peer before... does it have a new session?+ didSessionMembershipChange =+ all_of(idRange.first, idRange.second, [&peerSession](const Peer& test) {+ return test.first.sessionId() != peerSession;+ });++ // was it on this gateway?+ const auto addrRange =+ equal_range(idRange.first, idRange.second, peer, AddrComp{});++ if (addrRange.first == addrRange.second)+ {+ // First time on this gateway, add it+ mPeers.insert(std::move(addrRange.first), std::move(peer));+ }+ else+ {+ // We have an entry for this peer on this gateway, update it+ *addrRange.first = std::move(peer);+ }+ }++ // Invoke callbacks outside the critical section+ if (isNewSessionTimeline)+ {+ mSessionTimelineCallback(peerSession, peerTimeline);+ }++ // Pass the start stop state to the Controller after it processed the timeline.+ // A new timeline can cause a session Id change which will prevent processing the+ // new start stop state. By handling the start stop state after the timeline we+ // assure that the start stop state is processed with the correct session Id.+ if (isNewSessionStartStopState)+ {+ mSessionStartStopStateCallback(peerSession, peerStartStopState);+ }++ if (didSessionMembershipChange)+ {+ mSessionMembershipCallback();+ }+ }++ void peerLeftGateway(const NodeId& nodeId, const asio::ip::address& gatewayAddr)+ {+ using namespace std;++ auto it = find_if(begin(mPeers), end(mPeers), [&](const Peer& peer) {+ return peer.first.ident() == nodeId && peer.second == gatewayAddr;+ });++ bool didSessionMembershipChange = false;+ if (it != end(mPeers))+ {+ mPeers.erase(std::move(it));+ didSessionMembershipChange = true;+ }++ if (didSessionMembershipChange)+ {+ mSessionMembershipCallback();+ }+ }++ void gatewayClosed(const asio::ip::address& gatewayAddr)+ {+ using namespace std;++ mPeers.erase(+ remove_if(begin(mPeers), end(mPeers),+ [&gatewayAddr](const Peer& peer) { return peer.second == gatewayAddr; }),+ end(mPeers));++ mSessionMembershipCallback();+ }++ template <typename Predicate>+ bool hasPeerWith(const SessionId& sessionId, Predicate predicate)+ {+ using namespace std;+ return find_if(begin(mPeers), end(mPeers), [&](const Peer& peer) {+ return peer.first.sessionId() == sessionId && predicate(peer.first);+ }) != end(mPeers);+ }++ bool sessionTimelineExists(const SessionId& session, const Timeline& timeline)+ {+ return hasPeerWith(session,+ [&](const PeerState& peerState) { return peerState.timeline() == timeline; });+ }++ bool sessionStartStopStateExists(+ const SessionId& sessionId, const StartStopState& startStopState)+ {+ return hasPeerWith(sessionId, [&](const PeerState& peerState) {+ return peerState.startStopState() == startStopState;+ });+ }++ struct PeerIdComp+ {+ bool operator()(const Peer& lhs, const Peer& rhs) const+ {+ return lhs.first.ident() < rhs.first.ident();+ }+ };++ struct AddrComp+ {+ bool operator()(const Peer& lhs, const Peer& rhs) const+ {+ return lhs.second < rhs.second;+ }+ };++ util::Injected<IoContext> mIo;+ SessionMembershipCallback mSessionMembershipCallback;+ SessionTimelineCallback mSessionTimelineCallback;+ SessionStartStopStateCallback mSessionStartStopStateCallback;+ std::vector<Peer> mPeers; // sorted by peerId, unique by (peerId, addr)+ };++ struct SessionMemberPred+ {+ bool operator()(const Peer& peer) const+ {+ return peer.first.sessionId() == sid;+ }++ const SessionId& sid;+ };++ std::shared_ptr<Impl> mpImpl;+};++template <typename Io,+ typename SessionMembershipCallback,+ typename SessionTimelineCallback,+ typename SessionStartStopStateCallback>+Peers<Io,+ SessionMembershipCallback,+ SessionTimelineCallback,+ SessionStartStopStateCallback>+makePeers(util::Injected<Io> io,+ SessionMembershipCallback membershipCallback,+ SessionTimelineCallback timelineCallback,+ SessionStartStopStateCallback startStopStateCallback)+{+ return {std::move(io), std::move(membershipCallback), std::move(timelineCallback),+ std::move(startStopStateCallback)};+}++} // namespace link+} // namespace ableton
+ link/include/ableton/link/Phase.hpp view
@@ -0,0 +1,100 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/Beats.hpp>+#include <ableton/link/Timeline.hpp>+#include <chrono>++namespace ableton+{+namespace link+{++// Returns a value in the range [0,quantum) corresponding to beats %+// quantum except that negative beat values are handled correctly.+// If the given quantum is zero, returns zero.+inline Beats phase(const Beats beats, const Beats quantum)+{+ if (quantum == Beats{INT64_C(0)})+ {+ return Beats{INT64_C(0)};+ }+ else+ {+ // Handle negative beat values by doing the computation relative to an+ // origin that is on the nearest quantum boundary less than -(abs(x))+ const auto quantumMicros = quantum.microBeats();+ const auto quantumBins = (llabs(beats.microBeats()) + quantumMicros) / quantumMicros;+ const std::int64_t quantumBeats{quantumBins * quantumMicros};+ return (beats + Beats{quantumBeats}) % quantum;+ }+}++// Return the least value greater than x that matches the phase of+// target with respect to the given quantum. If the given quantum+// quantum is 0, x is returned.+inline Beats nextPhaseMatch(const Beats x, const Beats target, const Beats quantum)+{+ const auto desiredPhase = phase(target, quantum);+ const auto xPhase = phase(x, quantum);+ const auto phaseDiff = (desiredPhase - xPhase + quantum) % quantum;+ return x + phaseDiff;+}++// Return the closest value to x that matches the phase of the target+// with respect to the given quantum. The result deviates from x by at+// most quantum/2, but may be less than x.+inline Beats closestPhaseMatch(const Beats x, const Beats target, const Beats quantum)+{+ return nextPhaseMatch(x - Beats{0.5 * quantum.floating()}, target, quantum);+}++// Interprets the given timeline as encoding a quantum boundary at its+// origin. Given such a timeline, returns a phase-encoded beat value+// relative to the given quantum that corresponds to the given+// time. The phase of the resulting beat value can be calculated with+// phase(beats, quantum). The result will deviate by up to +-+// (quantum/2) beats compared to the result of tl.toBeats(time).+inline Beats toPhaseEncodedBeats(+ const Timeline& tl, const std::chrono::microseconds time, const Beats quantum)+{+ const auto beat = tl.toBeats(time);+ return closestPhaseMatch(beat, beat - tl.beatOrigin, quantum);+}++// The inverse of toPhaseEncodedBeats. Given a phase encoded beat+// value from the given timeline and quantum, find the time value that+// it maps to.+inline std::chrono::microseconds fromPhaseEncodedBeats(+ const Timeline& tl, const Beats beat, const Beats quantum)+{+ const auto fromOrigin = beat - tl.beatOrigin;+ const auto originOffset = fromOrigin - phase(fromOrigin, quantum);+ // invert the phase calculation so that it always rounds up in the+ // middle instead of down like closestPhaseMatch. Otherwise we'll+ // end up rounding down twice when a value is at phase quantum/2.+ const auto inversePhaseOffset = closestPhaseMatch(+ quantum - phase(fromOrigin, quantum), quantum - phase(beat, quantum), quantum);+ return tl.fromBeats(tl.beatOrigin + originOffset + quantum - inversePhaseOffset);+}++} // namespace link+} // namespace ableton
+ link/include/ableton/link/PingResponder.hpp view
@@ -0,0 +1,171 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/GhostXForm.hpp>+#include <ableton/link/PayloadEntries.hpp>+#include <ableton/link/SessionId.hpp>+#include <ableton/link/v1/Messages.hpp>+#include <ableton/util/Injected.hpp>+#include <ableton/util/SafeAsyncHandler.hpp>+#include <chrono>+#include <memory>++namespace ableton+{+namespace link+{++template <typename Clock, typename IoContext>+class PingResponder+{+ using IoType = util::Injected<IoContext&>;+ using Socket = typename IoType::type::template Socket<v1::kMaxMessageSize>;++public:+ PingResponder(asio::ip::address_v4 address,+ SessionId sessionId,+ GhostXForm ghostXForm,+ Clock clock,+ IoType io)+ : mIo(io)+ , mpImpl(std::make_shared<Impl>(std::move(address),+ std::move(sessionId),+ std::move(ghostXForm),+ std::move(clock),+ std::move(io)))+ {+ mpImpl->listen();+ }++ PingResponder(const PingResponder&) = delete;+ PingResponder(PingResponder&&) = delete;++ void updateNodeState(const SessionId& sessionId, const GhostXForm& xform)+ {+ mpImpl->mSessionId = std::move(sessionId);+ mpImpl->mGhostXForm = std::move(xform);+ }++ asio::ip::udp::endpoint endpoint() const+ {+ return mpImpl->mSocket.endpoint();+ }++ asio::ip::address address() const+ {+ return endpoint().address();+ }++ Socket socket() const+ {+ return mpImpl->mSocket;+ }++private:+ struct Impl : std::enable_shared_from_this<Impl>+ {+ Impl(asio::ip::address_v4 address,+ SessionId sessionId,+ GhostXForm ghostXForm,+ Clock clock,+ IoType io)+ : mSessionId(std::move(sessionId))+ , mGhostXForm(std::move(ghostXForm))+ , mClock(std::move(clock))+ , mLog(channel(io->log(), "gateway@" + address.to_string()))+ , mSocket(io->template openUnicastSocket<v1::kMaxMessageSize>(address))+ {+ }++ void listen()+ {+ mSocket.receive(util::makeAsyncSafe(this->shared_from_this()));+ }++ // Operator to handle incoming messages on the interface+ template <typename It>+ void operator()(const asio::ip::udp::endpoint& from, const It begin, const It end)+ {+ using namespace discovery;++ // Decode Ping Message+ const auto result = link::v1::parseMessageHeader(begin, end);+ const auto& header = result.first;+ const auto payloadBegin = result.second;++ // Check Payload size+ const auto payloadSize = static_cast<std::size_t>(std::distance(payloadBegin, end));+ const auto maxPayloadSize =+ sizeInByteStream(makePayload(HostTime{}, PrevGHostTime{}));+ if (header.messageType == v1::kPing && payloadSize <= maxPayloadSize)+ {+ debug(mLog) << " Received ping message from " << from;++ try+ {+ reply(std::move(payloadBegin), std::move(end), from);+ }+ catch (const std::runtime_error& err)+ {+ info(mLog) << " Failed to send pong to " << from << ". Reason: " << err.what();+ }+ }+ else+ {+ info(mLog) << " Received invalid Message from " << from << ".";+ }+ listen();+ }++ template <typename It>+ void reply(It begin, It end, const asio::ip::udp::endpoint& to)+ {+ using namespace discovery;++ // Encode Pong Message+ const auto id = SessionMembership{mSessionId};+ const auto currentGt = GHostTime{mGhostXForm.hostToGhost(mClock.micros())};+ const auto pongPayload = makePayload(id, currentGt);++ v1::MessageBuffer pongBuffer;+ const auto pongMsgBegin = std::begin(pongBuffer);+ auto pongMsgEnd = v1::pongMessage(pongPayload, pongMsgBegin);+ // Append ping payload to pong message.+ pongMsgEnd = std::copy(begin, end, pongMsgEnd);++ const auto numBytes =+ static_cast<std::size_t>(std::distance(pongMsgBegin, pongMsgEnd));+ mSocket.send(pongBuffer.data(), numBytes, to);+ }++ SessionId mSessionId;+ GhostXForm mGhostXForm;+ Clock mClock;+ typename IoType::type::Log mLog;+ Socket mSocket;+ };++ IoType mIo;+ std::shared_ptr<Impl> mpImpl;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/SessionId.hpp view
@@ -0,0 +1,63 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/NodeId.hpp>++namespace ableton+{+namespace link+{++// SessionIds occupy the same value space as NodeIds and are+// identified by their founding node.+using SessionId = NodeId;++// A payload entry indicating membership in a particular session+struct SessionMembership+{+ static const std::int32_t key = 'sess';+ static_assert(key == 0x73657373, "Unexpected byte order");++ // Model the NetworkByteStreamSerializable concept+ friend std::uint32_t sizeInByteStream(const SessionMembership& sm)+ {+ return discovery::sizeInByteStream(sm.sessionId);+ }++ template <typename It>+ friend It toNetworkByteStream(const SessionMembership& sm, It out)+ {+ return discovery::toNetworkByteStream(sm.sessionId, std::move(out));+ }++ template <typename It>+ static std::pair<SessionMembership, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ auto idRes = SessionId::fromNetworkByteStream(std::move(begin), std::move(end));+ return make_pair(SessionMembership{std::move(idRes.first)}, std::move(idRes.second));+ }++ SessionId sessionId;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/SessionState.hpp view
@@ -0,0 +1,115 @@+/* Copyright 2017, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/Optional.hpp>+#include <ableton/link/StartStopState.hpp>+#include <ableton/link/Timeline.hpp>+#include <ableton/link/TripleBuffer.hpp>++namespace ableton+{+namespace link+{++using OptionalTimeline = Optional<Timeline>;+using OptionalStartStopState = Optional<StartStopState>;+using OptionalClientStartStopState = Optional<ClientStartStopState>;++struct SessionState+{+ Timeline timeline;+ StartStopState startStopState;+ GhostXForm ghostXForm;+};++struct ClientState+{+ friend bool operator==(const ClientState& lhs, const ClientState& rhs)+ {+ return std::tie(lhs.timeline, lhs.startStopState)+ == std::tie(rhs.timeline, rhs.startStopState);+ }++ friend bool operator!=(const ClientState& lhs, const ClientState& rhs)+ {+ return !(lhs == rhs);+ }++ Timeline timeline;+ ClientStartStopState startStopState;+};++struct ControllerClientState+{+ ControllerClientState(ClientState state)+ : mState(state)+ , mRtState(state)+ {+ }++ template <typename Fn>+ void update(Fn fn)+ {+ std::unique_lock<std::mutex> lock(mMutex);+ fn(mState);+ mRtState.write(mState);+ }++ ClientState get() const+ {+ std::unique_lock<std::mutex> lock(mMutex);+ return mState;+ }++ ClientState getRt() const+ {+ return mRtState.read();+ }++private:+ mutable std::mutex mMutex;+ ClientState mState;+ mutable TripleBuffer<ClientState> mRtState;+};++struct RtClientState+{+ Timeline timeline;+ ClientStartStopState startStopState;+ std::chrono::microseconds timelineTimestamp;+ std::chrono::microseconds startStopStateTimestamp;+};++struct IncomingClientState+{+ OptionalTimeline timeline;+ OptionalClientStartStopState startStopState;+ std::chrono::microseconds timelineTimestamp;+};++struct ApiState+{+ Timeline timeline;+ ApiStartStopState startStopState;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/Sessions.hpp view
@@ -0,0 +1,301 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/GhostXForm.hpp>+#include <ableton/link/SessionId.hpp>+#include <ableton/link/Timeline.hpp>++namespace ableton+{+namespace link+{++struct SessionMeasurement+{+ GhostXForm xform;+ std::chrono::microseconds timestamp;+};++struct Session+{+ SessionId sessionId;+ Timeline timeline;+ SessionMeasurement measurement;+};++template <typename Peers,+ typename MeasurePeer,+ typename JoinSessionCallback,+ typename IoContext,+ typename Clock>+class Sessions+{+public:+ using Timer = typename util::Injected<IoContext>::type::Timer;++ Sessions(Session init,+ util::Injected<Peers> peers,+ MeasurePeer measure,+ JoinSessionCallback join,+ util::Injected<IoContext> io,+ Clock clock)+ : mPeers(std::move(peers))+ , mMeasure(std::move(measure))+ , mCallback(std::move(join))+ , mCurrent(std::move(init))+ , mIo(std::move(io))+ , mTimer(mIo->makeTimer())+ , mClock(std::move(clock))+ {+ }++ void resetSession(Session session)+ {+ mCurrent = std::move(session);+ mOtherSessions.clear();+ }++ void resetTimeline(Timeline timeline)+ {+ mCurrent.timeline = std::move(timeline);+ }++ // Consider the observed session/timeline pair and return a possibly+ // new timeline that should be used going forward.+ Timeline sawSessionTimeline(SessionId sid, Timeline timeline)+ {+ using namespace std;+ if (sid == mCurrent.sessionId)+ {+ // matches our current session, update the timeline if necessary+ updateTimeline(mCurrent, std::move(timeline));+ }+ else+ {+ auto session = Session{std::move(sid), std::move(timeline), {}};+ const auto range =+ equal_range(begin(mOtherSessions), end(mOtherSessions), session, SessionIdComp{});+ if (range.first == range.second)+ {+ // brand new session, insert it into our list of known+ // sessions and launch a measurement+ launchSessionMeasurement(session);+ mOtherSessions.insert(range.first, std::move(session));+ }+ else+ {+ // we've seen this session before, update its timeline if necessary+ updateTimeline(*range.first, std::move(timeline));+ }+ }+ return mCurrent.timeline;+ }++private:+ void launchSessionMeasurement(Session& session)+ {+ using namespace std;+ auto peers = mPeers->sessionPeers(session.sessionId);+ if (!peers.empty())+ {+ // first criteria: always prefer the founding peer+ const auto it = find_if(begin(peers), end(peers),+ [&session](const Peer& peer) { return session.sessionId == peer.first.ident(); });+ // TODO: second criteria should be degree. We don't have that+ // represented yet so just use the first peer for now+ auto peer = it == end(peers) ? peers.front() : *it;+ // mark that a session is in progress by clearing out the+ // session's timestamp+ session.measurement.timestamp = {};+ mMeasure(std::move(peer), MeasurementResultsHandler{*this, session.sessionId});+ }+ }++ void handleSuccessfulMeasurement(const SessionId& id, GhostXForm xform)+ {+ using namespace std;++ debug(mIo->log()) << "Session " << id << " measurement completed with result "+ << "(" << xform.slope << ", " << xform.intercept.count() << ")";++ auto measurement = SessionMeasurement{std::move(xform), mClock.micros()};++ if (mCurrent.sessionId == id)+ {+ mCurrent.measurement = std::move(measurement);+ mCallback(mCurrent);+ }+ else+ {+ const auto range = equal_range(+ begin(mOtherSessions), end(mOtherSessions), Session{id, {}, {}}, SessionIdComp{});++ if (range.first != range.second)+ {+ const auto SESSION_EPS = chrono::microseconds{500000};+ // should we join this session?+ const auto hostTime = mClock.micros();+ const auto curGhost = mCurrent.measurement.xform.hostToGhost(hostTime);+ const auto newGhost = measurement.xform.hostToGhost(hostTime);+ // update the measurement for the session entry+ range.first->measurement = std::move(measurement);+ // If session times too close - fall back to session id order+ const auto ghostDiff = newGhost - curGhost;+ if (ghostDiff > SESSION_EPS+ || (std::abs(ghostDiff.count()) < SESSION_EPS.count()+ && id < mCurrent.sessionId))+ {+ // The new session wins, switch over to it+ auto current = mCurrent;+ mCurrent = std::move(*range.first);+ mOtherSessions.erase(range.first);+ // Put the old current session back into our list of known+ // sessions so that we won't re-measure it+ const auto it = upper_bound(+ begin(mOtherSessions), end(mOtherSessions), current, SessionIdComp{});+ mOtherSessions.insert(it, std::move(current));+ // And notify that we have a new session and make sure that+ // we remeasure it periodically.+ mCallback(mCurrent);+ scheduleRemeasurement();+ }+ }+ }+ }++ void scheduleRemeasurement()+ {+ // set a timer to re-measure the active session after a period+ mTimer.expires_from_now(std::chrono::microseconds{30000000});+ mTimer.async_wait([this](const typename Timer::ErrorCode e) {+ if (!e)+ {+ launchSessionMeasurement(mCurrent);+ scheduleRemeasurement();+ }+ });+ }++ void handleFailedMeasurement(const SessionId& id)+ {+ using namespace std;++ debug(mIo->log()) << "Session " << id << " measurement failed.";++ // if we failed to measure for our current session, schedule a+ // retry in the future. Otherwise, remove the session from our set+ // of known sessions (if it is seen again it will be measured as+ // if new).+ if (mCurrent.sessionId == id)+ {+ scheduleRemeasurement();+ }+ else+ {+ const auto range = equal_range(+ begin(mOtherSessions), end(mOtherSessions), Session{id, {}, {}}, SessionIdComp{});+ if (range.first != range.second)+ {+ mOtherSessions.erase(range.first);+ mPeers->forgetSession(id);+ }+ }+ }++ void updateTimeline(Session& session, Timeline timeline)+ {+ // We use beat origin magnitude to prioritize sessions.+ if (timeline.beatOrigin > session.timeline.beatOrigin)+ {+ debug(mIo->log()) << "Adopting peer timeline (" << timeline.tempo.bpm() << ", "+ << timeline.beatOrigin.floating() << ", "+ << timeline.timeOrigin.count() << ")";++ session.timeline = std::move(timeline);+ }+ else+ {+ debug(mIo->log()) << "Rejecting peer timeline with beat origin: "+ << timeline.beatOrigin.floating()+ << ". Current timeline beat origin: "+ << session.timeline.beatOrigin.floating();+ }+ }++ struct MeasurementResultsHandler+ {+ void operator()(GhostXForm xform) const+ {+ Sessions& sessions = mSessions;+ const SessionId& sessionId = mSessionId;+ if (xform == GhostXForm{})+ {+ sessions.handleFailedMeasurement(std::move(sessionId));+ }+ else+ {+ sessions.handleSuccessfulMeasurement(std::move(sessionId), std::move(xform));+ }+ }++ Sessions& mSessions;+ SessionId mSessionId;+ };++ struct SessionIdComp+ {+ bool operator()(const Session& lhs, const Session& rhs) const+ {+ return lhs.sessionId < rhs.sessionId;+ }+ };++ using Peer = typename util::Injected<Peers>::type::Peer;+ util::Injected<Peers> mPeers;+ MeasurePeer mMeasure;+ JoinSessionCallback mCallback;+ Session mCurrent;+ util::Injected<IoContext> mIo;+ Timer mTimer;+ Clock mClock;+ std::vector<Session> mOtherSessions; // sorted/unique by session id+};++template <typename Peers,+ typename MeasurePeer,+ typename JoinSessionCallback,+ typename IoContext,+ typename Clock>+Sessions<Peers, MeasurePeer, JoinSessionCallback, IoContext, Clock> makeSessions(+ Session init,+ util::Injected<Peers> peers,+ MeasurePeer measure,+ JoinSessionCallback join,+ util::Injected<IoContext> io,+ Clock clock)+{+ using namespace std;+ return {std::move(init), std::move(peers), std::move(measure), std::move(join),+ std::move(io), std::move(clock)};+}++} // namespace link+} // namespace ableton
+ link/include/ableton/link/StartStopState.hpp view
@@ -0,0 +1,152 @@+/* Copyright 2017, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/NetworkByteStreamSerializable.hpp>+#include <ableton/link/Beats.hpp>+#include <chrono>+#include <tuple>++namespace ableton+{+namespace link+{++// A tuple of (isPlaying, time) that represents the playing state+// with an according timestamp in microseconds. It also serves as a+// payload entry.++struct StartStopState+{+ static const std::int32_t key = 'stst';+ static_assert(key == 0x73747374, "Unexpected byte order");++ using StartStopStateTuple = std::tuple<bool, Beats, std::chrono::microseconds>;++ StartStopState() = default;++ StartStopState(+ const bool aIsPlaying, const Beats aBeats, const std::chrono::microseconds aTimestamp)+ : isPlaying(aIsPlaying)+ , beats(aBeats)+ , timestamp(aTimestamp)+ {+ }++ friend bool operator==(const StartStopState& lhs, const StartStopState& rhs)+ {+ return std::tie(lhs.isPlaying, lhs.beats, lhs.timestamp)+ == std::tie(rhs.isPlaying, rhs.beats, rhs.timestamp);+ }++ friend bool operator!=(const StartStopState& lhs, const StartStopState& rhs)+ {+ return !(lhs == rhs);+ }++ // Model the NetworkByteStreamSerializable concept+ friend std::uint32_t sizeInByteStream(const StartStopState& state)+ {+ return discovery::sizeInByteStream(state.asTuple());+ }++ template <typename It>+ friend It toNetworkByteStream(const StartStopState& state, It out)+ {+ return discovery::toNetworkByteStream(state.asTuple(), std::move(out));+ }++ template <typename It>+ static std::pair<StartStopState, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ using namespace discovery;+ auto result = Deserialize<StartStopStateTuple>::fromNetworkByteStream(+ std::move(begin), std::move(end));+ auto state =+ StartStopState{get<0>(result.first), get<1>(result.first), get<2>(result.first)};+ return make_pair(std::move(state), std::move(result.second));+ }++ bool isPlaying{false};+ Beats beats{0.};+ std::chrono::microseconds timestamp{0};++private:+ StartStopStateTuple asTuple() const+ {+ return std::make_tuple(isPlaying, beats, timestamp);+ }+};++struct ClientStartStopState+{+ ClientStartStopState() = default;++ ClientStartStopState(const bool aIsPlaying,+ const std::chrono::microseconds aTime,+ const std::chrono::microseconds aTimestamp)+ : isPlaying(aIsPlaying)+ , time(aTime)+ , timestamp(aTimestamp)+ {+ }++ friend bool operator==(const ClientStartStopState& lhs, const ClientStartStopState& rhs)+ {+ return std::tie(lhs.isPlaying, lhs.time, lhs.timestamp)+ == std::tie(rhs.isPlaying, rhs.time, rhs.timestamp);+ }++ friend bool operator!=(const ClientStartStopState& lhs, const ClientStartStopState& rhs)+ {+ return !(lhs == rhs);+ }++ bool isPlaying{false};+ std::chrono::microseconds time{0};+ std::chrono::microseconds timestamp{0};+};++struct ApiStartStopState+{+ ApiStartStopState() = default;++ ApiStartStopState(const bool aIsPlaying, const std::chrono::microseconds aTime)+ : isPlaying(aIsPlaying)+ , time(aTime)+ {+ }++ friend bool operator==(const ApiStartStopState& lhs, const ApiStartStopState& rhs)+ {+ return std::tie(lhs.isPlaying, lhs.time) == std::tie(rhs.isPlaying, rhs.time);+ }++ friend bool operator!=(const ApiStartStopState& lhs, const ApiStartStopState& rhs)+ {+ return !(lhs == rhs);+ }++ bool isPlaying{false};+ std::chrono::microseconds time{0};+};+} // namespace link+} // namespace ableton
+ link/include/ableton/link/Tempo.hpp view
@@ -0,0 +1,125 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/Beats.hpp>+#include <chrono>++namespace ableton+{+namespace link+{++struct Tempo+{+ Tempo() = default;++ // Beats per minute+ explicit Tempo(const double bpm)+ : mValue(bpm)+ {+ }++ Tempo(const std::chrono::microseconds microsPerBeat)+ : mValue(60. * 1e6 / static_cast<double>(microsPerBeat.count()))+ {+ }++ double bpm() const+ {+ return mValue;+ }++ std::chrono::microseconds microsPerBeat() const+ {+ return std::chrono::microseconds{std::llround(60. * 1e6 / bpm())};+ }++ // Given the tempo, convert a time to a beat value+ Beats microsToBeats(const std::chrono::microseconds micros) const+ {+ return Beats{+ static_cast<double>(micros.count()) / static_cast<double>(microsPerBeat().count())};+ }++ // Given the tempo, convert a beat to a time value+ std::chrono::microseconds beatsToMicros(const Beats beats) const+ {+ return std::chrono::microseconds{+ std::llround(beats.floating() * static_cast<double>(microsPerBeat().count()))};+ }++ // Model the NetworkByteStreamSerializable concept+ friend std::uint32_t sizeInByteStream(const Tempo tempo)+ {+ return discovery::sizeInByteStream(tempo.microsPerBeat());+ }++ template <typename It>+ friend It toNetworkByteStream(const Tempo tempo, It out)+ {+ return discovery::toNetworkByteStream(tempo.microsPerBeat(), std::move(out));+ }++ template <typename It>+ static std::pair<Tempo, It> fromNetworkByteStream(It begin, It end)+ {+ auto result =+ discovery::Deserialize<std::chrono::microseconds>::fromNetworkByteStream(+ std::move(begin), std::move(end));+ return std::make_pair(Tempo{std::move(result.first)}, std::move(result.second));+ }++ friend bool operator==(const Tempo lhs, const Tempo rhs)+ {+ return lhs.mValue == rhs.mValue;+ }++ friend bool operator!=(const Tempo lhs, const Tempo rhs)+ {+ return lhs.mValue != rhs.mValue;+ }++ friend bool operator<(const Tempo lhs, const Tempo rhs)+ {+ return lhs.mValue < rhs.mValue;+ }++ friend bool operator>(const Tempo lhs, const Tempo rhs)+ {+ return lhs.mValue > rhs.mValue;+ }++ friend bool operator<=(const Tempo lhs, const Tempo rhs)+ {+ return lhs.mValue <= rhs.mValue;+ }++ friend bool operator>=(const Tempo lhs, const Tempo rhs)+ {+ return lhs.mValue >= rhs.mValue;+ }++private:+ double mValue = 0;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/Timeline.hpp view
@@ -0,0 +1,98 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/NetworkByteStreamSerializable.hpp>+#include <ableton/link/Beats.hpp>+#include <ableton/link/Tempo.hpp>+#include <cmath>+#include <cstdint>+#include <tuple>++namespace ableton+{+namespace link+{++// A tuple of (tempo, beats, time), with integral units+// based on microseconds. This type establishes a bijection between+// beats and wall time, given a valid tempo. It also serves as a+// payload entry.++struct Timeline+{+ static const std::int32_t key = 'tmln';+ static_assert(key == 0x746d6c6e, "Unexpected byte order");++ Beats toBeats(const std::chrono::microseconds time) const+ {+ return beatOrigin + tempo.microsToBeats(time - timeOrigin);+ }++ std::chrono::microseconds fromBeats(const Beats beats) const+ {+ return timeOrigin + tempo.beatsToMicros(beats - beatOrigin);+ }++ friend bool operator==(const Timeline& lhs, const Timeline& rhs)+ {+ return std::tie(lhs.tempo, lhs.beatOrigin, lhs.timeOrigin)+ == std::tie(rhs.tempo, rhs.beatOrigin, rhs.timeOrigin);+ }++ friend bool operator!=(const Timeline& lhs, const Timeline& rhs)+ {+ return !(lhs == rhs);+ }++ // Model the NetworkByteStreamSerializable concept+ friend std::uint32_t sizeInByteStream(const Timeline& tl)+ {+ return discovery::sizeInByteStream(std::tie(tl.tempo, tl.beatOrigin, tl.timeOrigin));+ }++ template <typename It>+ friend It toNetworkByteStream(const Timeline& tl, It out)+ {+ return discovery::toNetworkByteStream(+ std::tie(tl.tempo, tl.beatOrigin, tl.timeOrigin), std::move(out));+ }++ template <typename It>+ static std::pair<Timeline, It> fromNetworkByteStream(It begin, It end)+ {+ using namespace std;+ using namespace discovery;+ Timeline timeline;+ auto result =+ Deserialize<tuple<Tempo, Beats, chrono::microseconds>>::fromNetworkByteStream(+ std::move(begin), std::move(end));+ tie(timeline.tempo, timeline.beatOrigin, timeline.timeOrigin) =+ std::move(result.first);+ return make_pair(std::move(timeline), std::move(result.second));+ }++ Tempo tempo;+ Beats beatOrigin;+ std::chrono::microseconds timeOrigin;+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/TripleBuffer.hpp view
@@ -0,0 +1,121 @@+/* Copyright 2022, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */+++#pragma once++#include <ableton/link/Optional.hpp>++#include <array>+#include <atomic>+#include <cassert>+#include <cstdint>++namespace ableton+{+namespace link+{++template <typename T>+struct TripleBuffer+{+public:+ TripleBuffer()+ : mBuffers{{{}, {}, {}}}+ {+ assert(mState.is_lock_free());+ }++ explicit TripleBuffer(const T& initial)+ : mBuffers{{initial, initial, initial}}+ {+ assert(mState.is_lock_free());+ }++ TripleBuffer(const TripleBuffer&) = delete;+ TripleBuffer& operator=(const TripleBuffer&) = delete;++ T read() noexcept+ {+ loadReadBuffer();+ return mBuffers[mReadIndex];+ }++ Optional<T> readNew()+ {+ if (loadReadBuffer())+ {+ return Optional<T>(mBuffers[mReadIndex]);+ }+ return {};+ }++ template <typename U>+ void write(U&& value)+ {+ mBuffers[mWriteIndex] = std::forward<U>(value);++ const auto prevState =+ mState.exchange(makeState(mWriteIndex, true), std::memory_order_acq_rel);++ mWriteIndex = backIndex(prevState);+ }++private:+ bool loadReadBuffer()+ {+ auto state = mState.load(std::memory_order_acquire);+ auto isNew = isNewWrite(state);+ if (isNew)+ {+ const auto prevState =+ mState.exchange(makeState(mReadIndex, false), std::memory_order_acq_rel);++ mReadIndex = backIndex(prevState);+ }+ return isNew;+ }++ using BackingState = uint32_t;++ static constexpr bool isNewWrite(const BackingState state)+ {+ return (state & 0x0000FFFFu) != 0;+ }++ static constexpr uint32_t backIndex(const BackingState state)+ {+ return state >> 16;+ }++ static constexpr BackingState makeState(+ const uint32_t backBufferIndex, const bool isWrite)+ {+ return (backBufferIndex << 16) | uint32_t(isWrite);+ }++ std::atomic<BackingState> mState{makeState(1u, false)}; // Reader and writer+ uint32_t mReadIndex = 0u; // Reader only+ uint32_t mWriteIndex = 2u; // Writer only++ std::array<T, 3> mBuffers{};+};++} // namespace link+} // namespace ableton
+ link/include/ableton/link/v1/Messages.hpp view
@@ -0,0 +1,138 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/Payload.hpp>+#include <array>++namespace ableton+{+namespace link+{+namespace v1+{++// The maximum size of a message, in bytes+const std::size_t kMaxMessageSize = 512;+// Utility typedef for an array of bytes of maximum message size+using MessageBuffer = std::array<uint8_t, v1::kMaxMessageSize>;++using MessageType = uint8_t;++const MessageType kPing = 1;+const MessageType kPong = 2;++struct MessageHeader+{+ MessageType messageType;++ friend std::uint32_t sizeInByteStream(const MessageHeader& header)+ {+ return discovery::sizeInByteStream(header.messageType);+ }++ template <typename It>+ friend It toNetworkByteStream(const MessageHeader& header, It out)+ {+ return discovery::toNetworkByteStream(header.messageType, std::move(out));+ }++ template <typename It>+ static std::pair<MessageHeader, It> fromNetworkByteStream(It begin, const It end)+ {+ using namespace discovery;++ MessageHeader header;+ std::tie(header.messageType, begin) =+ Deserialize<decltype(header.messageType)>::fromNetworkByteStream(begin, end);++ return std::make_pair(std::move(header), std::move(begin));+ }+};++namespace detail+{++// Types that are only used in the sending/parsing of messages, not+// publicly exposed.+using ProtocolHeader = std::array<char, 8>;+const ProtocolHeader kProtocolHeader = {{'_', 'l', 'i', 'n', 'k', '_', 'v', 1}};++// Must have at least kMaxMessageSize bytes available in the output stream+template <typename Payload, typename It>+It encodeMessage(const MessageType messageType, const Payload& payload, It out)+{+ using namespace std;+ const MessageHeader header = {messageType};+ const auto messageSize =+ kProtocolHeader.size() + sizeInByteStream(header) + sizeInByteStream(payload);++ if (messageSize < kMaxMessageSize)+ {+ return toNetworkByteStream(+ payload, toNetworkByteStream(header,+ copy(begin(kProtocolHeader), end(kProtocolHeader), std::move(out))));+ }+ else+ {+ throw range_error("Exceeded maximum message size");+ }+}++} // namespace detail++template <typename Payload, typename It>+It pingMessage(const Payload& payload, It out)+{+ return detail::encodeMessage(kPing, payload, std::move(out));+}++template <typename Payload, typename It>+It pongMessage(const Payload& payload, It out)+{+ return detail::encodeMessage(kPong, payload, std::move(out));+}++template <typename It>+std::pair<MessageHeader, It> parseMessageHeader(It bytesBegin, const It bytesEnd)+{+ using ItDiff = typename std::iterator_traits<It>::difference_type;++ MessageHeader header = {};+ const auto protocolHeaderSize = discovery::sizeInByteStream(detail::kProtocolHeader);+ const auto minMessageSize =+ static_cast<ItDiff>(protocolHeaderSize + sizeInByteStream(header));++ // If there are enough bytes in the stream to make a header and if+ // the first bytes in the stream are the protocol header, then+ // proceed to parse the stream.+ if (std::distance(bytesBegin, bytesEnd) >= minMessageSize+ && std::equal(+ begin(detail::kProtocolHeader), end(detail::kProtocolHeader), bytesBegin))+ {+ std::tie(header, bytesBegin) =+ MessageHeader::fromNetworkByteStream(bytesBegin + protocolHeaderSize, bytesEnd);+ }+ return std::make_pair(std::move(header), std::move(bytesBegin));+}++} // namespace v1+} // namespace link+} // namespace ableton
+ link/include/ableton/platforms/Config.hpp view
@@ -0,0 +1,101 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/link/Controller.hpp>+#include <ableton/util/Log.hpp>++#if defined(LINK_PLATFORM_WINDOWS)+#include <ableton/platforms/asio/Context.hpp>+#include <ableton/platforms/stl/Random.hpp>+#include <ableton/platforms/windows/Clock.hpp>+#include <ableton/platforms/windows/ScanIpIfAddrs.hpp>+#if defined(LINK_WINDOWS_SETTHREADDESCRIPTION)+#include <ableton/platforms/windows/ThreadFactory.hpp>+#endif+#elif defined(LINK_PLATFORM_MACOSX)+#include <ableton/platforms/asio/Context.hpp>+#include <ableton/platforms/darwin/Clock.hpp>+#include <ableton/platforms/darwin/ThreadFactory.hpp>+#include <ableton/platforms/posix/ScanIpIfAddrs.hpp>+#include <ableton/platforms/stl/Random.hpp>+#elif defined(LINK_PLATFORM_LINUX)+#include <ableton/platforms/asio/Context.hpp>+#include <ableton/platforms/linux/Clock.hpp>+#include <ableton/platforms/posix/ScanIpIfAddrs.hpp>+#include <ableton/platforms/stl/Random.hpp>+#ifdef __linux__+#include <ableton/platforms/linux/ThreadFactory.hpp>+#endif+#elif defined(ESP_PLATFORM)+#include <ableton/platforms/esp32/Clock.hpp>+#include <ableton/platforms/esp32/Context.hpp>+#include <ableton/platforms/esp32/Random.hpp>+#include <ableton/platforms/esp32/ScanIpIfAddrs.hpp>+#endif++namespace ableton+{+namespace link+{+namespace platform+{++#if defined(LINK_PLATFORM_WINDOWS)+using Clock = platforms::windows::Clock;+using Random = platforms::stl::Random;+#if defined(LINK_WINDOWS_SETTHREADDESCRIPTION)+using IoContext = platforms::asio::Context<platforms::windows::ScanIpIfAddrs,+ util::NullLog,+ platforms::windows::ThreadFactory>;+#else+using IoContext =+ platforms::asio::Context<platforms::windows::ScanIpIfAddrs, util::NullLog>;+#endif++#elif defined(LINK_PLATFORM_MACOSX)+using Clock = platforms::darwin::Clock;+using IoContext = platforms::asio::Context<platforms::posix::ScanIpIfAddrs,+ util::NullLog,+ platforms::darwin::ThreadFactory>;+using Random = platforms::stl::Random;++#elif defined(LINK_PLATFORM_LINUX)+using Clock = platforms::linux::ClockMonotonicRaw;+using Random = platforms::stl::Random;+#ifdef __linux__+using IoContext = platforms::asio::Context<platforms::posix::ScanIpIfAddrs,+ util::NullLog,+ platforms::linux::ThreadFactory>;+#else+using IoContext =+ platforms::asio::Context<platforms::posix::ScanIpIfAddrs, util::NullLog>;+#endif++#elif defined(ESP_PLATFORM)+using Clock = platforms::esp32::Clock;+using IoContext =+ platforms::esp32::Context<platforms::esp32::ScanIpIfAddrs, util::NullLog>;+using Random = platforms::esp32::Random;+#endif++} // namespace platform+} // namespace link+} // namespace ableton
+ link/include/ableton/platforms/asio/AsioTimer.hpp view
@@ -0,0 +1,132 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/util/SafeAsyncHandler.hpp>+#include <functional>++namespace ableton+{+namespace platforms+{+namespace asio+{++// This implementation is based on the boost::asio::system_timer concept.+// Since boost::system_timer doesn't support move semantics, we create a wrapper+// with a unique_ptr to get a movable type. It also handles an inconvenient+// aspect of asio timers, which is that you must explicitly guard against the+// handler firing after cancellation. We handle this by use of the SafeAsyncHandler+// utility. AsioTimer therefore guarantees that a handler will not be called after+// the destruction of the timer, or after the timer has been canceled.++class AsioTimer+{+public:+ using ErrorCode = ::asio::error_code;+ using TimePoint = std::chrono::system_clock::time_point;++ AsioTimer(::asio::io_service& io)+ : mpTimer(new ::asio::system_timer(io))+ , mpAsyncHandler(std::make_shared<AsyncHandler>())+ {+ }++ ~AsioTimer()+ {+ // The timer may not be valid anymore if this instance was moved from+ if (mpTimer != nullptr)+ {+ // Ignore errors during cancellation+ cancel();+ }+ }++ AsioTimer(const AsioTimer&) = delete;+ AsioTimer& operator=(const AsioTimer&) = delete;++ // Enable move construction but not move assignment. Move assignment+ // would get weird - would have to handle outstanding handlers+ AsioTimer(AsioTimer&& rhs)+ : mpTimer(std::move(rhs.mpTimer))+ , mpAsyncHandler(std::move(rhs.mpAsyncHandler))+ {+ }++ void expires_at(std::chrono::system_clock::time_point tp)+ {+ mpTimer->expires_at(std::move(tp));+ }++ template <typename T>+ void expires_from_now(T duration)+ {+ mpTimer->expires_from_now(std::move(duration));+ }++ ErrorCode cancel()+ {+ ErrorCode ec;+ mpTimer->cancel(ec);+ mpAsyncHandler->mpHandler = nullptr;+ return ec;+ }++ template <typename Handler>+ void async_wait(Handler handler)+ {+ *mpAsyncHandler = std::move(handler);+ mpTimer->async_wait(util::makeAsyncSafe(mpAsyncHandler));+ }++ TimePoint now() const+ {+ return std::chrono::system_clock::now();+ }++private:+ struct AsyncHandler+ {+ template <typename Handler>+ AsyncHandler& operator=(Handler handler)+ {+ mpHandler = [handler](ErrorCode ec) { handler(std::move(ec)); };+ return *this;+ }++ void operator()(ErrorCode ec)+ {+ if (mpHandler)+ {+ mpHandler(std::move(ec));+ }+ }++ std::function<void(const ErrorCode)> mpHandler;+ };++ std::unique_ptr<::asio::system_timer> mpTimer;+ std::shared_ptr<AsyncHandler> mpAsyncHandler;+};++} // namespace asio+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/asio/AsioWrapper.hpp view
@@ -0,0 +1,90 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++/*!+ * \brief Wrapper file for AsioStandalone library+ *+ * This file includes all necessary headers from the AsioStandalone library which are used+ * by Link.+ */++#if !defined(ESP_PLATFORM)+#pragma push_macro("ASIO_STANDALONE")+#define ASIO_STANDALONE 1++#pragma push_macro("ASIO_NO_TYPEID")+#define ASIO_NO_TYPEID 1+#endif++#if defined(LINK_PLATFORM_WINDOWS)+#pragma push_macro("INCL_EXTRA_HTON_FUNCTIONS")+#define INCL_EXTRA_HTON_FUNCTIONS 1+#endif++#if defined(WIN32) || defined(_WIN32)+#if !defined(_WIN32_WINNT)+#define _WIN32_WINNT 0x0501+#endif+#endif++#if defined(__clang__)+#pragma clang diagnostic push+#if __has_warning("-Wcomma")+#pragma clang diagnostic ignored "-Wcomma"+#endif+#if __has_warning("-Wshorten-64-to-32")+#pragma clang diagnostic ignored "-Wshorten-64-to-32"+#endif+#if __has_warning("-Wunused-local-typedef")+#pragma clang diagnostic ignored "-Wunused-local-typedef"+#endif+#endif++#if defined(_MSC_VER)+#define _SCL_SECURE_NO_WARNINGS 1+#pragma warning(push, 0)+#pragma warning(disable : 4242)+#pragma warning(disable : 4668)+#pragma warning(disable : 4702)+#pragma warning(disable : 5204)+#pragma warning(disable : 5220)+#endif++#include <asio.hpp>+#include <asio/system_timer.hpp>++#if defined(LINK_PLATFORM_WINDOWS)+#pragma pop_macro("INCL_EXTRA_HTON_FUNCTIONS")+#endif++#if !defined(ESP_PLATFORM)+#pragma pop_macro("ASIO_STANDALONE")+#pragma pop_macro("ASIO_NO_TYPEID")+#endif++#if defined(_MSC_VER)+#pragma warning(pop)+#undef _SCL_SECURE_NO_WARNINGS+#endif++#if defined(__clang__)+#pragma clang diagnostic pop+#endif
+ link/include/ableton/platforms/asio/Context.hpp view
@@ -0,0 +1,196 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/IpV4Interface.hpp>+#include <ableton/platforms/asio/AsioTimer.hpp>+#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/platforms/asio/LockFreeCallbackDispatcher.hpp>+#include <ableton/platforms/asio/Socket.hpp>+#include <thread>+#include <utility>++namespace ableton+{+namespace platforms+{+namespace asio+{+namespace+{++struct ThreadFactory+{+ template <typename Callable, typename... Args>+ static std::thread makeThread(std::string, Callable&& f, Args&&... args)+ {+ return std::thread(std::forward<Callable>(f), std::forward<Args>(args)...);+ }+};++} // namespace++template <typename ScanIpIfAddrs, typename LogT, typename ThreadFactoryT = ThreadFactory>+class Context+{+public:+ using Timer = AsioTimer;+ using Log = LogT;++ template <typename Handler, typename Duration>+ using LockFreeCallbackDispatcher =+ LockFreeCallbackDispatcher<Handler, Duration, ThreadFactoryT>;++ template <std::size_t BufferSize>+ using Socket = asio::Socket<BufferSize>;++ Context()+ : Context(DefaultHandler{})+ {+ }++ template <typename ExceptionHandler>+ explicit Context(ExceptionHandler exceptHandler)+ : mpService(new ::asio::io_service())+ , mpWork(new ::asio::io_service::work(*mpService))+ {+ mThread = ThreadFactoryT::makeThread("Link Main",+ [](::asio::io_service& service, ExceptionHandler handler) {+ for (;;)+ {+ try+ {+ service.run();+ break;+ }+ catch (const typename ExceptionHandler::Exception& exception)+ {+ handler(exception);+ }+ }+ },+ std::ref(*mpService), std::move(exceptHandler));+ }++ Context(const Context&) = delete;++ Context(Context&& rhs)+ : mpService(std::move(rhs.mpService))+ , mpWork(std::move(rhs.mpWork))+ , mThread(std::move(rhs.mThread))+ , mLog(std::move(rhs.mLog))+ , mScanIpIfAddrs(std::move(rhs.mScanIpIfAddrs))+ {+ }++ ~Context()+ {+ if (mpService && mpWork)+ {+ mpWork.reset();+ mThread.join();+ }+ }++ void stop()+ {+ if (mpService && mpWork)+ {+ mpWork.reset();+ mpService->stop();+ mThread.join();+ }+ }+++ template <std::size_t BufferSize>+ Socket<BufferSize> openUnicastSocket(const ::asio::ip::address_v4& addr)+ {+ auto socket = Socket<BufferSize>{*mpService};+ socket.mpImpl->mSocket.set_option(+ ::asio::ip::multicast::enable_loopback(addr.is_loopback()));+ socket.mpImpl->mSocket.set_option(::asio::ip::multicast::outbound_interface(addr));+ socket.mpImpl->mSocket.bind(::asio::ip::udp::endpoint{addr, 0});+ return socket;+ }++ template <std::size_t BufferSize>+ Socket<BufferSize> openMulticastSocket(const ::asio::ip::address_v4& addr)+ {+ auto socket = Socket<BufferSize>{*mpService};+ socket.mpImpl->mSocket.set_option(::asio::ip::udp::socket::reuse_address(true));+ socket.mpImpl->mSocket.set_option(+ ::asio::socket_base::broadcast(!addr.is_loopback()));+ socket.mpImpl->mSocket.set_option(+ ::asio::ip::multicast::enable_loopback(addr.is_loopback()));+ socket.mpImpl->mSocket.set_option(::asio::ip::multicast::outbound_interface(addr));+ socket.mpImpl->mSocket.bind({::asio::ip::address::from_string("0.0.0.0"),+ discovery::multicastEndpoint().port()});+ socket.mpImpl->mSocket.set_option(::asio::ip::multicast::join_group(+ discovery::multicastEndpoint().address().to_v4(), addr));+ return socket;+ }++ std::vector<::asio::ip::address> scanNetworkInterfaces()+ {+ return mScanIpIfAddrs();+ }++ Timer makeTimer() const+ {+ return {*mpService};+ }++ Log& log()+ {+ return mLog;+ }++ template <typename Handler>+ void async(Handler handler)+ {+ mpService->post(std::move(handler));+ }++private:+ // Default handler is hidden and defines a hidden exception type+ // that will never be thrown by other code, so it effectively does+ // not catch.+ struct DefaultHandler+ {+ struct Exception+ {+ };++ void operator()(const Exception&)+ {+ }+ };++ std::unique_ptr<::asio::io_service> mpService;+ std::unique_ptr<::asio::io_service::work> mpWork;+ std::thread mThread;+ Log mLog;+ ScanIpIfAddrs mScanIpIfAddrs;+};++} // namespace asio+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/asio/LockFreeCallbackDispatcher.hpp view
@@ -0,0 +1,88 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <atomic>+#include <condition_variable>+#include <thread>++namespace ableton+{+namespace platforms+{+namespace asio+{++// Utility to signal invocation of a callback on another thread in a lock free manner.+// The callback is evoked on a thread owned by the instance of this class.+//+// A condition variable is used to notify a waiting thread, but only if the required+// lock can be acquired immediately. If that fails, we fall back on signaling+// after a timeout. This gives us a guaranteed minimum signaling rate which is defined+// by the fallbackPeriod parameter.++template <typename Callback, typename Duration, typename ThreadFactory>+class LockFreeCallbackDispatcher+{+public:+ LockFreeCallbackDispatcher(Callback callback, Duration fallbackPeriod)+ : mCallback(std::move(callback))+ , mFallbackPeriod(std::move(fallbackPeriod))+ , mRunning(true)+ , mThread(ThreadFactory::makeThread("Link Dispatcher", [this] { run(); }))+ {+ }++ ~LockFreeCallbackDispatcher()+ {+ mRunning = false;+ mCondition.notify_one();+ mThread.join();+ }++ void invoke()+ {+ mCondition.notify_one();+ }++private:+ void run()+ {+ while (mRunning.load())+ {+ {+ std::unique_lock<std::mutex> lock(mMutex);+ mCondition.wait_for(lock, mFallbackPeriod);+ }+ mCallback();+ }+ }++ Callback mCallback;+ Duration mFallbackPeriod;+ std::atomic<bool> mRunning;+ std::mutex mMutex;+ std::condition_variable mCondition;+ std::thread mThread;+};++} // namespace asio+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/asio/Socket.hpp view
@@ -0,0 +1,110 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/util/SafeAsyncHandler.hpp>+#include <array>+#include <cassert>++namespace ableton+{+namespace platforms+{+namespace asio+{++template <std::size_t MaxPacketSize>+struct Socket+{+ Socket(::asio::io_service& io)+ : mpImpl(std::make_shared<Impl>(io))+ {+ }++ Socket(const Socket&) = delete;+ Socket& operator=(const Socket&) = delete;++ Socket(Socket&& rhs)+ : mpImpl(std::move(rhs.mpImpl))+ {+ }++ std::size_t send(const uint8_t* const pData,+ const size_t numBytes,+ const ::asio::ip::udp::endpoint& to)+ {+ assert(numBytes < MaxPacketSize);+ return mpImpl->mSocket.send_to(::asio::buffer(pData, numBytes), to);+ }++ template <typename Handler>+ void receive(Handler handler)+ {+ mpImpl->mHandler = std::move(handler);+ mpImpl->mSocket.async_receive_from(+ ::asio::buffer(mpImpl->mReceiveBuffer, MaxPacketSize), mpImpl->mSenderEndpoint,+ util::makeAsyncSafe(mpImpl));+ }++ ::asio::ip::udp::endpoint endpoint() const+ {+ return mpImpl->mSocket.local_endpoint();+ }++ struct Impl+ {+ Impl(::asio::io_service& io)+ : mSocket(io, ::asio::ip::udp::v4())+ {+ }++ ~Impl()+ {+ // Ignore error codes in shutdown and close as the socket may+ // have already been forcibly closed+ ::asio::error_code ec;+ mSocket.shutdown(::asio::ip::udp::socket::shutdown_both, ec);+ mSocket.close(ec);+ }++ void operator()(const ::asio::error_code& error, const std::size_t numBytes)+ {+ if (!error && numBytes > 0 && numBytes <= MaxPacketSize)+ {+ const auto bufBegin = begin(mReceiveBuffer);+ mHandler(mSenderEndpoint, bufBegin, bufBegin + static_cast<ptrdiff_t>(numBytes));+ }+ }++ ::asio::ip::udp::socket mSocket;+ ::asio::ip::udp::endpoint mSenderEndpoint;+ using Buffer = std::array<uint8_t, MaxPacketSize>;+ Buffer mReceiveBuffer;+ using ByteIt = typename Buffer::const_iterator;+ std::function<void(const ::asio::ip::udp::endpoint&, ByteIt, ByteIt)> mHandler;+ };++ std::shared_ptr<Impl> mpImpl;+};++} // namespace asio+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/asio/Util.hpp view
@@ -0,0 +1,43 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <algorithm>++namespace ableton+{+namespace platforms+{+namespace asio+{++// Utility for making v4 or v6 ip addresses from raw bytes in network byte-order+template <typename AsioAddrType>+AsioAddrType makeAddress(const char* pAddr)+{+ using namespace std;+ typename AsioAddrType::bytes_type bytes;+ copy(pAddr, pAddr + bytes.size(), begin(bytes));+ return AsioAddrType{bytes};+}++} // namespace asio+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/darwin/Clock.hpp view
@@ -0,0 +1,70 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <chrono>+#include <mach/mach_time.h>++namespace ableton+{+namespace platforms+{+namespace darwin+{++struct Clock+{+ using Ticks = std::uint64_t;+ using Micros = std::chrono::microseconds;++ Clock()+ {+ mach_timebase_info_data_t timeInfo;+ mach_timebase_info(&timeInfo);+ // numer / denom gives nanoseconds, we want microseconds+ mTicksToMicros = timeInfo.numer / (timeInfo.denom * 1000.);+ }++ Micros ticksToMicros(const Ticks ticks) const+ {+ return Micros{llround(mTicksToMicros * ticks)};+ }++ Ticks microsToTicks(const Micros micros) const+ {+ return static_cast<Ticks>(micros.count() / mTicksToMicros);+ }++ Ticks ticks() const+ {+ return mach_absolute_time();+ }++ std::chrono::microseconds micros() const+ {+ return ticksToMicros(ticks());+ }++ double mTicksToMicros;+};++} // namespace darwin+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/darwin/Darwin.hpp view
@@ -0,0 +1,30 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++// ntohll and htonll are not defined in 10.7 SDK, so we provide a compatibility macro here++#ifndef ntohll+#define ntohll(x) __DARWIN_OSSwapInt64(x)+#endif++#ifndef htonll+#define htonll(x) __DARWIN_OSSwapInt64(x)+#endif
+ link/include/ableton/platforms/darwin/ThreadFactory.hpp view
@@ -0,0 +1,48 @@+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <pthread.h>+#include <thread>+#include <utility>++namespace ableton+{+namespace platforms+{+namespace darwin+{++struct ThreadFactory+{+ template <typename Callable, typename... Args>+ static std::thread makeThread(std::string name, Callable&& f, Args&&... args)+ {+ return std::thread{[](std::string name, Callable&& f, Args&&... args) {+ pthread_setname_np(name.c_str());+ f(args...);+ },+ std::move(name), std::forward<Callable>(f), std::forward<Args>(args)...};+ }+};++} // namespace darwin+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/esp32/Clock.hpp view
@@ -0,0 +1,36 @@+/* Copyright 2019, Mathias Bredholt, Torso Electronics, Copenhagen. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ */++#pragma once++#include "esp_timer.h"++namespace ableton+{+namespace platforms+{+namespace esp32+{+struct Clock+{+ std::chrono::microseconds micros() const+ {+ return static_cast<std::chrono::microseconds>(esp_timer_get_time());+ }+};+} // namespace esp32+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/esp32/Context.hpp view
@@ -0,0 +1,228 @@+/* Copyright 2020, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/discovery/IpV4Interface.hpp>+#include <ableton/platforms/asio/AsioTimer.hpp>+#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/platforms/asio/Socket.hpp>+#include <ableton/platforms/esp32/LockFreeCallbackDispatcher.hpp>+#include <driver/timer.h>+#include <freertos/FreeRTOS.h>+#include <freertos/task.h>++namespace ableton+{+namespace platforms+{+namespace esp32+{++template <typename ScanIpIfAddrs, typename LogT>+class Context+{+ class ServiceRunner+ {++ static void run(void* userParams)+ {+ auto runner = static_cast<ServiceRunner*>(userParams);+ for (;;)+ {+ try+ {+ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);+ runner->mpService->poll_one();+ }+ catch (...)+ {+ }+ }+ }++ static void IRAM_ATTR timerIsr(void* userParam)+ {+ static BaseType_t xHigherPriorityTaskWoken = pdFALSE;++ timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_1);+ timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_1);++ vTaskNotifyGiveFromISR(userParam, &xHigherPriorityTaskWoken);+ if (xHigherPriorityTaskWoken)+ {+ portYIELD_FROM_ISR();+ }+ }++ public:+ ServiceRunner()+ : mpService(new ::asio::io_service())+ , mpWork(new ::asio::io_service::work(*mpService))+ {+ xTaskCreatePinnedToCore(run, "link", 8192, this, 2 | portPRIVILEGE_BIT,+ &mTaskHandle, LINK_ESP_TASK_CORE_ID);++ timer_config_t config = {.alarm_en = TIMER_ALARM_EN,+ .counter_en = TIMER_PAUSE,+ .intr_type = TIMER_INTR_LEVEL,+ .counter_dir = TIMER_COUNT_UP,+ .auto_reload = TIMER_AUTORELOAD_EN,+ .divider = 80};++ timer_init(TIMER_GROUP_0, TIMER_1, &config);+ timer_set_counter_value(TIMER_GROUP_0, TIMER_1, 0);+ timer_set_alarm_value(TIMER_GROUP_0, TIMER_1, 100);+ timer_enable_intr(TIMER_GROUP_0, TIMER_1);+ timer_isr_register(TIMER_GROUP_0, TIMER_1, &timerIsr, mTaskHandle, 0, nullptr);++ timer_start(TIMER_GROUP_0, TIMER_1);+ }++ ~ServiceRunner()+ {+ vTaskDelete(mTaskHandle);+ }++ template <typename Handler>+ void async(Handler handler)+ {+ mpService->post(std::move(handler));+ }++ ::asio::io_service& service() const+ {+ return *mpService;+ }++ private:+ TaskHandle_t mTaskHandle;+ std::unique_ptr<::asio::io_service> mpService;+ std::unique_ptr<::asio::io_service::work> mpWork;+ };++public:+ using Timer = ::ableton::platforms::asio::AsioTimer;+ using Log = LogT;++ template <typename Handler, typename Duration>+ using LockFreeCallbackDispatcher = LockFreeCallbackDispatcher<Handler, Duration>;++ template <std::size_t BufferSize>+ using Socket = asio::Socket<BufferSize>;++ Context()+ : Context(DefaultHandler{})+ {+ }++ template <typename ExceptionHandler>+ explicit Context(ExceptionHandler exceptHandler)+ {+ }++ Context(const Context&) = delete;++ Context(Context&& rhs)+ : mLog(std::move(rhs.mLog))+ , mScanIpIfAddrs(std::move(rhs.mScanIpIfAddrs))+ {+ }++ void stop()+ {+ }++ template <std::size_t BufferSize>+ Socket<BufferSize> openUnicastSocket(const ::asio::ip::address_v4& addr)+ {+ auto socket = Socket<BufferSize>{serviceRunner().service()};+ socket.mpImpl->mSocket.set_option(+ ::asio::ip::multicast::enable_loopback(addr.is_loopback()));+ socket.mpImpl->mSocket.set_option(::asio::ip::multicast::outbound_interface(addr));+ socket.mpImpl->mSocket.bind(::asio::ip::udp::endpoint{addr, 0});+ return socket;+ }++ template <std::size_t BufferSize>+ Socket<BufferSize> openMulticastSocket(const ::asio::ip::address_v4& addr)+ {+ auto socket = Socket<BufferSize>{serviceRunner().service()};+ socket.mpImpl->mSocket.set_option(::asio::ip::udp::socket::reuse_address(true));+ socket.mpImpl->mSocket.set_option(+ ::asio::socket_base::broadcast(!addr.is_loopback()));+ socket.mpImpl->mSocket.set_option(+ ::asio::ip::multicast::enable_loopback(addr.is_loopback()));+ socket.mpImpl->mSocket.set_option(::asio::ip::multicast::outbound_interface(addr));+ socket.mpImpl->mSocket.bind({::asio::ip::address::from_string("0.0.0.0"),+ discovery::multicastEndpoint().port()});+ socket.mpImpl->mSocket.set_option(::asio::ip::multicast::join_group(+ discovery::multicastEndpoint().address().to_v4(), addr));+ return socket;+ }++ std::vector<::asio::ip::address> scanNetworkInterfaces()+ {+ return mScanIpIfAddrs();+ }++ Timer makeTimer() const+ {+ return {serviceRunner().service()};+ }++ Log& log()+ {+ return mLog;+ }++ template <typename Handler>+ void async(Handler handler)+ {+ serviceRunner().service().post(std::move(handler));+ }++private:+ // Default handler is hidden and defines a hidden exception type+ // that will never be thrown by other code, so it effectively does+ // not catch.+ struct DefaultHandler+ {+ struct Exception+ {+ };++ void operator()(const Exception&)+ {+ }+ };++ static ServiceRunner& serviceRunner()+ {+ static ServiceRunner runner;+ return runner;+ }++ Log mLog;+ ScanIpIfAddrs mScanIpIfAddrs;+};++} // namespace esp32+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/esp32/Esp32.hpp view
@@ -0,0 +1,27 @@+/* Copyright 2019, Mathias Bredholt, Torso Electronics, Copenhagen. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ */++#pragma once++#include <endian.h>++#ifndef ntohll+#define ntohll(x) bswap64(x)+#endif++#ifndef htonll+#define htonll(x) bswap64(x)+#endif
+ link/include/ableton/platforms/esp32/LockFreeCallbackDispatcher.hpp view
@@ -0,0 +1,94 @@+/* Copyright 2020, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <atomic>+#include <condition_variable>+#include <freertos/task.h>++namespace ableton+{+namespace platforms+{+namespace esp32+{++// Utility to signal invocation of a callback on another thread in a lock free manner.+// The callback is evoked on a thread owned by the instance of this class.+//+// A condition variable is used to notify a waiting thread, but only if the required+// lock can be acquired immediately. If that fails, we fall back on signaling+// after a timeout. This gives us a guaranteed minimum signaling rate which is defined+// by the fallbackPeriod parameter.++template <typename Callback, typename Duration>+class LockFreeCallbackDispatcher+{+public:+ LockFreeCallbackDispatcher(Callback callback, Duration fallbackPeriod)+ : mCallback(std::move(callback))+ , mFallbackPeriod(std::move(fallbackPeriod))+ , mRunning(true)+ {+ xTaskCreate(run, "link", 4096, this, tskIDLE_PRIORITY, &mTaskHandle);+ }++ ~LockFreeCallbackDispatcher()+ {+ mRunning = false;+ mCondition.notify_one();+ vTaskDelete(mTaskHandle);+ }++ void invoke()+ {+ if (mMutex.try_lock())+ {+ mCondition.notify_one();+ mMutex.unlock();+ }+ }++private:+ static void run(void* userData)+ {+ auto dispatcher = static_cast<LockFreeCallbackDispatcher*>(userData);+ while (dispatcher->mRunning.load())+ {+ {+ std::unique_lock<std::mutex> lock(dispatcher->mMutex);+ dispatcher->mCondition.wait_for(lock, dispatcher->mFallbackPeriod);+ }+ dispatcher->mCallback();+ vTaskDelay(1);+ }+ }++ Callback mCallback;+ Duration mFallbackPeriod;+ std::atomic<bool> mRunning;+ std::mutex mMutex;+ std::condition_variable mCondition;+ TaskHandle_t mTaskHandle;+};++} // namespace esp32+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/esp32/Random.hpp view
@@ -0,0 +1,36 @@+/* Copyright 2019, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ */++#pragma once++namespace ableton+{+namespace platforms+{+namespace esp32+{++struct Random+{+ uint8_t operator()()+ {+ return static_cast<uint8_t>((esp_random() % 93) + 33); // printable ascii chars+ }+};++} // namespace esp32+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/esp32/ScanIpIfAddrs.hpp view
@@ -0,0 +1,59 @@+/* Copyright 2020, Ableton AG, Berlin and 2019, Mathias Bredholt, Torso Electronics,+ * Copenhagen. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ */++#pragma once++#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <arpa/inet.h>+#include <esp_netif.h>+#include <net/if.h>+#include <vector>++namespace ableton+{+namespace platforms+{+namespace esp32+{++// ESP32 implementation of ip interface address scanner+struct ScanIpIfAddrs+{+ std::vector<::asio::ip::address> operator()()+ {+ std::vector<::asio::ip::address> addrs;+ // Get first network interface+ esp_netif_t* esp_netif = esp_netif_next(NULL);+ while (esp_netif)+ {+ // Check if interface is active+ if (esp_netif_is_netif_up(esp_netif))+ {+ esp_netif_ip_info_t ip_info;+ esp_netif_get_ip_info(esp_netif, &ip_info);+ addrs.emplace_back(::asio::ip::address_v4(ntohl(ip_info.ip.addr)));+ }+ // Get next network interface+ esp_netif = esp_netif_next(esp_netif);+ }+ return addrs;+ }+};++} // namespace esp32+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/linux/Clock.hpp view
@@ -0,0 +1,60 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <chrono>+#include <cmath>+#include <ctime>++namespace ableton+{+namespace platforms+{++#ifdef linux+#undef linux+#endif++#if defined(__FreeBSD_kernel__)+#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC+#endif++namespace linux+{++template <clockid_t CLOCK>+class Clock+{+public:+ std::chrono::microseconds micros() const+ {+ ::timespec ts;+ ::clock_gettime(CLOCK, &ts);+ std::uint64_t ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec;+ return std::chrono::microseconds(ns / 1000ULL);+ }+};++using ClockMonotonic = Clock<CLOCK_MONOTONIC>;+using ClockMonotonicRaw = Clock<CLOCK_MONOTONIC_RAW>;++} // namespace linux+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/linux/Linux.hpp view
@@ -0,0 +1,30 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <byteswap.h>++#ifndef ntohll+#define ntohll(x) bswap_64(x)+#endif++#ifndef htonll+#define htonll(x) bswap_64(x)+#endif
+ link/include/ableton/platforms/linux/ThreadFactory.hpp view
@@ -0,0 +1,45 @@+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <pthread.h>+#include <thread>++namespace ableton+{+namespace platforms+{+namespace linux+{++struct ThreadFactory+{+ template <typename Callable, typename... Args>+ static std::thread makeThread(std::string name, Callable&& f, Args&&... args)+ {+ auto thread = std::thread(std::forward<Callable>(f), std::forward<Args>(args)...);+ pthread_setname_np(thread.native_handle(), name.c_str());+ return thread;+ }+};++} // namespace linux+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/posix/ScanIpIfAddrs.hpp view
@@ -0,0 +1,110 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/platforms/asio/Util.hpp>+#include <arpa/inet.h>+#include <ifaddrs.h>+#include <net/if.h>+#include <vector>++namespace ableton+{+namespace platforms+{+namespace posix+{+namespace detail+{++// RAII type to make [get,free]ifaddrs function pairs exception safe+class GetIfAddrs+{+public:+ GetIfAddrs()+ {+ if (getifaddrs(&interfaces)) // returns 0 on success+ {+ interfaces = NULL;+ }+ }+ ~GetIfAddrs()+ {+ if (interfaces)+ freeifaddrs(interfaces);+ }++ // RAII must not copy+ GetIfAddrs(GetIfAddrs&) = delete;+ GetIfAddrs& operator=(GetIfAddrs&) = delete;++ template <typename Function>+ void withIfAddrs(Function f)+ {+ if (interfaces)+ f(*interfaces);+ }++private:+ struct ifaddrs* interfaces = NULL;+};++} // namespace detail+++// Posix implementation of ip interface address scanner+struct ScanIpIfAddrs+{+ // Scan active network interfaces and return corresponding addresses+ // for all ip-based interfaces.+ std::vector<::asio::ip::address> operator()()+ {+ std::vector<::asio::ip::address> addrs;++ detail::GetIfAddrs getIfAddrs;+ getIfAddrs.withIfAddrs([&addrs](const struct ifaddrs& interfaces) {+ const struct ifaddrs* interface;+ for (interface = &interfaces; interface; interface = interface->ifa_next)+ {+ auto addr = reinterpret_cast<const struct sockaddr_in*>(interface->ifa_addr);+ if (addr && interface->ifa_flags & IFF_UP)+ {+ if (addr->sin_family == AF_INET)+ {+ auto bytes = reinterpret_cast<const char*>(&addr->sin_addr);+ addrs.emplace_back(asio::makeAddress<::asio::ip::address_v4>(bytes));+ }+ else if (addr->sin_family == AF_INET6)+ {+ auto addr6 = reinterpret_cast<const struct sockaddr_in6*>(addr);+ auto bytes = reinterpret_cast<const char*>(&addr6->sin6_addr);+ addrs.emplace_back(asio::makeAddress<::asio::ip::address_v6>(bytes));+ }+ }+ }+ });+ return addrs;+ }+};++} // namespace posix+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/stl/Clock.hpp view
@@ -0,0 +1,43 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <chrono>++namespace ableton+{+namespace platforms+{+namespace stl+{++struct Clock+{+ std::chrono::microseconds micros() const+ {+ using namespace std::chrono;+ auto nowInMicros = time_point_cast<microseconds>(steady_clock::now());+ return nowInMicros.time_since_epoch();+ }+};++} // namespace stl+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/stl/Random.hpp view
@@ -0,0 +1,51 @@+/* Copyright 2019, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <random>++namespace ableton+{+namespace platforms+{+namespace stl+{++struct Random+{+ Random()+ : gen(rd())+ , dist(33, 126) // printable ascii chars+ {+ }++ uint8_t operator()()+ {+ return static_cast<uint8_t>(dist(gen));+ }++ std::random_device rd;+ std::mt19937 gen;+ std::uniform_int_distribution<unsigned> dist;+};++} // namespace stl+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/windows/Clock.hpp view
@@ -0,0 +1,71 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <chrono>+#include <cstdint>++namespace ableton+{+namespace platforms+{+namespace windows+{++struct Clock+{+ using Ticks = std::int64_t;+ using Micros = std::chrono::microseconds;++ Clock()+ {+ LARGE_INTEGER frequency;+ QueryPerformanceFrequency(&frequency);+ mTicksToMicros = 1.0e6 / static_cast<double>(frequency.QuadPart);+ }++ Micros ticksToMicros(const Ticks ticks) const+ {+ return Micros{llround(mTicksToMicros * static_cast<double>(ticks))};+ }++ Ticks microsToTicks(const Micros micros) const+ {+ return static_cast<Ticks>(static_cast<double>(micros.count()) / mTicksToMicros);+ }++ Ticks ticks() const+ {+ LARGE_INTEGER count;+ QueryPerformanceCounter(&count);+ return count.QuadPart;+ }++ std::chrono::microseconds micros() const+ {+ return ticksToMicros(ticks());+ }++ double mTicksToMicros;+};++} // namespace windows+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/windows/ScanIpIfAddrs.hpp view
@@ -0,0 +1,140 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/platforms/asio/Util.hpp>+#include <iphlpapi.h>+#include <stdio.h>+#include <vector>+#include <winsock2.h>+#include <ws2tcpip.h>++#pragma comment(lib, "iphlpapi.lib")+#pragma comment(lib, "ws2_32.lib")++namespace ableton+{+namespace platforms+{+namespace windows+{+namespace detail+{+// RAII type to make [get,free]ifaddrs function pairs exception safe+class GetIfAddrs+{+public:+ GetIfAddrs()+ {+ const int MAX_TRIES = 3; // MSFT recommendation+ const int WORKING_BUFFER_SIZE = 15000; // MSFT recommendation++ DWORD adapter_addrs_buffer_size = WORKING_BUFFER_SIZE;+ for (int i = 0; i < MAX_TRIES; i++)+ {+ adapter_addrs = (IP_ADAPTER_ADDRESSES*)malloc(adapter_addrs_buffer_size);+ assert(adapter_addrs);++ DWORD error = ::GetAdaptersAddresses(AF_UNSPEC,+ GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER+ | GAA_FLAG_SKIP_FRIENDLY_NAME,+ NULL, adapter_addrs, &adapter_addrs_buffer_size);++ if (error == ERROR_SUCCESS)+ {+ break;+ }+ // if buffer too small, use new buffer size in next iteration+ if (error == ERROR_BUFFER_OVERFLOW)+ {+ free(adapter_addrs);+ adapter_addrs = NULL;+ continue;+ }+ }+ }+ ~GetIfAddrs()+ {+ if (adapter_addrs)+ free(adapter_addrs);+ }++ // RAII must not copy+ GetIfAddrs(GetIfAddrs&) = delete;+ GetIfAddrs& operator=(GetIfAddrs&) = delete;++ template <typename Function>+ void withIfAddrs(Function f)+ {+ if (adapter_addrs)+ f(*adapter_addrs);+ }++private:+ IP_ADAPTER_ADDRESSES* adapter_addrs;+ IP_ADAPTER_ADDRESSES* adapter;+};++} // namespace detail++struct ScanIpIfAddrs+{+ // Scan active network interfaces and return corresponding addresses+ // for all ip-based interfaces.+ std::vector<::asio::ip::address> operator()()+ {+ std::vector<::asio::ip::address> addrs;++ detail::GetIfAddrs getIfAddrs;+ getIfAddrs.withIfAddrs([&addrs](const IP_ADAPTER_ADDRESSES& interfaces) {+ const IP_ADAPTER_ADDRESSES* networkInterface;+ for (networkInterface = &interfaces; networkInterface;+ networkInterface = networkInterface->Next)+ {+ for (IP_ADAPTER_UNICAST_ADDRESS* address = networkInterface->FirstUnicastAddress;+ NULL != address; address = address->Next)+ {+ auto family = address->Address.lpSockaddr->sa_family;+ if (AF_INET == family)+ {+ // IPv4+ SOCKADDR_IN* addr4 =+ reinterpret_cast<SOCKADDR_IN*>(address->Address.lpSockaddr);+ auto bytes = reinterpret_cast<const char*>(&addr4->sin_addr);+ addrs.emplace_back(asio::makeAddress<::asio::ip::address_v4>(bytes));+ }+ else if (AF_INET6 == family)+ {+ SOCKADDR_IN6* addr6 =+ reinterpret_cast<SOCKADDR_IN6*>(address->Address.lpSockaddr);+ auto bytes = reinterpret_cast<const char*>(&addr6->sin6_addr);+ addrs.emplace_back(asio::makeAddress<::asio::ip::address_v6>(bytes));+ }+ }+ }+ });+ return addrs;+ }+};++} // namespace windows+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/windows/ThreadFactory.hpp view
@@ -0,0 +1,52 @@+/* Copyright 2021, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <processthreadsapi.h>+#include <thread>+#include <utility>++namespace ableton+{+namespace platforms+{+namespace windows+{++struct ThreadFactory+{+ template <typename Callable, typename... Args>+ static std::thread makeThread(std::string name, Callable&& f, Args&&... args)+ {+ return std::thread(+ [](std::string name, Callable&& f, Args&&... args) {+ assert(name.length() < 20);+ wchar_t nativeName[20];+ mbstowcs(nativeName, name.c_str(), name.length() + 1);+ SetThreadDescription(GetCurrentThread(), nativeName);+ f(args...);+ },+ std::move(name), std::forward<Callable>(f), std::forward<Args>(args)...);+ }+};++} // namespace windows+} // namespace platforms+} // namespace ableton
+ link/include/ableton/platforms/windows/Windows.hpp view
@@ -0,0 +1,32 @@+/* Copyright 2020, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++// ntohll and htonll are not defined for MinGW++#ifdef __MINGW32__+#if __BIG_ENDIAN__+#define htonll(x) (x)+#define ntohll(x) (x)+#else+#define htonll(x) (((uint64_t)htonl((x)&0xFFFFFFFF) << 32) | htonl((x) >> 32))+#define ntohll(x) (((uint64_t)ntohl((x)&0xFFFFFFFF) << 32) | ntohl((x) >> 32))+#endif+#endif
+ link/include/ableton/test/CatchWrapper.hpp view
@@ -0,0 +1,42 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++/*!+ * \brief Wrapper file for Catch library+ *+ * This file includes the Catch header for Link, and also disables some compiler warnings+ * which are specific to that library.+ */++#if defined(_MSC_VER)+#pragma warning(push, 0)+#pragma warning(disable : 4242)+#pragma warning(disable : 4244)+#pragma warning(disable : 4668)+#pragma warning(disable : 4702)+#pragma warning(disable : 5220)+#endif++#include <catch.hpp>++#if defined(_MSC_VER)+#pragma warning(pop)+#endif
+ link/include/ableton/test/serial_io/Context.hpp view
@@ -0,0 +1,109 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/test/serial_io/SchedulerTree.hpp>+#include <ableton/test/serial_io/Timer.hpp>+#include <ableton/util/Log.hpp>+#include <chrono>+#include <memory>++namespace ableton+{+namespace test+{+namespace serial_io+{++class Context+{+public:+ Context(const SchedulerTree::TimePoint& now,+ const std::vector<::asio::ip::address>& ifAddrs,+ std::shared_ptr<SchedulerTree> pScheduler)+ : mNow(now)+ , mIfAddrs(ifAddrs)+ , mpScheduler(std::move(pScheduler))+ , mNextTimerId(0)+ {+ }++ ~Context()+ {+ if (mpScheduler != nullptr)+ {+ // Finish any pending tasks before shutting down+ mpScheduler->run();+ }+ }++ Context(const Context&) = delete;+ Context& operator=(const Context&) = delete;++ Context(Context&& rhs)+ : mNow(rhs.mNow)+ , mIfAddrs(rhs.mIfAddrs)+ , mpScheduler(std::move(rhs.mpScheduler))+ , mLog(std::move(rhs.mLog))+ , mNextTimerId(rhs.mNextTimerId)+ {+ }++ void stop()+ {+ }++ template <typename Handler>+ void async(Handler handler)+ {+ mpScheduler->async(std::move(handler));+ }++ using Timer = serial_io::Timer;++ Timer makeTimer()+ {+ return {mNextTimerId++, mNow, mpScheduler};+ }++ using Log = util::NullLog;++ Log& log()+ {+ return mLog;+ }++ std::vector<::asio::ip::address> scanNetworkInterfaces()+ {+ return mIfAddrs;+ }++private:+ const SchedulerTree::TimePoint& mNow;+ const std::vector<::asio::ip::address>& mIfAddrs;+ std::shared_ptr<SchedulerTree> mpScheduler;+ Log mLog;+ SchedulerTree::TimerId mNextTimerId;+};++} // namespace serial_io+} // namespace test+} // namespace ableton
+ link/include/ableton/test/serial_io/Fixture.hpp view
@@ -0,0 +1,92 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/platforms/asio/AsioWrapper.hpp>+#include <ableton/test/serial_io/Context.hpp>+#include <chrono>+#include <memory>++namespace ableton+{+namespace test+{+namespace serial_io+{++class Fixture+{+public:+ Fixture()+ : mpScheduler(std::make_shared<SchedulerTree>())+ , mNow(std::chrono::milliseconds{123456789})+ {+ }++ ~Fixture()+ {+ flush();+ }++ Fixture(const Fixture&) = delete;+ Fixture& operator=(const Fixture&) = delete;+ Fixture(Fixture&&) = delete;+ Fixture& operator=(Fixture&&) = delete;++ void setNetworkInterfaces(std::vector<::asio::ip::address> ifAddrs)+ {+ mIfAddrs = std::move(ifAddrs);+ }++ Context makeIoContext()+ {+ return {mNow, mIfAddrs, mpScheduler};+ }++ void flush()+ {+ mpScheduler->run();+ }++ template <typename T, typename Rep>+ void advanceTime(std::chrono::duration<T, Rep> duration)+ {+ const auto target = mNow + duration;+ mpScheduler->run();+ auto nextTimer = mpScheduler->nextTimerExpiration();+ while (nextTimer <= target)+ {+ mNow = nextTimer;+ mpScheduler->triggerTimersUntil(mNow);+ mpScheduler->run();+ nextTimer = mpScheduler->nextTimerExpiration();+ }+ mNow = target;+ }++private:+ std::shared_ptr<SchedulerTree> mpScheduler;+ SchedulerTree::TimePoint mNow;+ std::vector<::asio::ip::address> mIfAddrs;+};++} // namespace serial_io+} // namespace test+} // namespace ableton
+ link/include/ableton/test/serial_io/SchedulerTree.hpp view
@@ -0,0 +1,104 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <chrono>+#include <functional>+#include <list>+#include <map>+#include <memory>++namespace ableton+{+namespace test+{+namespace serial_io+{++class SchedulerTree+{+public:+ using TimePoint = std::chrono::system_clock::time_point;+ using TimerId = std::size_t;+ using TimerErrorCode = int;++ void run();++ std::shared_ptr<SchedulerTree> makeChild();++ template <typename Handler>+ void async(Handler handler)+ {+ mPendingHandlers.push_back(std::move(handler));+ }++ template <typename Handler>+ void setTimer(const TimerId timerId, const TimePoint expiration, Handler handler)+ {+ using namespace std;+ mTimers[make_pair(std::move(expiration), timerId)] = std::move(handler);+ }++ void cancelTimer(const TimerId timerId);++ // returns the time that the next timer in the subtree expires+ TimePoint nextTimerExpiration();++ // triggers all timers in the subtree that expire at time t or before+ void triggerTimersUntil(const TimePoint t);++private:+ // returns true if some work was done, false if there was none to do+ bool handlePending();++ // returns the time that the next timer from this node expires+ TimePoint nextOwnTimerExpiration();++ // Traversal function over children that cleans up children that+ // have been destroyed.+ template <typename Fn>+ void withChildren(Fn fn)+ {+ auto it = begin(mChildren);+ while (it != end(mChildren))+ {+ const auto childIt = it++;+ auto pChild = childIt->lock();+ if (pChild)+ {+ fn(*pChild);+ }+ else+ {+ mChildren.erase(childIt);+ }+ }+ }++ using TimerHandler = std::function<void(TimerErrorCode)>;+ using TimerMap = std::map<std::pair<TimePoint, TimerId>, TimerHandler>;+ TimerMap mTimers;+ std::list<std::function<void()>> mPendingHandlers;+ std::list<std::weak_ptr<SchedulerTree>> mChildren;+};++} // namespace serial_io+} // namespace test+} // namespace ableton
+ link/include/ableton/test/serial_io/Timer.hpp view
@@ -0,0 +1,110 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/test/serial_io/SchedulerTree.hpp>++namespace ableton+{+namespace test+{+namespace serial_io+{++struct Timer+{+ using ErrorCode = SchedulerTree::TimerErrorCode;+ using TimePoint = SchedulerTree::TimePoint;++ Timer(const SchedulerTree::TimerId timerId,+ const TimePoint& now,+ std::shared_ptr<SchedulerTree> pScheduler)+ : mId(timerId)+ , mNow(now)+ , mpScheduler(std::move(pScheduler))+ {+ }++ ~Timer()+ {+ if (!mbMovedFrom)+ {+ cancel();+ }+ }++ Timer(const Timer&) = delete;++ Timer(Timer&& rhs)+ : mId(rhs.mId)+ , mNow(rhs.mNow)+ , mExpiration(std::move(rhs.mExpiration))+ , mpScheduler(std::move(rhs.mpScheduler))+ {+ rhs.mbMovedFrom = true;+ }++ void expires_at(const TimePoint t)+ {+ if (t < mNow)+ {+ throw std::runtime_error("Setting timer in the past");+ }+ else+ {+ cancel();+ mExpiration = t;+ }+ }++ template <typename T, typename Rep>+ void expires_from_now(std::chrono::duration<T, Rep> duration)+ {+ expires_at(mNow + duration);+ }++ void cancel()+ {+ auto pScheduler = mpScheduler.lock();+ pScheduler->cancelTimer(mId);+ }++ template <typename Handler>+ void async_wait(Handler handler)+ {+ auto pScheduler = mpScheduler.lock();+ pScheduler->setTimer(mId, mExpiration, std::move(handler));+ }++ TimePoint now() const+ {+ return mNow;+ }++ const SchedulerTree::TimerId mId;+ const TimePoint& mNow;+ TimePoint mExpiration;+ std::weak_ptr<SchedulerTree> mpScheduler;+ bool mbMovedFrom = false;+};++} // namespace serial_io+} // namespace test+} // namespace ableton
+ link/include/ableton/util/Injected.hpp view
@@ -0,0 +1,254 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <memory>++namespace ableton+{+namespace util+{++// Utility type for aiding in dependency injection.++// Base template and implementation for injected valued+template <typename T>+struct Injected+{+ using type = T;++ Injected() = default;++ explicit Injected(T t)+ : val(std::move(t))+ {+ }++ Injected(const Injected&) = default;+ Injected& operator=(const Injected&) = default;++ Injected(Injected&& rhs)+ : val(std::move(rhs.val))+ {+ }++ Injected& operator=(Injected&& rhs)+ {+ val = std::move(rhs.val);+ return *this;+ }++ T* operator->()+ {+ return &val;+ }++ const T* operator->() const+ {+ return &val;+ }++ T& operator*()+ {+ return val;+ }++ const T& operator*() const+ {+ return val;+ }++ T val;+};++// Utility function for injecting values+template <typename T>+Injected<T> injectVal(T t)+{+ return Injected<T>(std::move(t));+}++// Specialization for injected references+template <typename T>+struct Injected<T&>+{+ using type = T;++ explicit Injected(T& t)+ : ref(std::ref(t))+ {+ }++ Injected(const Injected&) = default;+ Injected& operator=(const Injected&) = default;++ Injected(Injected&& rhs)+ : ref(std::move(rhs.ref))+ {+ }++ Injected& operator=(Injected&& rhs)+ {+ ref = std::move(rhs.ref);+ return *this;+ }++ T* operator->()+ {+ return &ref.get();+ }++ const T* operator->() const+ {+ return &ref.get();+ }++ T& operator*()+ {+ return ref;+ }++ const T& operator*() const+ {+ return ref;+ }++ std::reference_wrapper<T> ref;+};++// Utility function for injecting references+template <typename T>+Injected<T&> injectRef(T& t)+{+ return Injected<T&>(t);+}++// Specialization for injected shared_ptr+template <typename T>+struct Injected<std::shared_ptr<T>>+{+ using type = T;++ explicit Injected(std::shared_ptr<T> pT)+ : shared(std::move(pT))+ {+ }++ Injected(const Injected&) = default;+ Injected& operator=(const Injected&) = default;++ Injected(Injected&& rhs)+ : shared(std::move(rhs.shared))+ {+ }++ Injected& operator=(Injected&& rhs)+ {+ shared = std::move(rhs.shared);+ return *this;+ }++ T* operator->()+ {+ return shared.get();+ }++ const T* operator->() const+ {+ return shared.get();+ }++ T& operator*()+ {+ return *shared;+ }++ const T& operator*() const+ {+ return *shared;+ }++ std::shared_ptr<T> shared;+};++// Utility function for injected shared_ptr+template <typename T>+Injected<std::shared_ptr<T>> injectShared(std::shared_ptr<T> shared)+{+ return Injected<std::shared_ptr<T>>(std::move(shared));+}++// Specialization for injected unique_ptr+template <typename T>+struct Injected<std::unique_ptr<T>>+{+ using type = T;++ explicit Injected(std::unique_ptr<T> pT)+ : unique(std::move(pT))+ {+ }++ Injected(const Injected&) = default;+ Injected& operator=(const Injected&) = default;++ Injected(Injected&& rhs)+ : unique(std::move(rhs.unique))+ {+ }++ Injected& operator=(Injected&& rhs)+ {+ unique = std::move(rhs.unique);+ return *this;+ }++ T* operator->()+ {+ return unique.get();+ }++ const T* operator->() const+ {+ return unique.get();+ }++ T& operator*()+ {+ return *unique;+ }++ const T& operator*() const+ {+ return *unique;+ }++ std::unique_ptr<T> unique;+};++// Utility function for injected unique_ptr+template <typename T>+Injected<std::unique_ptr<T>> injectUnique(std::unique_ptr<T> unique)+{+ return Injected<std::unique_ptr<T>>(std::move(unique));+}++} // namespace util+} // namespace ableton
+ link/include/ableton/util/Log.hpp view
@@ -0,0 +1,176 @@+// Copyright: 2014, Ableton AG, Berlin, all rights reserved++#pragma once++#include <ableton/util/Injected.hpp>+#include <iostream>+#include <string>++namespace ableton+{+namespace util+{++// Null object for the Log concept+struct NullLog+{+ template <typename T>+ friend const NullLog& operator<<(const NullLog& log, const T&)+ {+ return log;+ }++ friend const NullLog& debug(const NullLog& log)+ {+ return log;+ }++ friend const NullLog& info(const NullLog& log)+ {+ return log;+ }++ friend const NullLog& warning(const NullLog& log)+ {+ return log;+ }++ friend const NullLog& error(const NullLog& log)+ {+ return log;+ }++ friend NullLog channel(const NullLog&, std::string)+ {+ return {};+ }+};++// std streams-based log+struct StdLog+{+ StdLog(std::string channelName = "")+ : mChannelName(std::move(channelName))+ {+ }++ // Stream type used by std log to prepend the channel name to log messages+ struct StdLogStream+ {+ StdLogStream(std::ostream& ioStream, const std::string& channelName)+ : mpIoStream(&ioStream)+ , mChannelName(channelName)+ {+ ioStream << "[" << mChannelName << "] ";+ }++ StdLogStream(StdLogStream&& rhs)+ : mpIoStream(rhs.mpIoStream)+ , mChannelName(rhs.mChannelName)+ {+ rhs.mpIoStream = nullptr;+ }++ ~StdLogStream()+ {+ if (mpIoStream)+ {+ (*mpIoStream) << "\n";+ }+ }++ template <typename T>+ std::ostream& operator<<(const T& rhs)+ {+ (*mpIoStream) << rhs;+ return *mpIoStream;+ }++ std::ostream* mpIoStream;+ const std::string& mChannelName;+ };++ friend StdLogStream debug(const StdLog& log)+ {+ return {std::clog, log.mChannelName};+ }++ friend StdLogStream info(const StdLog& log)+ {+ return {std::clog, log.mChannelName};+ }++ friend StdLogStream warning(const StdLog& log)+ {+ return {std::clog, log.mChannelName};+ }++ friend StdLogStream error(const StdLog& log)+ {+ return {std::cerr, log.mChannelName};+ }++ friend StdLog channel(const StdLog& log, const std::string& channelName)+ {+ auto compositeName =+ log.mChannelName.empty() ? channelName : log.mChannelName + "::" + channelName;+ return {std::move(compositeName)};+ }++ std::string mChannelName;+};++// Log adapter that adds timestamps+template <typename Log>+struct Timestamped+{+ using InnerLog = typename util::Injected<Log>::type;++ Timestamped() = default;++ Timestamped(util::Injected<Log> log)+ : mLog(std::move(log))+ {+ }++ util::Injected<Log> mLog;++ friend decltype(debug(std::declval<InnerLog>())) debug(const Timestamped& log)+ {+ return log.logTimestamp(debug(*log.mLog));+ }++ friend decltype(info(std::declval<InnerLog>())) info(const Timestamped& log)+ {+ return log.logTimestamp(info(*log.mLog));+ }++ friend decltype(warning(std::declval<InnerLog>())) warning(const Timestamped& log)+ {+ return log.logTimestamp(warning(*log.mLog));+ }++ friend decltype(error(std::declval<InnerLog>())) error(const Timestamped& log)+ {+ return log.logTimestamp(error(*log.mLog));+ }++ friend Timestamped channel(const Timestamped& log, const std::string& channelName)+ {+ return {channel(*log.mLog, channelName)};+ }++ template <typename Stream>+ Stream logTimestamp(Stream&& streamRef) const+ {+ using namespace std::chrono;+ Stream stream = std::forward<Stream>(streamRef);+ stream << "|"+ << duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count()+ << "ms| ";+ return stream;+ }+};++} // namespace util+} // namespace ableton
+ link/include/ableton/util/SafeAsyncHandler.hpp view
@@ -0,0 +1,66 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <memory>++namespace ableton+{+namespace util+{++// A utility handler for passing to async functions that may call the+// handler past the lifetime of the wrapped delegate object.+// The need for this is particularly driven by boost::asio timer+// objects, which explicitly document that they may be called without+// an error code after they have been cancelled. This has led to+// several crashes. This handler wrapper implements a useful idiom for+// avoiding this problem.++template <typename Delegate>+struct SafeAsyncHandler+{+ SafeAsyncHandler(const std::shared_ptr<Delegate>& pDelegate)+ : mpDelegate(pDelegate)+ {+ }++ template <typename... T>+ void operator()(T&&... t) const+ {+ std::shared_ptr<Delegate> pDelegate = mpDelegate.lock();+ if (pDelegate)+ {+ (*pDelegate)(std::forward<T>(t)...);+ }+ }++ std::weak_ptr<Delegate> mpDelegate;+};++// Factory function for easily wrapping a shared_ptr to a handler+template <typename Delegate>+SafeAsyncHandler<Delegate> makeAsyncSafe(const std::shared_ptr<Delegate>& pDelegate)+{+ return {pDelegate};+}++} // namespace util+} // namespace ableton
+ link/include/ableton/util/SampleTiming.hpp view
@@ -0,0 +1,52 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <chrono>++namespace ableton+{+namespace util+{++/*! Utility type to convert between time and sample index given the+ * time at the beginning of a buffer and the sample rate.+ */+struct SampleTiming+{+ double sampleAtTime(std::chrono::microseconds time) const+ {+ using namespace std::chrono;+ return duration_cast<duration<double>>(time - mBufferBegin).count() * mSampleRate;+ }++ std::chrono::microseconds timeAtSample(const double sample) const+ {+ using namespace std::chrono;+ return mBufferBegin+ + duration_cast<microseconds>(duration<double>{sample / mSampleRate});+ }++ std::chrono::microseconds mBufferBegin;+ double mSampleRate;+};++} // namespace util+} // namespace ableton
+ link/include/ableton/util/test/IoService.hpp view
@@ -0,0 +1,114 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <ableton/util/test/Timer.hpp>++namespace ableton+{+namespace util+{+namespace test+{++struct IoService+{+ // Wrapper around the internal util::test::Timer in the list+ struct Timer+ {+ using ErrorCode = test::Timer::ErrorCode;+ using TimePoint = test::Timer::TimePoint;++ Timer(util::test::Timer* pTimer)+ : mpTimer(pTimer)+ {+ }++ void expires_at(std::chrono::system_clock::time_point t)+ {+ mpTimer->expires_at(t);+ }++ template <typename T, typename Rep>+ void expires_from_now(std::chrono::duration<T, Rep> duration)+ {+ mpTimer->expires_from_now(duration);+ }++ ErrorCode cancel()+ {+ return mpTimer->cancel();+ }++ template <typename Handler>+ void async_wait(Handler handler)+ {+ mpTimer->async_wait(std::move(handler));+ }++ TimePoint now() const+ {+ return mpTimer->now();+ }++ util::test::Timer* mpTimer;+ };++ IoService() = default;++ Timer makeTimer()+ {+ mTimers.emplace_back();+ return Timer{&mTimers.back()};+ }++ template <typename Handler>+ void post(Handler handler)+ {+ mHandlers.emplace_back(std::move(handler));+ }++ template <typename T, typename Rep>+ void advance(std::chrono::duration<T, Rep> duration)+ {+ runHandlers();++ for (auto& timer : mTimers)+ {+ timer.advance(duration);+ }+ }++ void runHandlers()+ {+ for (auto& handler : mHandlers)+ {+ handler();+ }+ mHandlers.clear();+ }++ std::vector<std::function<void()>> mHandlers;+ std::vector<util::test::Timer> mTimers;+};++} // namespace test+} // namespace util+} // namespace ableton
+ link/include/ableton/util/test/Timer.hpp view
@@ -0,0 +1,96 @@+/* Copyright 2016, Ableton AG, Berlin. All rights reserved.+ *+ * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 2 of the License, or+ * (at your option) any later version.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ * You should have received a copy of the GNU General Public License+ * along with this program. If not, see <http://www.gnu.org/licenses/>.+ *+ * If you would like to incorporate Link into a proprietary software application,+ * please contact <link-devs@ableton.com>.+ */++#pragma once++#include <chrono>+#include <functional>++namespace ableton+{+namespace util+{+namespace test+{++struct Timer+{+ using ErrorCode = int;+ using TimePoint = std::chrono::system_clock::time_point;++ // Initialize timer with an arbitrary large value to simulate the+ // time_since_epoch of a real clock.+ Timer()+ : mNow{std::chrono::milliseconds{123456789}}+ {+ }++ void expires_at(std::chrono::system_clock::time_point t)+ {+ cancel();+ mFireAt = std::move(t);+ }++ template <typename T, typename Rep>+ void expires_from_now(std::chrono::duration<T, Rep> duration)+ {+ cancel();+ mFireAt = now() + duration;+ }++ ErrorCode cancel()+ {+ if (mHandler)+ {+ mHandler(1); // call existing handler with truthy error code+ }+ mHandler = nullptr;+ return 0;+ }++ template <typename Handler>+ void async_wait(Handler handler)+ {+ mHandler = [handler](ErrorCode ec) { handler(ec); };+ }++ std::chrono::system_clock::time_point now() const+ {+ return mNow;+ }++ template <typename T, typename Rep>+ void advance(std::chrono::duration<T, Rep> duration)+ {+ mNow += duration;+ if (mHandler && mFireAt < mNow)+ {+ mHandler(0);+ mHandler = nullptr;+ }+ }++ std::function<void(ErrorCode)> mHandler;+ std::chrono::system_clock::time_point mFireAt;+ std::chrono::system_clock::time_point mNow;+};++} // namespace test+} // namespace util+} // namespace ableton
+ link/modules/asio-standalone/asio/include/asio.hpp view
@@ -0,0 +1,182 @@+//+// asio.hpp+// ~~~~~~~~+//+// Copyright (c) 2003-2020 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_HPP+#define ASIO_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/associated_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/async_result.hpp"+#include "asio/awaitable.hpp"+#include "asio/basic_datagram_socket.hpp"+#include "asio/basic_deadline_timer.hpp"+#include "asio/basic_io_object.hpp"+#include "asio/basic_raw_socket.hpp"+#include "asio/basic_seq_packet_socket.hpp"+#include "asio/basic_serial_port.hpp"+#include "asio/basic_signal_set.hpp"+#include "asio/basic_socket.hpp"+#include "asio/basic_socket_acceptor.hpp"+#include "asio/basic_socket_iostream.hpp"+#include "asio/basic_socket_streambuf.hpp"+#include "asio/basic_stream_socket.hpp"+#include "asio/basic_streambuf.hpp"+#include "asio/basic_waitable_timer.hpp"+#include "asio/bind_executor.hpp"+#include "asio/buffer.hpp"+#include "asio/buffered_read_stream_fwd.hpp"+#include "asio/buffered_read_stream.hpp"+#include "asio/buffered_stream_fwd.hpp"+#include "asio/buffered_stream.hpp"+#include "asio/buffered_write_stream_fwd.hpp"+#include "asio/buffered_write_stream.hpp"+#include "asio/buffers_iterator.hpp"+#include "asio/co_spawn.hpp"+#include "asio/completion_condition.hpp"+#include "asio/compose.hpp"+#include "asio/connect.hpp"+#include "asio/coroutine.hpp"+#include "asio/deadline_timer.hpp"+#include "asio/defer.hpp"+#include "asio/detached.hpp"+#include "asio/dispatch.hpp"+#include "asio/error.hpp"+#include "asio/error_code.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/bulk_execute.hpp"+#include "asio/execution/bulk_guarantee.hpp"+#include "asio/execution/connect.hpp"+#include "asio/execution/context.hpp"+#include "asio/execution/context_as.hpp"+#include "asio/execution/execute.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/operation_state.hpp"+#include "asio/execution/outstanding_work.hpp"+#include "asio/execution/prefer_only.hpp"+#include "asio/execution/receiver.hpp"+#include "asio/execution/receiver_invocation_error.hpp"+#include "asio/execution/relationship.hpp"+#include "asio/execution/schedule.hpp"+#include "asio/execution/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/execution/set_done.hpp"+#include "asio/execution/set_error.hpp"+#include "asio/execution/set_value.hpp"+#include "asio/execution/start.hpp"+#include "asio/execution_context.hpp"+#include "asio/executor.hpp"+#include "asio/executor_work_guard.hpp"+#include "asio/generic/basic_endpoint.hpp"+#include "asio/generic/datagram_protocol.hpp"+#include "asio/generic/raw_protocol.hpp"+#include "asio/generic/seq_packet_protocol.hpp"+#include "asio/generic/stream_protocol.hpp"+#include "asio/handler_alloc_hook.hpp"+#include "asio/handler_continuation_hook.hpp"+#include "asio/handler_invoke_hook.hpp"+#include "asio/high_resolution_timer.hpp"+#include "asio/io_context.hpp"+#include "asio/io_context_strand.hpp"+#include "asio/io_service.hpp"+#include "asio/io_service_strand.hpp"+#include "asio/ip/address.hpp"+#include "asio/ip/address_v4.hpp"+#include "asio/ip/address_v4_iterator.hpp"+#include "asio/ip/address_v4_range.hpp"+#include "asio/ip/address_v6.hpp"+#include "asio/ip/address_v6_iterator.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/basic_endpoint.hpp"+#include "asio/ip/basic_resolver.hpp"+#include "asio/ip/basic_resolver_entry.hpp"+#include "asio/ip/basic_resolver_iterator.hpp"+#include "asio/ip/basic_resolver_query.hpp"+#include "asio/ip/host_name.hpp"+#include "asio/ip/icmp.hpp"+#include "asio/ip/multicast.hpp"+#include "asio/ip/resolver_base.hpp"+#include "asio/ip/resolver_query_base.hpp"+#include "asio/ip/tcp.hpp"+#include "asio/ip/udp.hpp"+#include "asio/ip/unicast.hpp"+#include "asio/ip/v6_only.hpp"+#include "asio/is_applicable_property.hpp"+#include "asio/is_executor.hpp"+#include "asio/is_read_buffered.hpp"+#include "asio/is_write_buffered.hpp"+#include "asio/local/basic_endpoint.hpp"+#include "asio/local/connect_pair.hpp"+#include "asio/local/datagram_protocol.hpp"+#include "asio/local/stream_protocol.hpp"+#include "asio/multiple_exceptions.hpp"+#include "asio/packaged_task.hpp"+#include "asio/placeholders.hpp"+#include "asio/posix/basic_descriptor.hpp"+#include "asio/posix/basic_stream_descriptor.hpp"+#include "asio/posix/descriptor.hpp"+#include "asio/posix/descriptor_base.hpp"+#include "asio/posix/stream_descriptor.hpp"+#include "asio/post.hpp"+#include "asio/prefer.hpp"+#include "asio/query.hpp"+#include "asio/read.hpp"+#include "asio/read_at.hpp"+#include "asio/read_until.hpp"+#include "asio/redirect_error.hpp"+#include "asio/require.hpp"+#include "asio/require_concept.hpp"+#include "asio/serial_port.hpp"+#include "asio/serial_port_base.hpp"+#include "asio/signal_set.hpp"+#include "asio/socket_base.hpp"+#include "asio/static_thread_pool.hpp"+#include "asio/steady_timer.hpp"+#include "asio/strand.hpp"+#include "asio/streambuf.hpp"+#include "asio/system_context.hpp"+#include "asio/system_error.hpp"+#include "asio/system_executor.hpp"+#include "asio/system_timer.hpp"+#include "asio/this_coro.hpp"+#include "asio/thread.hpp"+#include "asio/thread_pool.hpp"+#include "asio/time_traits.hpp"+#include "asio/use_awaitable.hpp"+#include "asio/use_future.hpp"+#include "asio/uses_executor.hpp"+#include "asio/version.hpp"+#include "asio/wait_traits.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_stream_handle.hpp"+#include "asio/windows/object_handle.hpp"+#include "asio/windows/overlapped_handle.hpp"+#include "asio/windows/overlapped_ptr.hpp"+#include "asio/windows/random_access_handle.hpp"+#include "asio/windows/stream_handle.hpp"+#include "asio/write.hpp"+#include "asio/write_at.hpp"++#endif // ASIO_HPP
+ link/modules/asio-standalone/asio/include/asio/any_io_executor.hpp view
@@ -0,0 +1,71 @@+//+// any_io_executor.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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+ */+#if defined(GENERATING_DOCUMENTATION)+typedef execution::any_executor<...> any_io_executor;+#else // 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>+ > any_io_executor;+#endif // defined(GENERATING_DOCUMENTATION)++#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_ANY_IO_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/associated_allocator.hpp view
@@ -0,0 +1,125 @@+//+// associated_allocator.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_ALLOCATOR_HPP+#define ASIO_ASSOCIATED_ALLOCATOR_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 {+namespace detail {++template <typename T, typename E, typename = void>+struct associated_allocator_impl+{+ typedef E type;++ static type get(const T&, const E& e) ASIO_NOEXCEPT+ {+ return e;+ }+};++template <typename T, typename E>+struct associated_allocator_impl<T, E,+ typename void_type<typename T::allocator_type>::type>+{+ typedef typename T::allocator_type type;++ static type get(const T& t, const E&) ASIO_NOEXCEPT+ {+ return t.get_allocator();+ }+};++} // namespace detail++/// Traits type used to obtain the allocator 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+ * Allocator shall be a type meeting the Allocator requirements.+ *+ * Specialisations shall meet the following requirements, where @c t is a const+ * reference to an object of type @c T, and @c a is an object of type @c+ * Allocator.+ *+ * @li Provide a nested typedef @c type that identifies a type meeting the+ * Allocator requirements.+ *+ * @li Provide a noexcept static member function named @c get, callable as @c+ * get(t) and with return type @c type.+ *+ * @li Provide a noexcept static member function named @c get, callable as @c+ * get(t,a) and with return type @c type.+ */+template <typename T, typename Allocator = std::allocator<void> >+struct associated_allocator+{+ /// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>.+ /// Otherwise @c Allocator.+#if defined(GENERATING_DOCUMENTATION)+ typedef see_below type;+#else // defined(GENERATING_DOCUMENTATION)+ typedef typename detail::associated_allocator_impl<T, Allocator>::type type;+#endif // defined(GENERATING_DOCUMENTATION)++ /// If @c T has a nested type @c allocator_type, returns+ /// <tt>t.get_allocator()</tt>. Otherwise returns @c a.+ static type get(const T& t,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return detail::associated_allocator_impl<T, Allocator>::get(t, a);+ }+};++/// Helper function to obtain an object's associated allocator.+/**+ * @returns <tt>associated_allocator<T>::get(t)</tt>+ */+template <typename T>+inline typename associated_allocator<T>::type+get_associated_allocator(const T& t) ASIO_NOEXCEPT+{+ return associated_allocator<T>::get(t);+}++/// Helper function to obtain an object's associated allocator.+/**+ * @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt>+ */+template <typename T, typename Allocator>+inline typename associated_allocator<T, Allocator>::type+get_associated_allocator(const T& t, const Allocator& a) ASIO_NOEXCEPT+{+ return associated_allocator<T, Allocator>::get(t, a);+}++#if defined(ASIO_HAS_ALIAS_TEMPLATES)++template <typename T, typename Allocator = std::allocator<void> >+using associated_allocator_t+ = typename associated_allocator<T, Allocator>::type;++#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_ASSOCIATED_ALLOCATOR_HPP
+ link/modules/asio-standalone/asio/include/asio/associated_executor.hpp view
@@ -0,0 +1,166 @@+//+// associated_executor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTOR_HPP+#define ASIO_ASSOCIATED_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/execution/executor.hpp"+#include "asio/is_executor.hpp"+#include "asio/system_executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename T, typename E, typename = void>+struct associated_executor_impl+{+ typedef void asio_associated_executor_is_unspecialised;++ typedef E type;++ static type get(const T&, const E& e = E()) ASIO_NOEXCEPT+ {+ return e;+ }+};++template <typename T, typename E>+struct associated_executor_impl<T, E,+ typename void_type<typename T::executor_type>::type>+{+ typedef typename T::executor_type type;++ static type get(const T& t, const E& = E()) ASIO_NOEXCEPT+ {+ return t.get_executor();+ }+};++} // namespace detail++/// Traits type used to obtain the 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.+ *+ * @li Provide a noexcept static member function named @c get, callable as @c+ * get(t,e) and with return type @c type.+ */+template <typename T, typename Executor = system_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>.+ /// Otherwise @c Executor.+ typedef see_below type;++ /// If @c T has a nested type @c executor_type, returns+ /// <tt>t.get_executor()</tt>. Otherwise returns @c ex.+ static type get(const T& t,+ const Executor& ex = Executor()) ASIO_NOEXCEPT;+#endif // defined(GENERATING_DOCUMENTATION)+};++/// Helper function to obtain an object's associated executor.+/**+ * @returns <tt>associated_executor<T>::get(t)</tt>+ */+template <typename T>+inline typename associated_executor<T>::type+get_associated_executor(const T& t) ASIO_NOEXCEPT+{+ return associated_executor<T>::get(t);+}++/// Helper function to obtain an object's associated executor.+/**+ * @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt>+ */+template <typename T, typename Executor>+inline typename associated_executor<T, Executor>::type+get_associated_executor(const T& t, const Executor& ex,+ typename enable_if<+ is_executor<Executor>::value || execution::is_executor<Executor>::value+ >::type* = 0) ASIO_NOEXCEPT+{+ return associated_executor<T, Executor>::get(t, ex);+}++/// Helper function to obtain an object's associated executor.+/**+ * @returns <tt>associated_executor<T, typename+ * ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt>+ */+template <typename T, typename ExecutionContext>+inline typename associated_executor<T,+ typename ExecutionContext::executor_type>::type+get_associated_executor(const T& t, ExecutionContext& ctx,+ typename enable_if<is_convertible<ExecutionContext&,+ execution_context&>::value>::type* = 0) ASIO_NOEXCEPT+{+ return associated_executor<T,+ typename ExecutionContext::executor_type>::get(t, ctx.get_executor());+}++#if defined(ASIO_HAS_ALIAS_TEMPLATES)++template <typename T, typename Executor = system_executor>+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,+ typename enable_if<+ is_same<+ typename associated_executor<T,+ E>::asio_associated_executor_is_unspecialised,+ void+ >::value+ >::type>+{+ typedef void asio_associated_executor_is_unspecialised;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_ASSOCIATED_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/async_result.hpp view
@@ -0,0 +1,582 @@+//+// async_result.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_ASYNC_RESULT_HPP+#define ASIO_ASYNC_RESULT_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/variadic_templates.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(ASIO_HAS_CONCEPTS) \+ && defined(ASIO_HAS_VARIADIC_TEMPLATES) \+ && defined(ASIO_HAS_DECLTYPE)++namespace detail {++template <typename T>+struct is_completion_signature : false_type+{+};++template <typename R, typename... Args>+struct is_completion_signature<R(Args...)> : true_type+{+};++template <typename T, typename... Args>+ASIO_CONCEPT callable_with = requires(T t, Args&&... args)+{+ t(static_cast<Args&&>(args)...);+};++template <typename T, typename Signature>+struct is_completion_handler_for : false_type+{+};++template <typename T, typename R, typename... Args>+struct is_completion_handler_for<T, R(Args...)>+ : integral_constant<bool, (callable_with<T, Args...>)>+{+};++} // namespace detail++template <typename T>+ASIO_CONCEPT completion_signature =+ detail::is_completion_signature<T>::value;++#define ASIO_COMPLETION_SIGNATURE \+ ::asio::completion_signature++template <typename T, typename Signature>+ASIO_CONCEPT completion_handler_for =+ detail::is_completion_signature<Signature>::value+ && detail::is_completion_handler_for<T, Signature>::value;++#define ASIO_COMPLETION_HANDLER_FOR(s) \+ ::asio::completion_handler_for<s>++#else // defined(ASIO_HAS_CONCEPTS)+ // && defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // && defined(ASIO_HAS_DECLTYPE)++#define ASIO_COMPLETION_SIGNATURE typename+#define ASIO_COMPLETION_HANDLER_FOR(s) typename++#endif // defined(ASIO_HAS_CONCEPTS)+ // && defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // && defined(ASIO_HAS_DECLTYPE)++/// An interface for customising the behaviour of an initiating function.+/**+ * The async_result traits class is used for determining:+ *+ * @li the concrete completion handler type to be called at the end of the+ * asynchronous operation;+ *+ * @li the initiating function return type; and+ *+ * @li how the return value of the initiating function is obtained.+ *+ * The trait allows the handler and return types to be determined at the point+ * where the specific completion handler signature is known.+ *+ * This template may be specialised for user-defined completion token types.+ * The primary template assumes that the CompletionToken is the completion+ * handler.+ */+template <typename CompletionToken, ASIO_COMPLETION_SIGNATURE Signature>+class async_result+{+public:+ /// The concrete completion handler type for the specific signature.+ typedef CompletionToken completion_handler_type;++ /// The return type of the initiating function.+ typedef void return_type;++ /// Construct an async result from a given handler.+ /**+ * When using a specalised async_result, the constructor has an opportunity+ * to initialise some state associated with the completion handler, which is+ * then returned from the initiating function.+ */+ explicit async_result(completion_handler_type& h)+ {+ (void)h;+ }++ /// Obtain the value to be returned from the initiating function.+ return_type get()+ {+ }++#if defined(GENERATING_DOCUMENTATION)++ /// Initiate the asynchronous operation that will produce the result, and+ /// obtain the value to be returned from the initiating function.+ template <typename Initiation, typename RawCompletionToken, typename... Args>+ static return_type initiate(+ ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_MOVE_ARG(RawCompletionToken) token,+ ASIO_MOVE_ARG(Args)... args);++#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Initiation,+ ASIO_COMPLETION_HANDLER_FOR(Signature) RawCompletionToken,+ typename... Args>+ static return_type initiate(+ ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_MOVE_ARG(RawCompletionToken) token,+ ASIO_MOVE_ARG(Args)... args)+ {+ ASIO_MOVE_CAST(Initiation)(initiation)(+ ASIO_MOVE_CAST(RawCompletionToken)(token),+ ASIO_MOVE_CAST(Args)(args)...);+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Initiation,+ ASIO_COMPLETION_HANDLER_FOR(Signature) RawCompletionToken>+ static return_type initiate(+ ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_MOVE_ARG(RawCompletionToken) token)+ {+ ASIO_MOVE_CAST(Initiation)(initiation)(+ ASIO_MOVE_CAST(RawCompletionToken)(token));+ }++#define ASIO_PRIVATE_INITIATE_DEF(n) \+ template <typename Initiation, \+ ASIO_COMPLETION_HANDLER_FOR(Signature) RawCompletionToken, \+ ASIO_VARIADIC_TPARAMS(n)> \+ static return_type initiate( \+ ASIO_MOVE_ARG(Initiation) initiation, \+ ASIO_MOVE_ARG(RawCompletionToken) token, \+ ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ ASIO_MOVE_CAST(Initiation)(initiation)( \+ ASIO_MOVE_CAST(RawCompletionToken)(token), \+ ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)+#undef ASIO_PRIVATE_INITIATE_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++private:+ async_result(const async_result&) ASIO_DELETED;+ async_result& operator=(const async_result&) ASIO_DELETED;+};++#if !defined(GENERATING_DOCUMENTATION)++template <ASIO_COMPLETION_SIGNATURE Signature>+class async_result<void, Signature>+{+ // Empty.+};++#endif // !defined(GENERATING_DOCUMENTATION)++/// Helper template to deduce the handler type from a CompletionToken, capture+/// a local copy of the handler, and then create an async_result for the+/// handler.+template <typename CompletionToken, ASIO_COMPLETION_SIGNATURE Signature>+struct async_completion+{+ /// The real handler type to be used for the asynchronous operation.+ typedef typename asio::async_result<+ typename decay<CompletionToken>::type,+ Signature>::completion_handler_type completion_handler_type;++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Constructor.+ /**+ * The constructor creates the concrete completion handler and makes the link+ * between the handler and the asynchronous result.+ */+ explicit async_completion(CompletionToken& token)+ : completion_handler(static_cast<typename conditional<+ is_same<CompletionToken, completion_handler_type>::value,+ completion_handler_type&, CompletionToken&&>::type>(token)),+ result(completion_handler)+ {+ }+#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ explicit async_completion(typename decay<CompletionToken>::type& token)+ : completion_handler(token),+ result(completion_handler)+ {+ }++ explicit async_completion(const typename decay<CompletionToken>::type& token)+ : completion_handler(token),+ result(completion_handler)+ {+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// A copy of, or reference to, a real handler object.+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ typename conditional<+ is_same<CompletionToken, completion_handler_type>::value,+ completion_handler_type&, completion_handler_type>::type completion_handler;+#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ completion_handler_type completion_handler;+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// The result of the asynchronous operation's initiating function.+ async_result<typename decay<CompletionToken>::type, Signature> result;+};++namespace detail {++template <typename CompletionToken, typename Signature>+struct async_result_helper+ : async_result<typename decay<CompletionToken>::type, Signature>+{+};++struct async_result_memfns_base+{+ void initiate();+};++template <typename T>+struct async_result_memfns_derived+ : T, async_result_memfns_base+{+};++template <typename T, T>+struct async_result_memfns_check+{+};++template <typename>+char (&async_result_initiate_memfn_helper(...))[2];++template <typename T>+char async_result_initiate_memfn_helper(+ async_result_memfns_check<+ void (async_result_memfns_base::*)(),+ &async_result_memfns_derived<T>::initiate>*);++template <typename CompletionToken, typename Signature>+struct async_result_has_initiate_memfn+ : integral_constant<bool, sizeof(async_result_initiate_memfn_helper<+ async_result<typename decay<CompletionToken>::type, Signature>+ >(0)) != 1>+{+};++} // namespace detail++#if defined(GENERATING_DOCUMENTATION)+# define ASIO_INITFN_RESULT_TYPE(ct, sig) \+ void_or_deduced+#elif defined(_MSC_VER) && (_MSC_VER < 1500)+# define ASIO_INITFN_RESULT_TYPE(ct, sig) \+ typename ::asio::detail::async_result_helper< \+ ct, sig>::return_type+#define ASIO_HANDLER_TYPE(ct, sig) \+ typename ::asio::detail::async_result_helper< \+ ct, sig>::completion_handler_type+#else+# define ASIO_INITFN_RESULT_TYPE(ct, sig) \+ typename ::asio::async_result< \+ typename ::asio::decay<ct>::type, sig>::return_type+#define ASIO_HANDLER_TYPE(ct, sig) \+ typename ::asio::async_result< \+ typename ::asio::decay<ct>::type, sig>::completion_handler_type+#endif++#if defined(GENERATION_DOCUMENTATION)+# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \+ auto+#elif defined(ASIO_HAS_RETURN_TYPE_DEDUCTION)+# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \+ auto+#else+# define ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \+ ASIO_INITFN_RESULT_TYPE(ct, sig)+#endif++#if defined(GENERATION_DOCUMENTATION)+# define ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \+ void_or_deduced+#elif defined(ASIO_HAS_DECLTYPE)+# define ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \+ decltype expr+#else+# define ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \+ ASIO_INITFN_RESULT_TYPE(ct, sig)+#endif++#if defined(GENERATING_DOCUMENTATION)++template <typename CompletionToken,+ completion_signature Signature,+ typename Initiation, typename... Args>+void_or_deduced async_initiate(+ ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken),+ ASIO_MOVE_ARG(Args)... args);++#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename CompletionToken,+ ASIO_COMPLETION_SIGNATURE Signature,+ typename Initiation, typename... Args>+inline typename enable_if<+ detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,+ ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature,+ (async_result<typename decay<CompletionToken>::type,+ Signature>::initiate(declval<ASIO_MOVE_ARG(Initiation)>(),+ declval<ASIO_MOVE_ARG(CompletionToken)>(),+ declval<ASIO_MOVE_ARG(Args)>()...)))>::type+async_initiate(ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,+ ASIO_MOVE_ARG(Args)... args)+{+ return async_result<typename decay<CompletionToken>::type,+ Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation),+ ASIO_MOVE_CAST(CompletionToken)(token),+ ASIO_MOVE_CAST(Args)(args)...);+}++template <typename CompletionToken,+ ASIO_COMPLETION_SIGNATURE Signature,+ typename Initiation, typename... Args>+inline typename enable_if<+ !detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,+ ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type+async_initiate(ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,+ ASIO_MOVE_ARG(Args)... args)+{+ async_completion<CompletionToken, Signature> completion(token);++ ASIO_MOVE_CAST(Initiation)(initiation)(+ ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken,+ Signature))(completion.completion_handler),+ ASIO_MOVE_CAST(Args)(args)...);++ return completion.result.get();+}++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename CompletionToken,+ ASIO_COMPLETION_SIGNATURE Signature,+ typename Initiation>+inline typename enable_if<+ detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,+ ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature,+ (async_result<typename decay<CompletionToken>::type,+ Signature>::initiate(declval<ASIO_MOVE_ARG(Initiation)>(),+ declval<ASIO_MOVE_ARG(CompletionToken)>())))>::type+async_initiate(ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token)+{+ return async_result<typename decay<CompletionToken>::type,+ Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation),+ ASIO_MOVE_CAST(CompletionToken)(token));+}++template <typename CompletionToken,+ ASIO_COMPLETION_SIGNATURE Signature,+ typename Initiation>+inline typename enable_if<+ !detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,+ ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type+async_initiate(ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token)+{+ async_completion<CompletionToken, Signature> completion(token);++ ASIO_MOVE_CAST(Initiation)(initiation)(+ ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken,+ Signature))(completion.completion_handler));++ return completion.result.get();+}++#define ASIO_PRIVATE_INITIATE_DEF(n) \+ template <typename CompletionToken, \+ ASIO_COMPLETION_SIGNATURE Signature, \+ typename Initiation, ASIO_VARIADIC_TPARAMS(n)> \+ inline typename enable_if< \+ detail::async_result_has_initiate_memfn< \+ CompletionToken, Signature>::value, \+ ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature, \+ (async_result<typename decay<CompletionToken>::type, \+ Signature>::initiate(declval<ASIO_MOVE_ARG(Initiation)>(), \+ declval<ASIO_MOVE_ARG(CompletionToken)>(), \+ ASIO_VARIADIC_MOVE_DECLVAL(n))))>::type \+ async_initiate(ASIO_MOVE_ARG(Initiation) initiation, \+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \+ ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ return async_result<typename decay<CompletionToken>::type, \+ Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation), \+ ASIO_MOVE_CAST(CompletionToken)(token), \+ ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ \+ template <typename CompletionToken, \+ ASIO_COMPLETION_SIGNATURE Signature, \+ typename Initiation, ASIO_VARIADIC_TPARAMS(n)> \+ inline typename enable_if< \+ !detail::async_result_has_initiate_memfn< \+ CompletionToken, Signature>::value, \+ ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type \+ async_initiate(ASIO_MOVE_ARG(Initiation) initiation, \+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \+ ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ async_completion<CompletionToken, Signature> completion(token); \+ \+ ASIO_MOVE_CAST(Initiation)(initiation)( \+ ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken, \+ Signature))(completion.completion_handler), \+ ASIO_VARIADIC_MOVE_ARGS(n)); \+ \+ return completion.result.get(); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)+#undef ASIO_PRIVATE_INITIATE_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#if defined(ASIO_HAS_CONCEPTS) \+ && defined(ASIO_HAS_VARIADIC_TEMPLATES) \+ && defined(ASIO_HAS_DECLTYPE)++namespace detail {++template <typename Signature>+struct initiation_archetype+{+ template <completion_handler_for<Signature> CompletionHandler>+ void operator()(CompletionHandler&&) const+ {+ }+};++} // namespace detail++template <typename T, typename Signature>+ASIO_CONCEPT completion_token_for =+ detail::is_completion_signature<Signature>::value+ &&+ requires(T&& t)+ {+ async_initiate<T, Signature>(detail::initiation_archetype<Signature>{}, t);+ };++#define ASIO_COMPLETION_TOKEN_FOR(s) \+ ::asio::completion_token_for<s>++#else // defined(ASIO_HAS_CONCEPTS)+ // && defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // && defined(ASIO_HAS_DECLTYPE)++#define ASIO_COMPLETION_TOKEN_FOR(s) typename++#endif // defined(ASIO_HAS_CONCEPTS)+ // && defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // && defined(ASIO_HAS_DECLTYPE)++namespace detail {++template <typename T, typename = void>+struct default_completion_token_impl+{+ typedef void type;+};++template <typename T>+struct default_completion_token_impl<T,+ typename void_type<typename T::default_completion_token_type>::type>+{+ typedef typename T::default_completion_token_type type;+};++} // namespace detail++#if defined(GENERATING_DOCUMENTATION)++/// Traits type used to determine the default completion token type associated+/// with a type (such as an executor).+/**+ * A program may specialise this traits type if the @c T template parameter in+ * the specialisation is a user-defined type.+ *+ * Specialisations of this trait may provide a nested typedef @c type, which is+ * a default-constructible completion token type.+ */+template <typename T>+struct default_completion_token+{+ /// If @c T has a nested type @c default_completion_token_type,+ /// <tt>T::default_completion_token_type</tt>. Otherwise the typedef @c type+ /// is not defined.+ typedef see_below type;+};+#else+template <typename T>+struct default_completion_token+ : detail::default_completion_token_impl<T>+{+};+#endif++#if defined(ASIO_HAS_ALIAS_TEMPLATES)++template <typename T>+using default_completion_token_t = typename default_completion_token<T>::type;++#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)++#if defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)++#define ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e) \+ = typename ::asio::default_completion_token<e>::type+#define ASIO_DEFAULT_COMPLETION_TOKEN(e) \+ = typename ::asio::default_completion_token<e>::type()++#else // defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)++#define ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e)+#define ASIO_DEFAULT_COMPLETION_TOKEN(e)++#endif // defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_ASYNC_RESULT_HPP
+ link/modules/asio-standalone/asio/include/asio/awaitable.hpp view
@@ -0,0 +1,133 @@+//+// awaitable.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 "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 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();+ }++ /// 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
+ link/modules/asio-standalone/asio/include/asio/basic_datagram_socket.hpp view
@@ -0,0 +1,1215 @@+//+// basic_datagram_socket.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DATAGRAM_SOCKET_HPP+#define ASIO_BASIC_DATAGRAM_SOCKET_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/basic_socket.hpp"+#include "asio/detail/handler_type_requirements.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/detail/push_options.hpp"++namespace asio {++#if !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)+#define ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename Protocol, typename Executor = any_io_executor>+class basic_datagram_socket;++#endif // !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)++/// Provides datagram-oriented socket functionality.+/**+ * The basic_datagram_socket class template provides asynchronous and blocking+ * datagram-oriented socket functionality.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename Protocol, typename Executor>+class basic_datagram_socket+ : public basic_socket<Protocol, Executor>+{+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_datagram_socket<Protocol, Executor1> other;+ };++ /// The native representation of a socket.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined native_handle_type;+#else+ typedef typename basic_socket<Protocol,+ Executor>::native_handle_type native_handle_type;+#endif++ /// The protocol type.+ typedef Protocol protocol_type;++ /// The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ /// Construct a basic_datagram_socket without opening it.+ /**+ * This constructor creates a datagram socket without opening it. The open()+ * function must be called before data can be sent or received on the socket.+ *+ * @param ex The I/O executor that the socket will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the socket.+ */+ explicit basic_datagram_socket(const executor_type& ex)+ : basic_socket<Protocol, Executor>(ex)+ {+ }++ /// Construct a basic_datagram_socket without opening it.+ /**+ * This constructor creates a datagram socket without opening it. The open()+ * function must be called before data can be sent or received on the 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.+ */+ template <typename ExecutionContext>+ explicit basic_datagram_socket(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context)+ {+ }++ /// Construct and open a basic_datagram_socket.+ /**+ * This constructor creates and opens a datagram socket.+ *+ * @param ex 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.+ */+ basic_datagram_socket(const executor_type& ex, const protocol_type& protocol)+ : basic_socket<Protocol, Executor>(ex, protocol)+ {+ }++ /// Construct and open a basic_datagram_socket.+ /**+ * This constructor creates and opens a datagram 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.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_datagram_socket(ExecutionContext& context,+ const protocol_type& protocol,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context, protocol)+ {+ }++ /// Construct a basic_datagram_socket, opening it and binding it to the given+ /// local endpoint.+ /**+ * This constructor creates a datagram 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 ex 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 datagram+ * socket will be bound.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_datagram_socket(const executor_type& ex, const endpoint_type& endpoint)+ : basic_socket<Protocol, Executor>(ex, endpoint)+ {+ }++ /// Construct a basic_datagram_socket, opening it and binding it to the given+ /// local endpoint.+ /**+ * This constructor creates a datagram 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 datagram+ * socket will be bound.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_datagram_socket(ExecutionContext& context,+ const endpoint_type& endpoint,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context, endpoint)+ {+ }++ /// Construct a basic_datagram_socket on an existing native socket.+ /**+ * This constructor creates a datagram socket object to hold an existing+ * native socket.+ *+ * @param ex 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.+ */+ basic_datagram_socket(const executor_type& ex,+ const protocol_type& protocol, const native_handle_type& native_socket)+ : basic_socket<Protocol, Executor>(ex, protocol, native_socket)+ {+ }++ /// Construct a basic_datagram_socket on an existing native socket.+ /**+ * This constructor creates a datagram 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_datagram_socket(ExecutionContext& context,+ const protocol_type& protocol, const native_handle_type& native_socket,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context, protocol, native_socket)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a basic_datagram_socket from another.+ /**+ * This constructor moves a datagram socket from one object to another.+ *+ * @param other The other basic_datagram_socket 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_datagram_socket(const executor_type&)+ * constructor.+ */+ basic_datagram_socket(basic_datagram_socket&& other) ASIO_NOEXCEPT+ : basic_socket<Protocol, Executor>(std::move(other))+ {+ }++ /// Move-assign a basic_datagram_socket from another.+ /**+ * This assignment operator moves a datagram socket from one object to+ * another.+ *+ * @param other The other basic_datagram_socket 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_datagram_socket(const executor_type&)+ * constructor.+ */+ basic_datagram_socket& operator=(basic_datagram_socket&& other)+ {+ basic_socket<Protocol, Executor>::operator=(std::move(other));+ return *this;+ }++ /// Move-construct a basic_datagram_socket from a socket of another protocol+ /// type.+ /**+ * This constructor moves a datagram socket from one object to another.+ *+ * @param other The other basic_datagram_socket 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_datagram_socket(const executor_type&)+ * constructor.+ */+ template <typename Protocol1, typename Executor1>+ basic_datagram_socket(basic_datagram_socket<Protocol1, Executor1>&& other,+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(std::move(other))+ {+ }++ /// Move-assign a basic_datagram_socket from a socket of another protocol+ /// type.+ /**+ * This assignment operator moves a datagram socket from one object to+ * another.+ *+ * @param other The other basic_datagram_socket 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_datagram_socket(const executor_type&)+ * constructor.+ */+ template <typename Protocol1, typename Executor1>+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value,+ basic_datagram_socket&+ >::type operator=(basic_datagram_socket<Protocol1, Executor1>&& other)+ {+ basic_socket<Protocol, Executor>::operator=(std::move(other));+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destroys the socket.+ /**+ * This function destroys the socket, cancelling any outstanding asynchronous+ * operations associated with the socket as if by calling @c cancel.+ */+ ~basic_datagram_socket()+ {+ }++ /// Send some data on a connected socket.+ /**+ * This function is used to send data on the datagram socket. The function+ * call will block until the data has been sent successfully or an error+ * occurs.+ *+ * @param buffers One ore more data buffers to be sent on the socket.+ *+ * @returns The number of bytes sent.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The send operation can only be used with a connected socket. Use+ * the send_to function to send data on an unconnected datagram socket.+ *+ * @par Example+ * To send a single data buffer use the @ref buffer function as follows:+ * @code socket.send(asio::buffer(data, size)); @endcode+ * See the @ref buffer documentation for information on sending multiple+ * buffers in one go, and how to use it with arrays, boost::array or+ * std::vector.+ */+ template <typename ConstBufferSequence>+ std::size_t send(const ConstBufferSequence& buffers)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().send(+ this->impl_.get_implementation(), buffers, 0, ec);+ asio::detail::throw_error(ec, "send");+ return s;+ }++ /// Send some data on a connected socket.+ /**+ * This function is used to send data on the datagram socket. The function+ * call will block until the data has been sent successfully or an error+ * occurs.+ *+ * @param buffers One ore more data buffers to be sent on the socket.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @returns The number of bytes sent.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The send operation can only be used with a connected socket. Use+ * the send_to function to send data on an unconnected datagram socket.+ */+ template <typename ConstBufferSequence>+ std::size_t send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().send(+ this->impl_.get_implementation(), buffers, flags, ec);+ asio::detail::throw_error(ec, "send");+ return s;+ }++ /// Send some data on a connected socket.+ /**+ * This function is used to send data on the datagram socket. The function+ * call will block until the data has been sent successfully or an error+ * occurs.+ *+ * @param buffers One or more data buffers to be sent on the socket.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes sent.+ *+ * @note The send operation can only be used with a connected socket. Use+ * the send_to function to send data on an unconnected datagram socket.+ */+ template <typename ConstBufferSequence>+ std::size_t send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ return this->impl_.get_service().send(+ this->impl_.get_implementation(), buffers, flags, ec);+ }++ /// Start an asynchronous send on a connected socket.+ /**+ * This function is used to asynchronously send data on the datagram socket.+ * The function call always returns immediately.+ *+ * @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+ * memory blocks is retained by the caller, which must guarantee that they+ * remain valid until the handler is called.+ *+ * @param handler The handler to be called when the send operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes sent.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The async_send operation can only be used with a connected socket.+ * Use the async_send_to function to send data on an unconnected datagram+ * socket.+ *+ * @par Example+ * To send a single data buffer use the @ref buffer function as follows:+ * @code+ * socket.async_send(asio::buffer(data, size), handler);+ * @endcode+ * See the @ref buffer documentation for information on sending 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)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_send(const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send(this), handler,+ buffers, socket_base::message_flags(0));+ }++ /// Start an asynchronous send on a connected socket.+ /**+ * This function is used to asynchronously send data on the datagram socket.+ * The function call always returns immediately.+ *+ * @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+ * memory blocks is retained by the caller, which must guarantee that they+ * remain valid until the handler is called.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param handler The handler to be called when the send operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes sent.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The async_send operation can only be used with a connected socket.+ * Use the async_send_to function to send data on an unconnected datagram+ * socket.+ */+ template <typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send(this), handler, buffers, flags);+ }++ /// Send a datagram to the specified endpoint.+ /**+ * This function is used to send a datagram to the specified remote endpoint.+ * The function call will block until the data has been sent successfully or+ * an error occurs.+ *+ * @param buffers One or more data buffers to be sent to the remote endpoint.+ *+ * @param destination The remote endpoint to which the data will be sent.+ *+ * @returns The number of bytes sent.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To send a single data buffer use the @ref buffer function as follows:+ * @code+ * asio::ip::udp::endpoint destination(+ * asio::ip::address::from_string("1.2.3.4"), 12345);+ * socket.send_to(asio::buffer(data, size), destination);+ * @endcode+ * See the @ref buffer documentation for information on sending multiple+ * buffers in one go, and how to use it with arrays, boost::array or+ * std::vector.+ */+ template <typename ConstBufferSequence>+ std::size_t send_to(const ConstBufferSequence& buffers,+ const endpoint_type& destination)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().send_to(+ this->impl_.get_implementation(), buffers, destination, 0, ec);+ asio::detail::throw_error(ec, "send_to");+ return s;+ }++ /// Send a datagram to the specified endpoint.+ /**+ * This function is used to send a datagram to the specified remote endpoint.+ * The function call will block until the data has been sent successfully or+ * an error occurs.+ *+ * @param buffers One or more data buffers to be sent to the remote endpoint.+ *+ * @param destination The remote endpoint to which the data will be sent.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @returns The number of bytes sent.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ConstBufferSequence>+ std::size_t send_to(const ConstBufferSequence& buffers,+ const endpoint_type& destination, socket_base::message_flags flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().send_to(+ this->impl_.get_implementation(), buffers, destination, flags, ec);+ asio::detail::throw_error(ec, "send_to");+ return s;+ }++ /// Send a datagram to the specified endpoint.+ /**+ * This function is used to send a datagram to the specified remote endpoint.+ * The function call will block until the data has been sent successfully or+ * an error occurs.+ *+ * @param buffers One or more data buffers to be sent to the remote endpoint.+ *+ * @param destination The remote endpoint to which the data will be sent.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes sent.+ */+ template <typename ConstBufferSequence>+ std::size_t send_to(const ConstBufferSequence& buffers,+ const endpoint_type& destination, socket_base::message_flags flags,+ asio::error_code& ec)+ {+ return this->impl_.get_service().send_to(this->impl_.get_implementation(),+ buffers, destination, flags, ec);+ }++ /// Start an asynchronous send.+ /**+ * This function is used to asynchronously send a datagram to the specified+ * remote endpoint. The function call always returns immediately.+ *+ * @param buffers One or more data buffers to be sent to the remote endpoint.+ * 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 handler is called.+ *+ * @param destination The remote endpoint to which the data will be sent.+ * Copies will be made of the endpoint as required.+ *+ * @param handler The handler to be called when the send operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes sent.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To send a single data buffer use the @ref buffer function as follows:+ * @code+ * asio::ip::udp::endpoint destination(+ * asio::ip::address::from_string("1.2.3.4"), 12345);+ * socket.async_send_to(+ * asio::buffer(data, size), destination, handler);+ * @endcode+ * See the @ref buffer documentation for information on sending 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)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_send_to(const ConstBufferSequence& buffers,+ const endpoint_type& destination,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send_to(this), handler, buffers,+ destination, socket_base::message_flags(0));+ }++ /// Start an asynchronous send.+ /**+ * This function is used to asynchronously send a datagram to the specified+ * remote endpoint. The function call always returns immediately.+ *+ * @param buffers One or more data buffers to be sent to the remote endpoint.+ * 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 handler is called.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param destination The remote endpoint to which the data will be sent.+ * Copies will be made of the endpoint as required.+ *+ * @param handler The handler to be called when the send operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes sent.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+ template <typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_send_to(const ConstBufferSequence& buffers,+ const endpoint_type& destination, socket_base::message_flags flags,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send_to(this), handler, buffers, destination, flags);+ }++ /// Receive some data on a connected socket.+ /**+ * This function is used to receive data on the datagram socket. The function+ * call will block until data has been received successfully or an error+ * occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @returns The number of bytes received.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The receive operation can only be used with a connected socket. Use+ * the receive_from function to receive data on an unconnected datagram+ * socket.+ *+ * @par Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code socket.receive(asio::buffer(data, size)); @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence>+ std::size_t receive(const MutableBufferSequence& buffers)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive(+ this->impl_.get_implementation(), buffers, 0, ec);+ asio::detail::throw_error(ec, "receive");+ return s;+ }++ /// Receive some data on a connected socket.+ /**+ * This function is used to receive data on the datagram socket. The function+ * call will block until data has been received successfully or an error+ * occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @returns The number of bytes received.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The receive operation can only be used with a connected socket. Use+ * the receive_from function to receive data on an unconnected datagram+ * socket.+ */+ template <typename MutableBufferSequence>+ std::size_t receive(const MutableBufferSequence& buffers,+ socket_base::message_flags flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive(+ this->impl_.get_implementation(), buffers, flags, ec);+ asio::detail::throw_error(ec, "receive");+ return s;+ }++ /// Receive some data on a connected socket.+ /**+ * This function is used to receive data on the datagram socket. The function+ * call will block until data has been received successfully or an error+ * occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes received.+ *+ * @note The receive operation can only be used with a connected socket. Use+ * the receive_from function to receive data on an unconnected datagram+ * socket.+ */+ template <typename MutableBufferSequence>+ std::size_t receive(const MutableBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ return this->impl_.get_service().receive(+ this->impl_.get_implementation(), buffers, flags, ec);+ }++ /// Start an asynchronous receive on a connected socket.+ /**+ * This function is used to asynchronously receive data from the datagram+ * socket. The function call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The async_receive operation can only be used with a connected socket.+ * Use the async_receive_from function to receive data on an unconnected+ * datagram socket.+ *+ * @par Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * socket.async_receive(asio::buffer(data, size), handler);+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive(const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive(this), handler,+ buffers, socket_base::message_flags(0));+ }++ /// Start an asynchronous receive on a connected socket.+ /**+ * This function is used to asynchronously receive data from the datagram+ * socket. The function call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The async_receive operation can only be used with a connected socket.+ * Use the async_receive_from function to receive data on an unconnected+ * datagram socket.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive(const MutableBufferSequence& buffers,+ socket_base::message_flags flags,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive(this), handler, buffers, flags);+ }++ /// Receive a datagram with the endpoint of the sender.+ /**+ * This function is used to receive a datagram. The function call will block+ * until data has been received successfully or an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param sender_endpoint An endpoint object that receives the endpoint of+ * the remote sender of the datagram.+ *+ * @returns The number of bytes received.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * asio::ip::udp::endpoint sender_endpoint;+ * socket.receive_from(+ * asio::buffer(data, size), sender_endpoint);+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence>+ std::size_t receive_from(const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive_from(+ this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec);+ asio::detail::throw_error(ec, "receive_from");+ return s;+ }+ + /// Receive a datagram with the endpoint of the sender.+ /**+ * This function is used to receive a datagram. The function call will block+ * until data has been received successfully or an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param sender_endpoint An endpoint object that receives the endpoint of+ * the remote sender of the datagram.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @returns The number of bytes received.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename MutableBufferSequence>+ std::size_t receive_from(const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint, socket_base::message_flags flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive_from(+ this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);+ asio::detail::throw_error(ec, "receive_from");+ return s;+ }+ + /// Receive a datagram with the endpoint of the sender.+ /**+ * This function is used to receive a datagram. The function call will block+ * until data has been received successfully or an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param sender_endpoint An endpoint object that receives the endpoint of+ * the remote sender of the datagram.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes received.+ */+ template <typename MutableBufferSequence>+ std::size_t receive_from(const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint, socket_base::message_flags flags,+ asio::error_code& ec)+ {+ return this->impl_.get_service().receive_from(+ this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);+ }++ /// Start an asynchronous receive.+ /**+ * This function is used to asynchronously receive a datagram. The function+ * call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param sender_endpoint An endpoint object that receives the endpoint of+ * the remote sender of the datagram. Ownership of the sender_endpoint object+ * is retained by the caller, which must guarantee that it is valid until the+ * handler is called.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code socket.async_receive_from(+ * asio::buffer(data, size), sender_endpoint, handler); @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive_from(const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive_from(this), handler, buffers,+ &sender_endpoint, socket_base::message_flags(0));+ }++ /// Start an asynchronous receive.+ /**+ * This function is used to asynchronously receive a datagram. The function+ * call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param sender_endpoint An endpoint object that receives the endpoint of+ * the remote sender of the datagram. Ownership of the sender_endpoint object+ * is retained by the caller, which must guarantee that it is valid until the+ * handler is called.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive_from(const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint, socket_base::message_flags flags,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive_from(this), handler,+ buffers, &sender_endpoint, flags);+ }++private:+ // Disallow copying and assignment.+ basic_datagram_socket(const basic_datagram_socket&) ASIO_DELETED;+ basic_datagram_socket& operator=(+ const basic_datagram_socket&) ASIO_DELETED;++ class initiate_async_send+ { + public:+ typedef Executor executor_type;++ explicit initiate_async_send(basic_datagram_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(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_datagram_socket* self_;+ };++ class initiate_async_send_to+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_send_to(basic_datagram_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(WriteHandler) handler,+ const ConstBufferSequence& buffers, const endpoint_type& destination,+ 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_to(+ self_->impl_.get_implementation(), buffers, destination,+ flags, handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_datagram_socket* self_;+ };++ class initiate_async_receive+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_receive(basic_datagram_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ const MutableBufferSequence& 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 ReadHandler.+ ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;++ detail::non_const_lvalue<ReadHandler> handler2(handler);+ self_->impl_.get_service().async_receive(+ self_->impl_.get_implementation(), buffers, flags,+ handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_datagram_socket* self_;+ };++ class initiate_async_receive_from+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_receive_from(basic_datagram_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ const MutableBufferSequence& buffers, endpoint_type* sender_endpoint,+ 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 ReadHandler.+ ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;++ detail::non_const_lvalue<ReadHandler> handler2(handler);+ self_->impl_.get_service().async_receive_from(+ self_->impl_.get_implementation(), buffers, *sender_endpoint,+ flags, handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_datagram_socket* self_;+ };+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BASIC_DATAGRAM_SOCKET_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_deadline_timer.hpp view
@@ -0,0 +1,693 @@+//+// basic_deadline_timer.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DEADLINE_TIMER_HPP+#define ASIO_BASIC_DEADLINE_TIMER_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_BOOST_DATE_TIME) \+ || defined(GENERATING_DOCUMENTATION)++#include <cstddef>+#include "asio/any_io_executor.hpp"+#include "asio/detail/deadline_timer_service.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/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/time_traits.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Provides waitable timer functionality.+/**+ * The basic_deadline_timer class template provides the ability to perform a+ * blocking or asynchronous wait for a timer to expire.+ *+ * A deadline timer is always in one of two states: "expired" or "not expired".+ * If the wait() or async_wait() function is called on an expired timer, the+ * wait operation will complete immediately.+ *+ * Most applications will use the asio::deadline_timer typedef.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Examples+ * Performing a blocking wait:+ * @code+ * // Construct a timer without setting an expiry time.+ * asio::deadline_timer timer(my_context);+ *+ * // Set an expiry time relative to now.+ * timer.expires_from_now(boost::posix_time::seconds(5));+ *+ * // Wait for the timer to expire.+ * timer.wait();+ * @endcode+ *+ * @par + * Performing an asynchronous wait:+ * @code+ * void handler(const asio::error_code& error)+ * {+ * if (!error)+ * {+ * // Timer expired.+ * }+ * }+ *+ * ...+ *+ * // Construct a timer with an absolute expiry time.+ * asio::deadline_timer timer(my_context,+ * boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));+ *+ * // Start an asynchronous wait.+ * timer.async_wait(handler);+ * @endcode+ *+ * @par Changing an active deadline_timer's expiry time+ *+ * Changing the expiry time of a timer while there are pending asynchronous+ * waits causes those wait operations to be cancelled. To ensure that the action+ * associated with the timer is performed only once, use something like this:+ * used:+ *+ * @code+ * void on_some_event()+ * {+ * if (my_timer.expires_from_now(seconds(5)) > 0)+ * {+ * // We managed to cancel the timer. Start new asynchronous wait.+ * my_timer.async_wait(on_timeout);+ * }+ * else+ * {+ * // Too late, timer has already expired!+ * }+ * }+ *+ * void on_timeout(const asio::error_code& e)+ * {+ * if (e != asio::error::operation_aborted)+ * {+ * // Timer was not cancelled, take necessary action.+ * }+ * }+ * @endcode+ *+ * @li The asio::basic_deadline_timer::expires_from_now() function+ * cancels any pending asynchronous waits, and returns the number of+ * asynchronous waits that were cancelled. If it returns 0 then you were too+ * late and the wait handler has already been executed, or will soon be+ * executed. If it returns 1 then the wait handler was successfully cancelled.+ *+ * @li If a wait handler is cancelled, the asio::error_code passed to+ * it contains the value asio::error::operation_aborted.+ */+template <typename Time,+ typename TimeTraits = asio::time_traits<Time>,+ typename Executor = any_io_executor>+class basic_deadline_timer+{+public:+ /// The type of the executor associated with the object.+ 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.+ typedef TimeTraits traits_type;++ /// The time type.+ typedef typename traits_type::time_type time_type;++ /// The duration type.+ typedef typename traits_type::duration_type duration_type;++ /// 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 ex The I/O executor that the timer will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the timer.+ */+ explicit basic_deadline_timer(const executor_type& ex)+ : impl_(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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ }++ /// Constructor to set a particular expiry time as an absolute time.+ /**+ * This constructor creates a timer and sets the expiry time.+ *+ * @param ex 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.+ */+ basic_deadline_timer(const executor_type& ex, const time_type& expiry_time)+ : impl_(ex)+ {+ asio::error_code 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code 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 relative to now.+ /**+ * This constructor creates a timer and sets the expiry time.+ *+ * @param ex 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.+ */+ basic_deadline_timer(const executor_type& ex,+ const duration_type& expiry_time)+ : impl_(ex)+ {+ asio::error_code ec;+ impl_.get_service().expires_from_now(+ 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(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");+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a basic_deadline_timer from another.+ /**+ * This constructor moves a timer from one object to another.+ *+ * @param other The other basic_deadline_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_deadline_timer(const executor_type&)+ * constructor.+ */+ basic_deadline_timer(basic_deadline_timer&& other)+ : impl_(std::move(other.impl_))+ {+ }++ /// Move-assign a basic_deadline_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_deadline_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_deadline_timer(const executor_type&)+ * constructor.+ */+ basic_deadline_timer& operator=(basic_deadline_timer&& other)+ {+ impl_ = std::move(other.impl_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destroys the timer.+ /**+ * This function destroys the timer, cancelling any outstanding asynchronous+ * wait operations associated with the timer as if by calling @c cancel.+ */+ ~basic_deadline_timer()+ {+ }++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_NOEXCEPT+ {+ return impl_.get_executor();+ }++ /// Cancel any asynchronous operations that are waiting on the timer.+ /**+ * This function forces the completion of any pending asynchronous wait+ * operations against the timer. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * Cancelling the timer does not change the expiry time.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note If the timer has already expired when cancel() is called, then the+ * handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t cancel()+ {+ asio::error_code ec;+ std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "cancel");+ return s;+ }++ /// Cancel any asynchronous operations that are waiting on the timer.+ /**+ * This function forces the completion of any pending asynchronous wait+ * operations against the timer. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * Cancelling the timer does not change the expiry time.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @note If the timer has already expired when cancel() is called, then the+ * handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t cancel(asio::error_code& ec)+ {+ return impl_.get_service().cancel(impl_.get_implementation(), ec);+ }++ /// Cancels one asynchronous operation that is waiting on the timer.+ /**+ * This function forces the completion of one pending asynchronous wait+ * operation against the timer. Handlers are cancelled in FIFO order. The+ * handler for the cancelled operation will be invoked with the+ * asio::error::operation_aborted error code.+ *+ * Cancelling the timer does not change the expiry time.+ *+ * @return The number of asynchronous operations that were cancelled. That is,+ * either 0 or 1.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note If the timer has already expired when cancel_one() is called, then+ * the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t cancel_one()+ {+ asio::error_code ec;+ std::size_t s = impl_.get_service().cancel_one(+ impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "cancel_one");+ return s;+ }++ /// Cancels one asynchronous operation that is waiting on the timer.+ /**+ * This function forces the completion of one pending asynchronous wait+ * operation against the timer. Handlers are cancelled in FIFO order. The+ * handler for the cancelled operation will be invoked with the+ * asio::error::operation_aborted error code.+ *+ * Cancelling the timer does not change the expiry time.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of asynchronous operations that were cancelled. That is,+ * either 0 or 1.+ *+ * @note If the timer has already expired when cancel_one() is called, then+ * the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t cancel_one(asio::error_code& ec)+ {+ return impl_.get_service().cancel_one(impl_.get_implementation(), ec);+ }++ /// Get the timer's expiry time as an absolute time.+ /**+ * This function may be used to obtain the timer's current expiry time.+ * Whether the timer has expired or not does not affect this value.+ */+ time_type expires_at() const+ {+ return impl_.get_service().expires_at(impl_.get_implementation());+ }++ /// Set the timer's expiry time as an absolute time.+ /**+ * This function sets the expiry time. Any pending asynchronous wait+ * operations will be cancelled. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * @param expiry_time The expiry time to be used for the timer.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note If the timer has already expired when expires_at() is called, then+ * the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t expires_at(const time_type& expiry_time)+ {+ asio::error_code ec;+ std::size_t s = impl_.get_service().expires_at(+ impl_.get_implementation(), expiry_time, ec);+ asio::detail::throw_error(ec, "expires_at");+ return s;+ }++ /// Set the timer's expiry time as an absolute time.+ /**+ * This function sets the expiry time. Any pending asynchronous wait+ * operations will be cancelled. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * @param expiry_time The expiry time to be used for the timer.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @note If the timer has already expired when expires_at() is called, then+ * the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t expires_at(const time_type& expiry_time,+ asio::error_code& ec)+ {+ return impl_.get_service().expires_at(+ impl_.get_implementation(), expiry_time, ec);+ }++ /// Get the timer's expiry time relative to now.+ /**+ * This function may be used to obtain the timer's current expiry time.+ * Whether the timer has expired or not does not affect this value.+ */+ duration_type expires_from_now() const+ {+ return impl_.get_service().expires_from_now(impl_.get_implementation());+ }++ /// Set the timer's expiry time relative to now.+ /**+ * This function sets the expiry time. Any pending asynchronous wait+ * operations will be cancelled. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * @param expiry_time The expiry time to be used for the timer.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note If the timer has already expired when expires_from_now() is called,+ * then the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t expires_from_now(const duration_type& expiry_time)+ {+ asio::error_code ec;+ std::size_t s = impl_.get_service().expires_from_now(+ impl_.get_implementation(), expiry_time, ec);+ asio::detail::throw_error(ec, "expires_from_now");+ return s;+ }++ /// Set the timer's expiry time relative to now.+ /**+ * This function sets the expiry time. Any pending asynchronous wait+ * operations will be cancelled. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * @param expiry_time The expiry time to be used for the timer.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @note If the timer has already expired when expires_from_now() is called,+ * then the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t expires_from_now(const duration_type& expiry_time,+ asio::error_code& ec)+ {+ return impl_.get_service().expires_from_now(+ impl_.get_implementation(), expiry_time, ec);+ }++ /// Perform a blocking wait on the timer.+ /**+ * This function is used to wait for the timer to expire. This function+ * blocks and does not return until the timer has expired.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void wait()+ {+ asio::error_code ec;+ impl_.get_service().wait(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "wait");+ }++ /// Perform a blocking wait on the timer.+ /**+ * This function is used to wait for the timer to expire. This function+ * blocks and does not return until the timer has expired.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ void wait(asio::error_code& ec)+ {+ impl_.get_service().wait(impl_.get_implementation(), ec);+ }++ /// Start an asynchronous wait on the timer.+ /**+ * This function may be used to initiate an asynchronous wait against the+ * timer. It always returns immediately.+ *+ * For each call to async_wait(), the supplied handler will be called exactly+ * once. The handler will be called when:+ *+ * @li The timer has expired.+ *+ * @li The timer was cancelled, in which case the handler is passed the error+ * code asio::error::operation_aborted.+ *+ * @param handler The handler to be called when the timer expires. Copies+ * will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error // Result of operation.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))+ WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,+ void (asio::error_code))+ async_wait(+ ASIO_MOVE_ARG(WaitHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WaitHandler, void (asio::error_code)>(+ initiate_async_wait(this), handler);+ }++private:+ // Disallow copying and assignment.+ basic_deadline_timer(const basic_deadline_timer&) ASIO_DELETED;+ basic_deadline_timer& operator=(+ const basic_deadline_timer&) ASIO_DELETED;++ class initiate_async_wait+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_wait(basic_deadline_timer* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WaitHandler>+ void operator()(ASIO_MOVE_ARG(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_deadline_timer* self_;+ };++ detail::io_object_impl<+ detail::deadline_timer_service<TimeTraits>, Executor> impl_;+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_BOOST_DATE_TIME)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_BASIC_DEADLINE_TIMER_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_io_object.hpp view
@@ -0,0 +1,290 @@+//+// basic_io_object.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IO_OBJECT_HPP+#define ASIO_BASIC_IO_OBJECT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/io_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(ASIO_HAS_MOVE)+namespace detail+{+ // Type trait used to determine whether a service supports move.+ template <typename IoObjectService>+ class service_has_move+ {+ private:+ typedef IoObjectService service_type;+ typedef typename service_type::implementation_type implementation_type;++ template <typename T, typename U>+ static auto asio_service_has_move_eval(T* t, U* u)+ -> decltype(t->move_construct(*u, *u), char());+ static char (&asio_service_has_move_eval(...))[2];++ public:+ static const bool value =+ sizeof(asio_service_has_move_eval(+ static_cast<service_type*>(0),+ static_cast<implementation_type*>(0))) == 1;+ };+}+#endif // defined(ASIO_HAS_MOVE)++/// Base class for all I/O objects.+/**+ * @note All I/O objects are non-copyable. However, when using C++0x, certain+ * I/O objects do support move construction and move assignment.+ */+#if !defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+template <typename IoObjectService>+#else+template <typename IoObjectService,+ bool Movable = detail::service_has_move<IoObjectService>::value>+#endif+class basic_io_object+{+public:+ /// The type of the service that will be used to provide I/O operations.+ typedef IoObjectService service_type;++ /// The underlying implementation type of I/O object.+ typedef typename service_type::implementation_type implementation_type;++#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 service_.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 service_.get_io_context();+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// The type of the executor associated with the object.+ typedef asio::io_context::executor_type executor_type;++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_NOEXCEPT+ {+ return service_.get_io_context().get_executor();+ }++protected:+ /// Construct a basic_io_object.+ /**+ * Performs:+ * @code get_service().construct(get_implementation()); @endcode+ */+ explicit basic_io_object(asio::io_context& io_context)+ : service_(asio::use_service<IoObjectService>(io_context))+ {+ service_.construct(implementation_);+ }++#if defined(GENERATING_DOCUMENTATION)+ /// Move-construct a basic_io_object.+ /**+ * Performs:+ * @code get_service().move_construct(+ * get_implementation(), other.get_implementation()); @endcode+ *+ * @note Available only for services that support movability,+ */+ basic_io_object(basic_io_object&& other);++ /// Move-assign a basic_io_object.+ /**+ * Performs:+ * @code get_service().move_assign(get_implementation(),+ * other.get_service(), other.get_implementation()); @endcode+ *+ * @note Available only for services that support movability,+ */+ basic_io_object& operator=(basic_io_object&& other);++ /// Perform a converting move-construction of a basic_io_object.+ template <typename IoObjectService1>+ basic_io_object(IoObjectService1& other_service,+ typename IoObjectService1::implementation_type& other_implementation);+#endif // defined(GENERATING_DOCUMENTATION)++ /// Protected destructor to prevent deletion through this type.+ /**+ * Performs:+ * @code get_service().destroy(get_implementation()); @endcode+ */+ ~basic_io_object()+ {+ service_.destroy(implementation_);+ }++ /// Get the service associated with the I/O object.+ service_type& get_service()+ {+ return service_;+ }++ /// Get the service associated with the I/O object.+ const service_type& get_service() const+ {+ return service_;+ }++ /// Get the underlying implementation of the I/O object.+ implementation_type& get_implementation()+ {+ return implementation_;+ }++ /// Get the underlying implementation of the I/O object.+ const implementation_type& get_implementation() const+ {+ return implementation_;+ }++private:+ basic_io_object(const basic_io_object&);+ basic_io_object& operator=(const basic_io_object&);++ // The service associated with the I/O object.+ service_type& service_;++ /// The underlying implementation of the I/O object.+ implementation_type implementation_;+};++#if defined(ASIO_HAS_MOVE)+// Specialisation for movable objects.+template <typename IoObjectService>+class basic_io_object<IoObjectService, true>+{+public:+ typedef IoObjectService service_type;+ typedef typename service_type::implementation_type implementation_type;++#if !defined(ASIO_NO_DEPRECATED)+ asio::io_context& get_io_context()+ {+ return service_->get_io_context();+ }++ asio::io_context& get_io_service()+ {+ return service_->get_io_context();+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ typedef asio::io_context::executor_type executor_type;++ executor_type get_executor() ASIO_NOEXCEPT+ {+ return service_->get_io_context().get_executor();+ }++protected:+ explicit basic_io_object(asio::io_context& io_context)+ : service_(&asio::use_service<IoObjectService>(io_context))+ {+ service_->construct(implementation_);+ }++ basic_io_object(basic_io_object&& other)+ : service_(&other.get_service())+ {+ service_->move_construct(implementation_, other.implementation_);+ }++ template <typename IoObjectService1>+ basic_io_object(IoObjectService1& other_service,+ typename IoObjectService1::implementation_type& other_implementation)+ : service_(&asio::use_service<IoObjectService>(+ other_service.get_io_context()))+ {+ service_->converting_move_construct(implementation_,+ other_service, other_implementation);+ }++ ~basic_io_object()+ {+ service_->destroy(implementation_);+ }++ basic_io_object& operator=(basic_io_object&& other)+ {+ service_->move_assign(implementation_,+ *other.service_, other.implementation_);+ service_ = other.service_;+ return *this;+ }++ service_type& get_service()+ {+ return *service_;+ }++ const service_type& get_service() const+ {+ return *service_;+ }++ implementation_type& get_implementation()+ {+ return implementation_;+ }++ const implementation_type& get_implementation() const+ {+ return implementation_;+ }++private:+ basic_io_object(const basic_io_object&);+ void operator=(const basic_io_object&);++ IoObjectService* service_;+ implementation_type implementation_;+};+#endif // defined(ASIO_HAS_MOVE)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BASIC_IO_OBJECT_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_raw_socket.hpp view
@@ -0,0 +1,1206 @@+//+// basic_raw_socket.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_RAW_SOCKET_HPP+#define ASIO_BASIC_RAW_SOCKET_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/basic_socket.hpp"+#include "asio/detail/handler_type_requirements.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/detail/push_options.hpp"++namespace asio {++#if !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL)+#define ASIO_BASIC_RAW_SOCKET_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename Protocol, typename Executor = any_io_executor>+class basic_raw_socket;++#endif // !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL)++/// Provides raw-oriented socket functionality.+/**+ * The basic_raw_socket class template provides asynchronous and blocking+ * raw-oriented socket functionality.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename Protocol, typename Executor>+class basic_raw_socket+ : public basic_socket<Protocol, Executor>+{+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_raw_socket<Protocol, Executor1> other;+ };++ /// The native representation of a socket.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined native_handle_type;+#else+ typedef typename basic_socket<Protocol,+ Executor>::native_handle_type native_handle_type;+#endif++ /// The protocol type.+ typedef Protocol protocol_type;++ /// The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ /// Construct a basic_raw_socket without opening it.+ /**+ * This constructor creates a raw socket without opening it. The open()+ * function must be called before data can be sent or received on the socket.+ *+ * @param ex The I/O executor that the socket will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the socket.+ */+ explicit basic_raw_socket(const executor_type& ex)+ : basic_socket<Protocol, Executor>(ex)+ {+ }++ /// Construct a basic_raw_socket without opening it.+ /**+ * This constructor creates a raw socket without opening it. The open()+ * function must be called before data can be sent or received on the 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.+ */+ template <typename ExecutionContext>+ explicit basic_raw_socket(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context)+ {+ }++ /// Construct and open a basic_raw_socket.+ /**+ * This constructor creates and opens a raw socket.+ *+ * @param ex 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.+ */+ basic_raw_socket(const executor_type& ex, const protocol_type& protocol)+ : basic_socket<Protocol, Executor>(ex, protocol)+ {+ }++ /// Construct and open a basic_raw_socket.+ /**+ * This constructor creates and opens a raw 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.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_raw_socket(ExecutionContext& context, const protocol_type& protocol,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context, protocol)+ {+ }++ /// Construct a basic_raw_socket, opening it and binding it to the given+ /// local endpoint.+ /**+ * This constructor creates a raw 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 ex 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 raw+ * socket will be bound.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_raw_socket(const executor_type& ex, const endpoint_type& endpoint)+ : basic_socket<Protocol, Executor>(ex, endpoint)+ {+ }++ /// Construct a basic_raw_socket, opening it and binding it to the given+ /// local endpoint.+ /**+ * This constructor creates a raw 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 raw+ * socket will be bound.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_raw_socket(ExecutionContext& context, const endpoint_type& endpoint,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context, endpoint)+ {+ }++ /// Construct a basic_raw_socket on an existing native socket.+ /**+ * This constructor creates a raw socket object to hold an existing+ * native socket.+ *+ * @param ex 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.+ */+ basic_raw_socket(const executor_type& ex,+ const protocol_type& protocol, const native_handle_type& native_socket)+ : basic_socket<Protocol, Executor>(ex, protocol, native_socket)+ {+ }++ /// Construct a basic_raw_socket on an existing native socket.+ /**+ * This constructor creates a raw 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_raw_socket(ExecutionContext& context,+ const protocol_type& protocol, const native_handle_type& native_socket,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context, protocol, native_socket)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a basic_raw_socket from another.+ /**+ * This constructor moves a raw socket from one object to another.+ *+ * @param other The other basic_raw_socket 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_raw_socket(const executor_type&)+ * constructor.+ */+ basic_raw_socket(basic_raw_socket&& other) ASIO_NOEXCEPT+ : basic_socket<Protocol, Executor>(std::move(other))+ {+ }++ /// Move-assign a basic_raw_socket from another.+ /**+ * This assignment operator moves a raw socket from one object to another.+ *+ * @param other The other basic_raw_socket 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_raw_socket(const executor_type&)+ * constructor.+ */+ basic_raw_socket& operator=(basic_raw_socket&& other)+ {+ basic_socket<Protocol, Executor>::operator=(std::move(other));+ return *this;+ }++ /// Move-construct a basic_raw_socket from a socket of another protocol+ /// type.+ /**+ * This constructor moves a raw socket from one object to another.+ *+ * @param other The other basic_raw_socket 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_raw_socket(const executor_type&)+ * constructor.+ */+ template <typename Protocol1, typename Executor1>+ basic_raw_socket(basic_raw_socket<Protocol1, Executor1>&& other,+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(std::move(other))+ {+ }++ /// Move-assign a basic_raw_socket from a socket of another protocol type.+ /**+ * This assignment operator moves a raw socket from one object to another.+ *+ * @param other The other basic_raw_socket 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_raw_socket(const executor_type&)+ * constructor.+ */+ template <typename Protocol1, typename Executor1>+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value,+ basic_raw_socket&+ >::type operator=(basic_raw_socket<Protocol1, Executor1>&& other)+ {+ basic_socket<Protocol, Executor>::operator=(std::move(other));+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destroys the socket.+ /**+ * This function destroys the socket, cancelling any outstanding asynchronous+ * operations associated with the socket as if by calling @c cancel.+ */+ ~basic_raw_socket()+ {+ }++ /// Send some data on a connected socket.+ /**+ * This function is used to send data on the raw socket. The function call+ * will block until the data has been sent successfully or an error occurs.+ *+ * @param buffers One ore more data buffers to be sent on the socket.+ *+ * @returns The number of bytes sent.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The send operation can only be used with a connected socket. Use+ * the send_to function to send data on an unconnected raw socket.+ *+ * @par Example+ * To send a single data buffer use the @ref buffer function as follows:+ * @code socket.send(asio::buffer(data, size)); @endcode+ * See the @ref buffer documentation for information on sending multiple+ * buffers in one go, and how to use it with arrays, boost::array or+ * std::vector.+ */+ template <typename ConstBufferSequence>+ std::size_t send(const ConstBufferSequence& buffers)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().send(+ this->impl_.get_implementation(), buffers, 0, ec);+ asio::detail::throw_error(ec, "send");+ return s;+ }++ /// Send some data on a connected socket.+ /**+ * This function is used to send data on the raw socket. The function call+ * will block until the data has been sent successfully or an error occurs.+ *+ * @param buffers One ore more data buffers to be sent on the socket.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @returns The number of bytes sent.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The send operation can only be used with a connected socket. Use+ * the send_to function to send data on an unconnected raw socket.+ */+ template <typename ConstBufferSequence>+ std::size_t send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().send(+ this->impl_.get_implementation(), buffers, flags, ec);+ asio::detail::throw_error(ec, "send");+ return s;+ }++ /// Send some data on a connected socket.+ /**+ * This function is used to send data on the raw socket. The function call+ * will block until the data has been sent successfully or an error occurs.+ *+ * @param buffers One or more data buffers to be sent on the socket.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes sent.+ *+ * @note The send operation can only be used with a connected socket. Use+ * the send_to function to send data on an unconnected raw socket.+ */+ template <typename ConstBufferSequence>+ std::size_t send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ return this->impl_.get_service().send(+ this->impl_.get_implementation(), buffers, flags, ec);+ }++ /// Start an asynchronous send on a connected socket.+ /**+ * This function is used to send data on the raw socket. The function call+ * will block until the data has been sent successfully or an error occurs.+ *+ * @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+ * memory blocks is retained by the caller, which must guarantee that they+ * remain valid until the handler is called.+ *+ * @param handler The handler to be called when the send operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes sent.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The async_send operation can only be used with a connected socket.+ * Use the async_send_to function to send data on an unconnected raw+ * socket.+ *+ * @par Example+ * To send a single data buffer use the @ref buffer function as follows:+ * @code+ * socket.async_send(asio::buffer(data, size), handler);+ * @endcode+ * See the @ref buffer documentation for information on sending 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)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_send(const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send(this), handler,+ buffers, socket_base::message_flags(0));+ }++ /// Start an asynchronous send on a connected socket.+ /**+ * This function is used to send data on the raw socket. The function call+ * will block until the data has been sent successfully or an error occurs.+ *+ * @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+ * memory blocks is retained by the caller, which must guarantee that they+ * remain valid until the handler is called.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param handler The handler to be called when the send operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes sent.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The async_send operation can only be used with a connected socket.+ * Use the async_send_to function to send data on an unconnected raw+ * socket.+ */+ template <typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send(this), handler, buffers, flags);+ }++ /// Send raw data to the specified endpoint.+ /**+ * This function is used to send raw data to the specified remote endpoint.+ * The function call will block until the data has been sent successfully or+ * an error occurs.+ *+ * @param buffers One or more data buffers to be sent to the remote endpoint.+ *+ * @param destination The remote endpoint to which the data will be sent.+ *+ * @returns The number of bytes sent.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To send a single data buffer use the @ref buffer function as follows:+ * @code+ * asio::ip::udp::endpoint destination(+ * asio::ip::address::from_string("1.2.3.4"), 12345);+ * socket.send_to(asio::buffer(data, size), destination);+ * @endcode+ * See the @ref buffer documentation for information on sending multiple+ * buffers in one go, and how to use it with arrays, boost::array or+ * std::vector.+ */+ template <typename ConstBufferSequence>+ std::size_t send_to(const ConstBufferSequence& buffers,+ const endpoint_type& destination)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().send_to(+ this->impl_.get_implementation(), buffers, destination, 0, ec);+ asio::detail::throw_error(ec, "send_to");+ return s;+ }++ /// Send raw data to the specified endpoint.+ /**+ * This function is used to send raw data to the specified remote endpoint.+ * The function call will block until the data has been sent successfully or+ * an error occurs.+ *+ * @param buffers One or more data buffers to be sent to the remote endpoint.+ *+ * @param destination The remote endpoint to which the data will be sent.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @returns The number of bytes sent.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ConstBufferSequence>+ std::size_t send_to(const ConstBufferSequence& buffers,+ const endpoint_type& destination, socket_base::message_flags flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().send_to(+ this->impl_.get_implementation(), buffers, destination, flags, ec);+ asio::detail::throw_error(ec, "send_to");+ return s;+ }++ /// Send raw data to the specified endpoint.+ /**+ * This function is used to send raw data to the specified remote endpoint.+ * The function call will block until the data has been sent successfully or+ * an error occurs.+ *+ * @param buffers One or more data buffers to be sent to the remote endpoint.+ *+ * @param destination The remote endpoint to which the data will be sent.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes sent.+ */+ template <typename ConstBufferSequence>+ std::size_t send_to(const ConstBufferSequence& buffers,+ const endpoint_type& destination, socket_base::message_flags flags,+ asio::error_code& ec)+ {+ return this->impl_.get_service().send_to(this->impl_.get_implementation(),+ buffers, destination, flags, ec);+ }++ /// Start an asynchronous send.+ /**+ * This function is used to asynchronously send raw data to the specified+ * remote endpoint. The function call always returns immediately.+ *+ * @param buffers One or more data buffers to be sent to the remote endpoint.+ * 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 handler is called.+ *+ * @param destination The remote endpoint to which the data will be sent.+ * Copies will be made of the endpoint as required.+ *+ * @param handler The handler to be called when the send operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes sent.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To send a single data buffer use the @ref buffer function as follows:+ * @code+ * asio::ip::udp::endpoint destination(+ * asio::ip::address::from_string("1.2.3.4"), 12345);+ * socket.async_send_to(+ * asio::buffer(data, size), destination, handler);+ * @endcode+ * See the @ref buffer documentation for information on sending 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)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_send_to(const ConstBufferSequence& buffers,+ const endpoint_type& destination,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send_to(this), handler, buffers,+ destination, socket_base::message_flags(0));+ }++ /// Start an asynchronous send.+ /**+ * This function is used to asynchronously send raw data to the specified+ * remote endpoint. The function call always returns immediately.+ *+ * @param buffers One or more data buffers to be sent to the remote endpoint.+ * 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 handler is called.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param destination The remote endpoint to which the data will be sent.+ * Copies will be made of the endpoint as required.+ *+ * @param handler The handler to be called when the send operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes sent.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+ template <typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_send_to(const ConstBufferSequence& buffers,+ const endpoint_type& destination, socket_base::message_flags flags,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send_to(this), handler, buffers, destination, flags);+ }++ /// Receive some data on a connected socket.+ /**+ * This function is used to receive data on the raw socket. The function+ * call will block until data has been received successfully or an error+ * occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @returns The number of bytes received.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The receive operation can only be used with a connected socket. Use+ * the receive_from function to receive data on an unconnected raw+ * socket.+ *+ * @par Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code socket.receive(asio::buffer(data, size)); @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence>+ std::size_t receive(const MutableBufferSequence& buffers)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive(+ this->impl_.get_implementation(), buffers, 0, ec);+ asio::detail::throw_error(ec, "receive");+ return s;+ }++ /// Receive some data on a connected socket.+ /**+ * This function is used to receive data on the raw socket. The function+ * call will block until data has been received successfully or an error+ * occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @returns The number of bytes received.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The receive operation can only be used with a connected socket. Use+ * the receive_from function to receive data on an unconnected raw+ * socket.+ */+ template <typename MutableBufferSequence>+ std::size_t receive(const MutableBufferSequence& buffers,+ socket_base::message_flags flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive(+ this->impl_.get_implementation(), buffers, flags, ec);+ asio::detail::throw_error(ec, "receive");+ return s;+ }++ /// Receive some data on a connected socket.+ /**+ * This function is used to receive data on the raw socket. The function+ * call will block until data has been received successfully or an error+ * occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes received.+ *+ * @note The receive operation can only be used with a connected socket. Use+ * the receive_from function to receive data on an unconnected raw+ * socket.+ */+ template <typename MutableBufferSequence>+ std::size_t receive(const MutableBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ return this->impl_.get_service().receive(+ this->impl_.get_implementation(), buffers, flags, ec);+ }++ /// Start an asynchronous receive on a connected socket.+ /**+ * This function is used to asynchronously receive data from the raw+ * socket. The function call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The async_receive operation can only be used with a connected socket.+ * Use the async_receive_from function to receive data on an unconnected+ * raw socket.+ *+ * @par Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * socket.async_receive(asio::buffer(data, size), handler);+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive(const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive(this), handler,+ buffers, socket_base::message_flags(0));+ }++ /// Start an asynchronous receive on a connected socket.+ /**+ * This function is used to asynchronously receive data from the raw+ * socket. The function call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The async_receive operation can only be used with a connected socket.+ * Use the async_receive_from function to receive data on an unconnected+ * raw socket.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive(const MutableBufferSequence& buffers,+ socket_base::message_flags flags,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive(this), handler, buffers, flags);+ }++ /// Receive raw data with the endpoint of the sender.+ /**+ * This function is used to receive raw data. The function call will block+ * until data has been received successfully or an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param sender_endpoint An endpoint object that receives the endpoint of+ * the remote sender of the data.+ *+ * @returns The number of bytes received.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * asio::ip::udp::endpoint sender_endpoint;+ * socket.receive_from(+ * asio::buffer(data, size), sender_endpoint);+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence>+ std::size_t receive_from(const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive_from(+ this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec);+ asio::detail::throw_error(ec, "receive_from");+ return s;+ }+ + /// Receive raw data with the endpoint of the sender.+ /**+ * This function is used to receive raw data. The function call will block+ * until data has been received successfully or an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param sender_endpoint An endpoint object that receives the endpoint of+ * the remote sender of the data.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @returns The number of bytes received.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename MutableBufferSequence>+ std::size_t receive_from(const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint, socket_base::message_flags flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive_from(+ this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);+ asio::detail::throw_error(ec, "receive_from");+ return s;+ }+ + /// Receive raw data with the endpoint of the sender.+ /**+ * This function is used to receive raw data. The function call will block+ * until data has been received successfully or an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param sender_endpoint An endpoint object that receives the endpoint of+ * the remote sender of the data.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes received.+ */+ template <typename MutableBufferSequence>+ std::size_t receive_from(const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint, socket_base::message_flags flags,+ asio::error_code& ec)+ {+ return this->impl_.get_service().receive_from(+ this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);+ }++ /// Start an asynchronous receive.+ /**+ * This function is used to asynchronously receive raw data. The function+ * call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param sender_endpoint An endpoint object that receives the endpoint of+ * the remote sender of the data. Ownership of the sender_endpoint object+ * is retained by the caller, which must guarantee that it is valid until the+ * handler is called.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code socket.async_receive_from(+ * asio::buffer(data, size), 0, sender_endpoint, handler); @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive_from(const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive_from(this), handler, buffers,+ &sender_endpoint, socket_base::message_flags(0));+ }++ /// Start an asynchronous receive.+ /**+ * This function is used to asynchronously receive raw data. The function+ * call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param sender_endpoint An endpoint object that receives the endpoint of+ * the remote sender of the data. Ownership of the sender_endpoint object+ * is retained by the caller, which must guarantee that it is valid until the+ * handler is called.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive_from(const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint, socket_base::message_flags flags,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive_from(this), handler,+ buffers, &sender_endpoint, flags);+ }++private:+ // Disallow copying and assignment.+ basic_raw_socket(const basic_raw_socket&) ASIO_DELETED;+ basic_raw_socket& operator=(const basic_raw_socket&) ASIO_DELETED;++ class initiate_async_send+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_send(basic_raw_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(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_raw_socket* self_;+ };++ class initiate_async_send_to+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_send_to(basic_raw_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(WriteHandler) handler,+ const ConstBufferSequence& buffers, const endpoint_type& destination,+ 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_to(+ self_->impl_.get_implementation(), buffers, destination,+ flags, handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_raw_socket* self_;+ };++ class initiate_async_receive+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_receive(basic_raw_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ const MutableBufferSequence& 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 ReadHandler.+ ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;++ detail::non_const_lvalue<ReadHandler> handler2(handler);+ self_->impl_.get_service().async_receive(+ self_->impl_.get_implementation(), buffers, flags,+ handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_raw_socket* self_;+ };++ class initiate_async_receive_from+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_receive_from(basic_raw_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ const MutableBufferSequence& buffers, endpoint_type* sender_endpoint,+ 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 ReadHandler.+ ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;++ detail::non_const_lvalue<ReadHandler> handler2(handler);+ self_->impl_.get_service().async_receive_from(+ self_->impl_.get_implementation(), buffers, *sender_endpoint,+ flags, handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_raw_socket* self_;+ };+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BASIC_RAW_SOCKET_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_seq_packet_socket.hpp view
@@ -0,0 +1,761 @@+//+// basic_seq_packet_socket.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SEQ_PACKET_SOCKET_HPP+#define ASIO_BASIC_SEQ_PACKET_SOCKET_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/basic_socket.hpp"+#include "asio/detail/handler_type_requirements.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++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.+/**+ * The basic_seq_packet_socket class template provides asynchronous and blocking+ * sequenced packet socket functionality.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename Protocol, typename Executor>+class basic_seq_packet_socket+ : public basic_socket<Protocol, Executor>+{+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.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined native_handle_type;+#else+ typedef typename basic_socket<Protocol,+ Executor>::native_handle_type native_handle_type;+#endif++ /// The protocol type.+ typedef Protocol protocol_type;++ /// The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ /// 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 ex The I/O executor that the socket will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the socket.+ */+ explicit basic_seq_packet_socket(const executor_type& ex)+ : 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context)+ {+ }++ /// 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 ex 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.+ */+ basic_seq_packet_socket(const executor_type& ex,+ const protocol_type& 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context, protocol)+ {+ }++ /// 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 ex 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.+ */+ basic_seq_packet_socket(const executor_type& ex,+ const endpoint_type& 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context, endpoint)+ {+ }++ /// 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 ex 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.+ */+ basic_seq_packet_socket(const executor_type& ex,+ const protocol_type& protocol, const native_handle_type& native_socket)+ : basic_socket<Protocol, Executor>(ex, 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 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.+ /**+ * This constructor moves a sequenced packet socket from one object to+ * another.+ *+ * @param other The other basic_seq_packet_socket 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_seq_packet_socket(const executor_type&)+ * constructor.+ */+ basic_seq_packet_socket(basic_seq_packet_socket&& other) ASIO_NOEXCEPT+ : basic_socket<Protocol, Executor>(std::move(other))+ {+ }++ /// Move-assign a basic_seq_packet_socket from another.+ /**+ * This assignment operator moves a sequenced packet socket from one object to+ * another.+ *+ * @param other The other basic_seq_packet_socket 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_seq_packet_socket(const executor_type&)+ * constructor.+ */+ basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other)+ {+ basic_socket<Protocol, Executor>::operator=(std::move(other));+ return *this;+ }++ /// Move-construct a basic_seq_packet_socket from a socket of another protocol+ /// type.+ /**+ * This constructor moves a sequenced packet socket from one object to+ * another.+ *+ * @param other The other basic_seq_packet_socket 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_seq_packet_socket(const executor_type&)+ * constructor.+ */+ template <typename Protocol1, typename Executor1>+ basic_seq_packet_socket(basic_seq_packet_socket<Protocol1, Executor1>&& other,+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(std::move(other))+ {+ }++ /// Move-assign a basic_seq_packet_socket from a socket of another protocol+ /// type.+ /**+ * This assignment operator moves a sequenced packet socket from one object to+ * another.+ *+ * @param other The other basic_seq_packet_socket 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_seq_packet_socket(const executor_type&)+ * constructor.+ */+ template <typename Protocol1, typename Executor1>+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value,+ basic_seq_packet_socket&+ >::type operator=(basic_seq_packet_socket<Protocol1, Executor1>&& other)+ {+ basic_socket<Protocol, Executor>::operator=(std::move(other));+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destroys the socket.+ /**+ * This function destroys the socket, cancelling any outstanding asynchronous+ * operations associated with the socket as if by calling @c cancel.+ */+ ~basic_seq_packet_socket()+ {+ }++ /// Send some data on the socket.+ /**+ * This function is used to send data on the sequenced packet socket. The+ * function call will block until the data has been sent successfully, or an+ * until error occurs.+ *+ * @param buffers One or more data buffers to be sent on the socket.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @returns The number of bytes sent.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To send a single data buffer use the @ref buffer function as follows:+ * @code+ * socket.send(asio::buffer(data, size), 0);+ * @endcode+ * See the @ref buffer documentation for information on sending multiple+ * buffers in one go, and how to use it with arrays, boost::array or+ * std::vector.+ */+ template <typename ConstBufferSequence>+ std::size_t send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().send(+ this->impl_.get_implementation(), buffers, flags, ec);+ asio::detail::throw_error(ec, "send");+ return s;+ }++ /// Send some data on the socket.+ /**+ * This function is used to send data on the sequenced packet socket. The+ * function call will block the data has been sent successfully, or an until+ * error occurs.+ *+ * @param buffers One or more data buffers to be sent on the socket.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes sent. Returns 0 if an error occurred.+ *+ * @note The send 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 send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ return this->impl_.get_service().send(+ this->impl_.get_implementation(), buffers, flags, ec);+ }++ /// Start an asynchronous send.+ /**+ * This function is used to asynchronously send data on the sequenced packet+ * socket. The function call always returns immediately.+ *+ * @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+ * memory blocks is retained by the caller, which must guarantee that they+ * remain valid until the handler is called.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param handler The handler to be called when the send operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes sent.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To send a single data buffer use the @ref buffer function as follows:+ * @code+ * socket.async_send(asio::buffer(data, size), 0, handler);+ * @endcode+ * See the @ref buffer documentation for information on sending 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)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send(this), handler, buffers, flags);+ }++ /// Receive some data on the socket.+ /**+ * This function is used to receive data on the sequenced packet socket. The+ * function call will block until data has been received successfully, or+ * until an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param out_flags After the receive call completes, contains flags+ * associated with the received data. For example, if the+ * socket_base::message_end_of_record bit is set then the received data marks+ * the end of a record.+ *+ * @returns The number of bytes received.+ *+ * @throws asio::system_error Thrown on failure. An error code of+ * asio::error::eof indicates that the connection was closed by the+ * peer.+ *+ * @par Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * socket.receive(asio::buffer(data, size), out_flags);+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence>+ std::size_t receive(const MutableBufferSequence& buffers,+ socket_base::message_flags& out_flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive_with_flags(+ this->impl_.get_implementation(), buffers, 0, out_flags, ec);+ asio::detail::throw_error(ec, "receive");+ return s;+ }++ /// Receive some data on the socket.+ /**+ * This function is used to receive data on the sequenced packet socket. The+ * function call will block until data has been received successfully, or+ * until an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param in_flags Flags specifying how the receive call is to be made.+ *+ * @param out_flags After the receive call completes, contains flags+ * associated with the received data. For example, if the+ * socket_base::message_end_of_record bit is set then the received data marks+ * the end of a record.+ *+ * @returns The number of bytes received.+ *+ * @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 receive operation may not receive 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 receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * socket.receive(asio::buffer(data, size), 0, out_flags);+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence>+ std::size_t receive(const MutableBufferSequence& buffers,+ socket_base::message_flags in_flags,+ socket_base::message_flags& out_flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive_with_flags(+ this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);+ asio::detail::throw_error(ec, "receive");+ return s;+ }++ /// Receive some data on a connected socket.+ /**+ * This function is used to receive data on the sequenced packet socket. The+ * function call will block until data has been received successfully, or+ * until an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param in_flags Flags specifying how the receive call is to be made.+ *+ * @param out_flags After the receive call completes, contains flags+ * associated with the received data. For example, if the+ * socket_base::message_end_of_record bit is set then the received data marks+ * the end of a record.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes received. Returns 0 if an error occurred.+ *+ * @note The receive operation may not receive 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 receive(const MutableBufferSequence& buffers,+ socket_base::message_flags in_flags,+ socket_base::message_flags& out_flags, asio::error_code& ec)+ {+ return this->impl_.get_service().receive_with_flags(+ this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);+ }++ /// Start an asynchronous receive.+ /**+ * This function is used to asynchronously receive data from the sequenced+ * packet socket. The function call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param out_flags Once the asynchronous operation completes, contains flags+ * associated with the received data. For example, if the+ * 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+ * variable remains valid until the handler is called.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * socket.async_receive(asio::buffer(data, size), out_flags, handler);+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive(const MutableBufferSequence& buffers,+ socket_base::message_flags& out_flags,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive_with_flags(this), handler,+ buffers, socket_base::message_flags(0), &out_flags);+ }++ /// Start an asynchronous receive.+ /**+ * This function is used to asynchronously receive data from the sequenced+ * data socket. The function call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param in_flags Flags specifying how the receive call is to be made.+ *+ * @param out_flags Once the asynchronous operation completes, contains flags+ * associated with the received data. For example, if the+ * 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+ * variable remains valid until the handler is called.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * socket.async_receive(+ * asio::buffer(data, size),+ * 0, out_flags, handler);+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive(const MutableBufferSequence& buffers,+ socket_base::message_flags in_flags,+ socket_base::message_flags& out_flags,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive_with_flags(this),+ handler, buffers, in_flags, &out_flags);+ }++private:+ // Disallow copying and assignment.+ basic_seq_packet_socket(const basic_seq_packet_socket&) ASIO_DELETED;+ basic_seq_packet_socket& operator=(+ const basic_seq_packet_socket&) ASIO_DELETED;++ class initiate_async_send+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_send(basic_seq_packet_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(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)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(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;++ detail::non_const_lvalue<ReadHandler> handler2(handler);+ self_->impl_.get_service().async_receive_with_flags(+ self_->impl_.get_implementation(), buffers, in_flags,+ *out_flags, handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_seq_packet_socket* self_;+ };+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BASIC_SEQ_PACKET_SOCKET_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_serial_port.hpp view
@@ -0,0 +1,907 @@+//+// basic_serial_port.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_SERIAL_PORT_HPP+#define ASIO_BASIC_SERIAL_PORT_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_SERIAL_PORT) \+ || defined(GENERATING_DOCUMENTATION)++#include <string>+#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"+#include "asio/serial_port_base.hpp"+#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_serial_port_service.hpp"+#else+# include "asio/detail/reactive_serial_port_service.hpp"+#endif++#if defined(ASIO_HAS_MOVE)+# include <utility>+#endif // defined(ASIO_HAS_MOVE)++#include "asio/detail/push_options.hpp"++namespace asio {++/// Provides serial port functionality.+/**+ * The basic_serial_port class provides a wrapper over serial port+ * functionality.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename Executor = any_io_executor>+class basic_serial_port+ : public serial_port_base+{+public:+ /// 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::reactive_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.+ /**+ * This constructor creates a serial port without opening it.+ *+ * @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.+ */+ explicit basic_serial_port(const executor_type& ex)+ : impl_(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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value,+ basic_serial_port+ >::type* = 0)+ : impl_(context)+ {+ }++ /// 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 char* device)+ : impl_(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 char* device,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ 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 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_(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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ impl_.get_service().open(impl_.get_implementation(), device, ec);+ asio::detail::throw_error(ec, "open");+ }++ /// 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 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 native_serial_port A native serial port.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_serial_port(const executor_type& ex,+ const native_handle_type& native_serial_port)+ : impl_(ex)+ {+ asio::error_code ec;+ 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(),+ native_serial_port, ec);+ asio::detail::throw_error(ec, "assign");+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a basic_serial_port from another.+ /**+ * 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.+ */+ basic_serial_port(basic_serial_port&& other)+ : impl_(std::move(other.impl_))+ {+ }++ /// Move-assign a basic_serial_port from another.+ /**+ * 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.+ */+ basic_serial_port& operator=(basic_serial_port&& other)+ {+ impl_ = std::move(other.impl_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// 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.+ executor_type get_executor() ASIO_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_serial_port 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_serial_port 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;+ }++ /// Open the serial port using the specified device name.+ /**+ * This function opens the serial port for the specified device name.+ *+ * @param device The platform-specific device name.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void open(const std::string& device)+ {+ asio::error_code ec;+ impl_.get_service().open(impl_.get_implementation(), device, ec);+ asio::detail::throw_error(ec, "open");+ }++ /// Open the serial port using the specified device name.+ /**+ * This function opens the serial port using the given platform-specific+ * device name.+ *+ * @param device The platform-specific device name.+ *+ * @param ec Set the indicate what error occurred, if any.+ */+ ASIO_SYNC_OP_VOID open(const std::string& device,+ asio::error_code& ec)+ {+ impl_.get_service().open(impl_.get_implementation(), device, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Assign an existing native serial port to the serial port.+ /*+ * This function opens the serial port to hold an existing native serial port.+ *+ * @param native_serial_port A native serial port.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void assign(const native_handle_type& native_serial_port)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(),+ native_serial_port, ec);+ asio::detail::throw_error(ec, "assign");+ }++ /// Assign an existing native serial port to the serial port.+ /*+ * This function opens the serial port to hold an existing native serial port.+ *+ * @param native_serial_port A native serial port.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port,+ asio::error_code& ec)+ {+ impl_.get_service().assign(impl_.get_implementation(),+ native_serial_port, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Determine whether the serial port is open.+ bool is_open() const+ {+ return impl_.get_service().is_open(impl_.get_implementation());+ }++ /// Close the serial port.+ /**+ * This function is used to close the serial port. 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.+ */+ void close()+ {+ asio::error_code ec;+ impl_.get_service().close(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "close");+ }++ /// Close the serial port.+ /**+ * This function is used to close the serial port. 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.+ */+ ASIO_SYNC_OP_VOID close(asio::error_code& ec)+ {+ impl_.get_service().close(impl_.get_implementation(), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Get the native serial port representation.+ /**+ * This function may be used to obtain the underlying representation of the+ * serial port. This is intended to allow access to native serial port+ * 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 serial port.+ /**+ * This function causes all outstanding asynchronous read or 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 serial port.+ /**+ * This function causes all outstanding asynchronous read or 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);+ }++ /// Send a break sequence to the serial port.+ /**+ * This function causes a break sequence of platform-specific duration to be+ * sent out the serial port.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void send_break()+ {+ asio::error_code ec;+ impl_.get_service().send_break(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "send_break");+ }++ /// Send a break sequence to the serial port.+ /**+ * This function causes a break sequence of platform-specific duration to be+ * sent out the serial port.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ ASIO_SYNC_OP_VOID send_break(asio::error_code& ec)+ {+ impl_.get_service().send_break(impl_.get_implementation(), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Set an option on the serial port.+ /**+ * This function is used to set an option on the serial port.+ *+ * @param option The option value to be set on the serial port.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @sa SettableSerialPortOption @n+ * asio::serial_port_base::baud_rate @n+ * asio::serial_port_base::flow_control @n+ * asio::serial_port_base::parity @n+ * asio::serial_port_base::stop_bits @n+ * asio::serial_port_base::character_size+ */+ template <typename SettableSerialPortOption>+ void set_option(const SettableSerialPortOption& option)+ {+ asio::error_code ec;+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);+ asio::detail::throw_error(ec, "set_option");+ }++ /// Set an option on the serial port.+ /**+ * This function is used to set an option on the serial port.+ *+ * @param option The option value to be set on the serial port.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @sa SettableSerialPortOption @n+ * asio::serial_port_base::baud_rate @n+ * asio::serial_port_base::flow_control @n+ * asio::serial_port_base::parity @n+ * asio::serial_port_base::stop_bits @n+ * asio::serial_port_base::character_size+ */+ template <typename SettableSerialPortOption>+ ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option,+ asio::error_code& ec)+ {+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Get an option from the serial port.+ /**+ * This function is used to get the current value of an option on the serial+ * port.+ *+ * @param option The option value to be obtained from the serial port.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @sa GettableSerialPortOption @n+ * asio::serial_port_base::baud_rate @n+ * asio::serial_port_base::flow_control @n+ * asio::serial_port_base::parity @n+ * asio::serial_port_base::stop_bits @n+ * asio::serial_port_base::character_size+ */+ template <typename GettableSerialPortOption>+ void get_option(GettableSerialPortOption& option) const+ {+ asio::error_code ec;+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);+ asio::detail::throw_error(ec, "get_option");+ }++ /// Get an option from the serial port.+ /**+ * This function is used to get the current value of an option on the serial+ * port.+ *+ * @param option The option value to be obtained from the serial port.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @sa GettableSerialPortOption @n+ * asio::serial_port_base::baud_rate @n+ * asio::serial_port_base::flow_control @n+ * asio::serial_port_base::parity @n+ * asio::serial_port_base::stop_bits @n+ * asio::serial_port_base::character_size+ */+ template <typename GettableSerialPortOption>+ ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option,+ asio::error_code& ec) const+ {+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Write some data to the serial port.+ /**+ * This function is used to write data to the serial port. 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 serial port.+ *+ * @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+ * basic_serial_port.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 serial port.+ /**+ * This function is used to write data to the serial port. 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 serial port.+ *+ * @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 serial port.+ * The function call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the 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 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().+ *+ * @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+ * basic_serial_port.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)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_write_some(const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_write_some(this), handler, buffers);+ }++ /// Read some data from the serial port.+ /**+ * This function is used to read data from the serial port. 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_serial_port.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 serial port.+ /**+ * This function is used to read data from the serial port. 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 serial port.+ * The function call 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 handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the 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 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().+ *+ * @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_serial_port.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)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_read_some(const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_read_some(this), handler, buffers);+ }++private:+ // Disallow copying and assignment.+ basic_serial_port(const basic_serial_port&) ASIO_DELETED;+ basic_serial_port& operator=(const basic_serial_port&) ASIO_DELETED;++ class initiate_async_write_some+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_write_some(basic_serial_port* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(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)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(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_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::reactive_serial_port_service, Executor> impl_;+#endif+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_SERIAL_PORT)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_BASIC_SERIAL_PORT_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_signal_set.hpp view
@@ -0,0 +1,568 @@+//+// basic_signal_set.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SIGNAL_SET_HPP+#define ASIO_BASIC_SIGNAL_SET_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#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/signal_set_service.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"++namespace asio {++/// Provides signal functionality.+/**+ * The basic_signal_set class provides the ability to perform an asynchronous+ * wait for one or more signals to occur.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Example+ * Performing an asynchronous wait:+ * @code+ * void handler(+ * const asio::error_code& error,+ * int signal_number)+ * {+ * if (!error)+ * {+ * // A signal occurred.+ * }+ * }+ *+ * ...+ *+ * // Construct a signal set registered for process termination.+ * asio::signal_set signals(my_context, SIGINT, SIGTERM);+ *+ * // Start an asynchronous wait for one of the signals to occur.+ * signals.async_wait(handler);+ * @endcode+ *+ * @par Queueing of signal notifications+ *+ * If a signal is registered with a signal_set, and the signal occurs when+ * there are no waiting handlers, then the signal notification is queued. The+ * next async_wait operation on that signal_set will dequeue the notification.+ * If multiple notifications are queued, subsequent async_wait operations+ * dequeue them one at a time. Signal notifications are dequeued in order of+ * ascending signal number.+ *+ * If a signal number is removed from a signal_set (using the @c remove or @c+ * erase member functions) then any queued notifications for that signal are+ * discarded.+ *+ * @par Multiple registration of signals+ *+ * The same signal number may be registered with different signal_set objects.+ * When the signal occurs, one handler is called for each signal_set object.+ *+ * Note that multiple registration only works for signals that are registered+ * using Asio. The application must not also register a signal handler using+ * functions such as @c signal() or @c sigaction().+ *+ * @par Signal masking on POSIX platforms+ *+ * POSIX allows signals to be blocked using functions such as @c sigprocmask()+ * and @c pthread_sigmask(). For signals to be delivered, programs must ensure+ * that any signals registered using signal_set objects are unblocked in at+ * least one thread.+ */+template <typename Executor = any_io_executor>+class basic_signal_set+{+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.+ /**+ * This constructor creates a signal set without registering for any signals.+ *+ * @param ex The I/O executor that the signal set will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * signal set.+ */+ explicit basic_signal_set(const executor_type& ex)+ : impl_(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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ }++ /// Construct a signal set and add one signal.+ /**+ * This constructor creates a signal set and registers for one signal.+ *+ * @param ex 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(ex);+ * signals.add(signal_number_1); @endcode+ */+ basic_signal_set(const executor_type& ex, int signal_number_1)+ : impl_(ex)+ {+ asio::error_code 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ impl_.get_service().add(impl_.get_implementation(), signal_number_1, 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 ex 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(ex);+ * signals.add(signal_number_1);+ * signals.add(signal_number_2); @endcode+ */+ basic_signal_set(const executor_type& ex, int signal_number_1,+ int signal_number_2)+ : impl_(ex)+ {+ 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");+ }++ /// 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(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");+ }++ /// Construct a signal set and add three signals.+ /**+ * This constructor creates a signal set and registers for three signals.+ *+ * @param ex 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(ex);+ * signals.add(signal_number_1);+ * signals.add(signal_number_2);+ * signals.add(signal_number_3); @endcode+ */+ basic_signal_set(const executor_type& ex, int signal_number_1,+ int signal_number_2, int signal_number_3)+ : impl_(ex)+ {+ 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");+ }++ /// 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(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.+ executor_type get_executor() ASIO_NOEXCEPT+ {+ return impl_.get_executor();+ }++ /// Add a signal to a signal_set.+ /**+ * This function adds the specified signal to the set. It has no effect if the+ * signal is already in the set.+ *+ * @param signal_number The signal to be added to the set.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void add(int signal_number)+ {+ asio::error_code ec;+ impl_.get_service().add(impl_.get_implementation(), signal_number, ec);+ asio::detail::throw_error(ec, "add");+ }++ /// Add a signal to a signal_set.+ /**+ * This function adds the specified signal to the set. It has no effect if the+ * signal is already in the set.+ *+ * @param signal_number The signal to be added to the set.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ ASIO_SYNC_OP_VOID add(int signal_number,+ asio::error_code& ec)+ {+ impl_.get_service().add(impl_.get_implementation(), signal_number, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Remove a signal from a signal_set.+ /**+ * This function removes the specified signal from the set. It has no effect+ * if the signal is not in the set.+ *+ * @param signal_number The signal to be removed from the set.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Removes any notifications that have been queued for the specified+ * signal number.+ */+ void remove(int signal_number)+ {+ asio::error_code ec;+ impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);+ asio::detail::throw_error(ec, "remove");+ }++ /// Remove a signal from a signal_set.+ /**+ * This function removes the specified signal from the set. It has no effect+ * if the signal is not in the set.+ *+ * @param signal_number The signal to be removed from the set.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Removes any notifications that have been queued for the specified+ * signal number.+ */+ ASIO_SYNC_OP_VOID remove(int signal_number,+ asio::error_code& ec)+ {+ impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Remove all signals from a signal_set.+ /**+ * This function removes all signals from the set. It has no effect if the set+ * is already empty.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Removes all queued notifications.+ */+ void clear()+ {+ asio::error_code ec;+ impl_.get_service().clear(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "clear");+ }++ /// Remove all signals from a signal_set.+ /**+ * This function removes all signals from the set. It has no effect if the set+ * is already empty.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Removes all queued notifications.+ */+ ASIO_SYNC_OP_VOID clear(asio::error_code& ec)+ {+ impl_.get_service().clear(impl_.get_implementation(), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Cancel all operations associated with the signal set.+ /**+ * This function forces the completion of any pending asynchronous wait+ * operations against the signal set. The handler for each cancelled+ * operation will be invoked with the asio::error::operation_aborted+ * error code.+ *+ * Cancellation does not alter the set of registered signals.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note If a registered signal occurred before cancel() is called, then the+ * handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ void cancel()+ {+ asio::error_code ec;+ impl_.get_service().cancel(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "cancel");+ }++ /// Cancel all operations associated with the signal set.+ /**+ * This function forces the completion of any pending asynchronous wait+ * operations against the signal set. The handler for each cancelled+ * operation will be invoked with the asio::error::operation_aborted+ * error code.+ *+ * Cancellation does not alter the set of registered signals.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note If a registered signal occurred before cancel() is called, then the+ * handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)+ {+ impl_.get_service().cancel(impl_.get_implementation(), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Start an asynchronous operation to wait for a signal to be delivered.+ /**+ * This function may be used to initiate an asynchronous wait against the+ * signal set. It always returns immediately.+ *+ * For each call to async_wait(), the supplied handler will be called exactly+ * once. The handler will be called when:+ *+ * @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+ * error code asio::error::operation_aborted.+ *+ * @param handler The handler to be called when the signal occurs. Copies+ * will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * int signal_number // Indicates which signal occurred.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, int))+ SignalHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(SignalHandler,+ void (asio::error_code, int))+ async_wait(+ ASIO_MOVE_ARG(SignalHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<SignalHandler, void (asio::error_code, int)>(+ initiate_async_wait(this), handler);+ }++private:+ // Disallow copying and assignment.+ basic_signal_set(const basic_signal_set&) ASIO_DELETED;+ basic_signal_set& operator=(const basic_signal_set&) ASIO_DELETED;++ class initiate_async_wait+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_wait(basic_signal_set* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename SignalHandler>+ void operator()(ASIO_MOVE_ARG(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;++ detail::non_const_lvalue<SignalHandler> handler2(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++#endif // ASIO_BASIC_SIGNAL_SET_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_socket.hpp view
@@ -0,0 +1,1894 @@+//+// basic_socket.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_HPP+#define ASIO_BASIC_SOCKET_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/any_io_executor.hpp"+#include "asio/detail/config.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"+#include "asio/post.hpp"+#include "asio/socket_base.hpp"++#if defined(ASIO_WINDOWS_RUNTIME)+# include "asio/detail/null_socket_service.hpp"+#elif defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_socket_service.hpp"+#else+# include "asio/detail/reactive_socket_service.hpp"+#endif++#if defined(ASIO_HAS_MOVE)+# include <utility>+#endif // defined(ASIO_HAS_MOVE)++#include "asio/detail/push_options.hpp"++namespace asio {++#if !defined(ASIO_BASIC_SOCKET_FWD_DECL)+#define ASIO_BASIC_SOCKET_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename Protocol, typename Executor = any_io_executor>+class basic_socket;++#endif // !defined(ASIO_BASIC_SOCKET_FWD_DECL)++/// Provides socket functionality.+/**+ * The basic_socket class template provides functionality that is common to both+ * stream-oriented and datagram-oriented sockets.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename Protocol, typename Executor>+class basic_socket+ : public socket_base+{+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_socket<Protocol, Executor1> other;+ };++ /// The native representation of a socket.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined native_handle_type;+#elif defined(ASIO_WINDOWS_RUNTIME)+ typedef typename detail::null_socket_service<+ Protocol>::native_handle_type native_handle_type;+#elif defined(ASIO_HAS_IOCP)+ typedef typename detail::win_iocp_socket_service<+ Protocol>::native_handle_type native_handle_type;+#else+ typedef typename detail::reactive_socket_service<+ Protocol>::native_handle_type native_handle_type;+#endif++ /// The protocol type.+ typedef Protocol protocol_type;++ /// The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++#if !defined(ASIO_NO_EXTENSIONS)+ /// A basic_socket is always the lowest layer.+ typedef basic_socket<Protocol, Executor> lowest_layer_type;+#endif // !defined(ASIO_NO_EXTENSIONS)++ /// Construct a basic_socket without opening it.+ /**+ * This constructor creates a socket without opening it.+ *+ * @param ex The I/O executor that the socket will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the socket.+ */+ explicit basic_socket(const executor_type& ex)+ : impl_(ex)+ {+ }++ /// Construct a basic_socket without opening it.+ /**+ * This constructor creates a socket without opening 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_socket(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ }++ /// Construct and open a basic_socket.+ /**+ * This constructor creates and opens a socket.+ *+ * @param ex 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.+ */+ basic_socket(const executor_type& ex, const protocol_type& protocol)+ : impl_(ex)+ {+ asio::error_code ec;+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ asio::detail::throw_error(ec, "open");+ }++ /// Construct and open a basic_socket.+ /**+ * This constructor creates and opens a 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.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_socket(ExecutionContext& context, const protocol_type& protocol,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ asio::detail::throw_error(ec, "open");+ }++ /// Construct a basic_socket, opening it and binding it to the given local+ /// endpoint.+ /**+ * This constructor creates a 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 ex 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 socket will+ * be bound.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_socket(const executor_type& ex, const endpoint_type& endpoint)+ : impl_(ex)+ {+ asio::error_code ec;+ const protocol_type protocol = endpoint.protocol();+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ asio::detail::throw_error(ec, "open");+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);+ asio::detail::throw_error(ec, "bind");+ }++ /// Construct a basic_socket, opening it and binding it to the given local+ /// endpoint.+ /**+ * This constructor creates a 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 socket will+ * be bound.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_socket(ExecutionContext& context, const endpoint_type& endpoint,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ const protocol_type protocol = endpoint.protocol();+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ asio::detail::throw_error(ec, "open");+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);+ asio::detail::throw_error(ec, "bind");+ }++ /// Construct a basic_socket on an existing native socket.+ /**+ * This constructor creates a socket object to hold an existing native socket.+ *+ * @param ex 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 A native socket.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_socket(const executor_type& ex, const protocol_type& protocol,+ const native_handle_type& native_socket)+ : impl_(ex)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(),+ protocol, native_socket, ec);+ asio::detail::throw_error(ec, "assign");+ }++ /// Construct a basic_socket on an existing native socket.+ /**+ * This constructor creates a 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 A native socket.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_socket(ExecutionContext& context, const protocol_type& protocol,+ const native_handle_type& native_socket,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(),+ protocol, native_socket, ec);+ asio::detail::throw_error(ec, "assign");+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a basic_socket from another.+ /**+ * This constructor moves a socket from one object to another.+ *+ * @param other The other basic_socket 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_socket(const executor_type&) constructor.+ */+ basic_socket(basic_socket&& other) ASIO_NOEXCEPT+ : impl_(std::move(other.impl_))+ {+ }++ /// Move-assign a basic_socket from another.+ /**+ * This assignment operator moves a socket from one object to another.+ *+ * @param other The other basic_socket 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_socket(const executor_type&) constructor.+ */+ basic_socket& operator=(basic_socket&& other)+ {+ impl_ = std::move(other.impl_);+ return *this;+ }++ // All sockets have access to each other's implementations.+ template <typename Protocol1, typename Executor1>+ friend class basic_socket;++ /// Move-construct a basic_socket from a socket of another protocol type.+ /**+ * This constructor moves a socket from one object to another.+ *+ * @param other The other basic_socket 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_socket(const executor_type&) constructor.+ */+ template <typename Protocol1, typename Executor1>+ basic_socket(basic_socket<Protocol1, Executor1>&& other,+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value+ >::type* = 0)+ : impl_(std::move(other.impl_))+ {+ }++ /// Move-assign a basic_socket from a socket of another protocol type.+ /**+ * This assignment operator moves a socket from one object to another.+ *+ * @param other The other basic_socket 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_socket(const executor_type&) constructor.+ */+ template <typename Protocol1, typename Executor1>+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value,+ basic_socket&+ >::type operator=(basic_socket<Protocol1, Executor1> && other)+ {+ basic_socket tmp(std::move(other));+ impl_ = std::move(tmp.impl_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_NOEXCEPT+ {+ return impl_.get_executor();+ }++#if !defined(ASIO_NO_EXTENSIONS)+ /// Get a reference to the lowest layer.+ /**+ * This function returns a reference to the lowest layer in a stack of+ * layers. Since a basic_socket 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_socket 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;+ }+#endif // !defined(ASIO_NO_EXTENSIONS)++ /// Open the socket using the specified protocol.+ /**+ * This function opens the socket so that it will use the specified protocol.+ *+ * @param protocol An object specifying protocol parameters to be used.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * socket.open(asio::ip::tcp::v4());+ * @endcode+ */+ void open(const protocol_type& protocol = protocol_type())+ {+ asio::error_code ec;+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ asio::detail::throw_error(ec, "open");+ }++ /// Open the socket using the specified protocol.+ /**+ * This function opens the socket so that it will use the specified protocol.+ *+ * @param protocol An object specifying which protocol is to be used.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * asio::error_code ec;+ * socket.open(asio::ip::tcp::v4(), ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ ASIO_SYNC_OP_VOID open(const protocol_type& protocol,+ asio::error_code& ec)+ {+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Assign an existing native socket to the socket.+ /*+ * This function opens the socket to hold an existing native socket.+ *+ * @param protocol An object specifying which protocol is to be used.+ *+ * @param native_socket A native socket.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void assign(const protocol_type& protocol,+ const native_handle_type& native_socket)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(),+ protocol, native_socket, ec);+ asio::detail::throw_error(ec, "assign");+ }++ /// Assign an existing native socket to the socket.+ /*+ * This function opens the socket to hold an existing native socket.+ *+ * @param protocol An object specifying which protocol is to be used.+ *+ * @param native_socket A native socket.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ ASIO_SYNC_OP_VOID assign(const protocol_type& protocol,+ const native_handle_type& native_socket, asio::error_code& ec)+ {+ impl_.get_service().assign(impl_.get_implementation(),+ protocol, native_socket, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Determine whether the socket is open.+ bool is_open() const+ {+ return impl_.get_service().is_open(impl_.get_implementation());+ }++ /// Close the socket.+ /**+ * This function is used to close the socket. Any asynchronous send, receive+ * or connect 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.+ *+ * @note For portable behaviour with respect to graceful closure of a+ * connected socket, call shutdown() before closing the socket.+ */+ void close()+ {+ asio::error_code ec;+ impl_.get_service().close(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "close");+ }++ /// Close the socket.+ /**+ * This function is used to close the socket. Any asynchronous send, receive+ * or connect 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::ip::tcp::socket socket(my_context);+ * ...+ * asio::error_code ec;+ * socket.close(ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ *+ * @note For portable behaviour with respect to graceful closure of a+ * connected socket, call shutdown() before closing the socket.+ */+ 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 socket.+ /**+ * This function causes all outstanding asynchronous connect, send and receive+ * operations to finish immediately, and the handlers for cancelled operations+ * will be passed the asio::error::operation_aborted error. Ownership+ * of the native socket 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 socket.+ /**+ * This function causes all outstanding asynchronous connect, send and receive+ * operations to finish immediately, and the handlers for cancelled operations+ * will be passed the asio::error::operation_aborted error. Ownership+ * of the native socket 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 socket representation.+ /**+ * This function may be used to obtain the underlying representation of the+ * socket. This is intended to allow access to native socket 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 socket.+ /**+ * This function causes all outstanding asynchronous connect, send and receive+ * 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 one of the following+ * alternatives:+ *+ * @li Disable asio's I/O completion port backend by defining+ * ASIO_DISABLE_IOCP.+ *+ * @li Use the close() function to simultaneously cancel the outstanding+ * operations and close the socket.+ *+ * 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 socket.+ /**+ * This function causes all outstanding asynchronous connect, send and receive+ * 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 one of the following+ * alternatives:+ *+ * @li Disable asio's I/O completion port backend by defining+ * ASIO_DISABLE_IOCP.+ *+ * @li Use the close() function to simultaneously cancel the outstanding+ * operations and close the socket.+ *+ * 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);+ }++ /// Determine whether the socket is at the out-of-band data mark.+ /**+ * This function is used to check whether the socket input is currently+ * positioned at the out-of-band data mark.+ *+ * @return A bool indicating whether the socket is at the out-of-band data+ * mark.+ *+ * @throws asio::system_error Thrown on failure.+ */+ bool at_mark() const+ {+ asio::error_code ec;+ bool b = impl_.get_service().at_mark(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "at_mark");+ return b;+ }++ /// Determine whether the socket is at the out-of-band data mark.+ /**+ * This function is used to check whether the socket input is currently+ * positioned at the out-of-band data mark.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return A bool indicating whether the socket is at the out-of-band data+ * mark.+ */+ bool at_mark(asio::error_code& ec) const+ {+ return impl_.get_service().at_mark(impl_.get_implementation(), ec);+ }++ /// Determine the number of bytes available for reading.+ /**+ * This function is used to determine the number of bytes that may be read+ * without blocking.+ *+ * @return The number of bytes that may be read without blocking, or 0 if an+ * error occurs.+ *+ * @throws asio::system_error Thrown on failure.+ */+ std::size_t available() const+ {+ asio::error_code ec;+ std::size_t s = impl_.get_service().available(+ impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "available");+ return s;+ }++ /// Determine the number of bytes available for reading.+ /**+ * This function is used to determine the number of bytes that may be read+ * without blocking.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of bytes that may be read without blocking, or 0 if an+ * error occurs.+ */+ std::size_t available(asio::error_code& ec) const+ {+ return impl_.get_service().available(impl_.get_implementation(), ec);+ }++ /// Bind the socket to the given local endpoint.+ /**+ * This function binds the socket to the specified endpoint on the local+ * machine.+ *+ * @param endpoint An endpoint on the local machine to which the socket will+ * be bound.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * socket.open(asio::ip::tcp::v4());+ * socket.bind(asio::ip::tcp::endpoint(+ * asio::ip::tcp::v4(), 12345));+ * @endcode+ */+ void bind(const endpoint_type& endpoint)+ {+ asio::error_code ec;+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);+ asio::detail::throw_error(ec, "bind");+ }++ /// Bind the socket to the given local endpoint.+ /**+ * This function binds the socket to the specified endpoint on the local+ * machine.+ *+ * @param endpoint An endpoint on the local machine to which the socket will+ * be bound.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * socket.open(asio::ip::tcp::v4());+ * asio::error_code ec;+ * socket.bind(asio::ip::tcp::endpoint(+ * asio::ip::tcp::v4(), 12345), ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint,+ asio::error_code& ec)+ {+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Connect the socket to the specified endpoint.+ /**+ * This function is used to connect a socket to the specified remote endpoint.+ * The function call will block until the connection is successfully made or+ * an error occurs.+ *+ * The socket is automatically opened if it is not already open. If the+ * connect fails, and the socket was automatically opened, the socket is+ * not returned to the closed state.+ *+ * @param peer_endpoint The remote endpoint to which the socket will be+ * connected.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * asio::ip::tcp::endpoint endpoint(+ * asio::ip::address::from_string("1.2.3.4"), 12345);+ * socket.connect(endpoint);+ * @endcode+ */+ void connect(const endpoint_type& peer_endpoint)+ {+ asio::error_code ec;+ if (!is_open())+ {+ impl_.get_service().open(impl_.get_implementation(),+ peer_endpoint.protocol(), ec);+ asio::detail::throw_error(ec, "connect");+ }+ impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec);+ asio::detail::throw_error(ec, "connect");+ }++ /// Connect the socket to the specified endpoint.+ /**+ * This function is used to connect a socket to the specified remote endpoint.+ * The function call will block until the connection is successfully made or+ * an error occurs.+ *+ * The socket is automatically opened if it is not already open. If the+ * connect fails, and the socket was automatically opened, the socket is+ * not returned to the closed state.+ *+ * @param peer_endpoint The remote endpoint to which the socket will be+ * connected.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * asio::ip::tcp::endpoint endpoint(+ * asio::ip::address::from_string("1.2.3.4"), 12345);+ * asio::error_code ec;+ * socket.connect(endpoint, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ ASIO_SYNC_OP_VOID connect(const endpoint_type& peer_endpoint,+ asio::error_code& ec)+ {+ if (!is_open())+ {+ impl_.get_service().open(impl_.get_implementation(),+ peer_endpoint.protocol(), ec);+ if (ec)+ {+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }++ impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Start an asynchronous connect.+ /**+ * This function is used to asynchronously connect a socket to the specified+ * remote endpoint. The function call always returns immediately.+ *+ * The socket is automatically opened if it is not already open. If the+ * connect fails, and the socket was automatically opened, the socket is+ * not returned to the closed state.+ *+ * @param peer_endpoint The remote endpoint to which the socket will be+ * connected. Copies will be made of the endpoint object as required.+ *+ * @param handler The handler to be called when the connection operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error // Result of operation+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code+ * void connect_handler(const asio::error_code& error)+ * {+ * if (!error)+ * {+ * // Connect succeeded.+ * }+ * }+ *+ * ...+ *+ * asio::ip::tcp::socket socket(my_context);+ * asio::ip::tcp::endpoint endpoint(+ * asio::ip::address::from_string("1.2.3.4"), 12345);+ * socket.async_connect(endpoint, connect_handler);+ * @endcode+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))+ ConnectHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ConnectHandler,+ void (asio::error_code))+ async_connect(const endpoint_type& peer_endpoint,+ ASIO_MOVE_ARG(ConnectHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ asio::error_code open_ec;+ if (!is_open())+ {+ const protocol_type protocol = peer_endpoint.protocol();+ impl_.get_service().open(impl_.get_implementation(), protocol, open_ec);+ }++ return async_initiate<ConnectHandler, void (asio::error_code)>(+ initiate_async_connect(this), handler, peer_endpoint, open_ec);+ }++ /// Set an option on the socket.+ /**+ * This function is used to set an option on the socket.+ *+ * @param option The new option value to be set on the socket.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @sa SettableSocketOption @n+ * asio::socket_base::broadcast @n+ * asio::socket_base::do_not_route @n+ * asio::socket_base::keep_alive @n+ * asio::socket_base::linger @n+ * asio::socket_base::receive_buffer_size @n+ * asio::socket_base::receive_low_watermark @n+ * asio::socket_base::reuse_address @n+ * asio::socket_base::send_buffer_size @n+ * asio::socket_base::send_low_watermark @n+ * asio::ip::multicast::join_group @n+ * asio::ip::multicast::leave_group @n+ * asio::ip::multicast::enable_loopback @n+ * asio::ip::multicast::outbound_interface @n+ * asio::ip::multicast::hops @n+ * asio::ip::tcp::no_delay+ *+ * @par Example+ * Setting the IPPROTO_TCP/TCP_NODELAY option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::tcp::no_delay option(true);+ * socket.set_option(option);+ * @endcode+ */+ template <typename SettableSocketOption>+ void set_option(const SettableSocketOption& option)+ {+ asio::error_code ec;+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);+ asio::detail::throw_error(ec, "set_option");+ }++ /// Set an option on the socket.+ /**+ * This function is used to set an option on the socket.+ *+ * @param option The new option value to be set on the socket.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @sa SettableSocketOption @n+ * asio::socket_base::broadcast @n+ * asio::socket_base::do_not_route @n+ * asio::socket_base::keep_alive @n+ * asio::socket_base::linger @n+ * asio::socket_base::receive_buffer_size @n+ * asio::socket_base::receive_low_watermark @n+ * asio::socket_base::reuse_address @n+ * asio::socket_base::send_buffer_size @n+ * asio::socket_base::send_low_watermark @n+ * asio::ip::multicast::join_group @n+ * asio::ip::multicast::leave_group @n+ * asio::ip::multicast::enable_loopback @n+ * asio::ip::multicast::outbound_interface @n+ * asio::ip::multicast::hops @n+ * asio::ip::tcp::no_delay+ *+ * @par Example+ * Setting the IPPROTO_TCP/TCP_NODELAY option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::tcp::no_delay option(true);+ * asio::error_code ec;+ * socket.set_option(option, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ template <typename SettableSocketOption>+ ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option,+ asio::error_code& ec)+ {+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Get an option from the socket.+ /**+ * This function is used to get the current value of an option on the socket.+ *+ * @param option The option value to be obtained from the socket.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @sa GettableSocketOption @n+ * asio::socket_base::broadcast @n+ * asio::socket_base::do_not_route @n+ * asio::socket_base::keep_alive @n+ * asio::socket_base::linger @n+ * asio::socket_base::receive_buffer_size @n+ * asio::socket_base::receive_low_watermark @n+ * asio::socket_base::reuse_address @n+ * asio::socket_base::send_buffer_size @n+ * asio::socket_base::send_low_watermark @n+ * asio::ip::multicast::join_group @n+ * asio::ip::multicast::leave_group @n+ * asio::ip::multicast::enable_loopback @n+ * asio::ip::multicast::outbound_interface @n+ * asio::ip::multicast::hops @n+ * asio::ip::tcp::no_delay+ *+ * @par Example+ * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::tcp::socket::keep_alive option;+ * socket.get_option(option);+ * bool is_set = option.value();+ * @endcode+ */+ template <typename GettableSocketOption>+ void get_option(GettableSocketOption& option) const+ {+ asio::error_code ec;+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);+ asio::detail::throw_error(ec, "get_option");+ }++ /// Get an option from the socket.+ /**+ * This function is used to get the current value of an option on the socket.+ *+ * @param option The option value to be obtained from the socket.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @sa GettableSocketOption @n+ * asio::socket_base::broadcast @n+ * asio::socket_base::do_not_route @n+ * asio::socket_base::keep_alive @n+ * asio::socket_base::linger @n+ * asio::socket_base::receive_buffer_size @n+ * asio::socket_base::receive_low_watermark @n+ * asio::socket_base::reuse_address @n+ * asio::socket_base::send_buffer_size @n+ * asio::socket_base::send_low_watermark @n+ * asio::ip::multicast::join_group @n+ * asio::ip::multicast::leave_group @n+ * asio::ip::multicast::enable_loopback @n+ * asio::ip::multicast::outbound_interface @n+ * asio::ip::multicast::hops @n+ * asio::ip::tcp::no_delay+ *+ * @par Example+ * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::tcp::socket::keep_alive option;+ * asio::error_code ec;+ * socket.get_option(option, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * bool is_set = option.value();+ * @endcode+ */+ template <typename GettableSocketOption>+ ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option,+ asio::error_code& ec) const+ {+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Perform an IO control command on the socket.+ /**+ * This function is used to execute an IO control command on the socket.+ *+ * @param command The IO control command to be performed on the socket.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @sa IoControlCommand @n+ * asio::socket_base::bytes_readable @n+ * asio::socket_base::non_blocking_io+ *+ * @par Example+ * Getting the number of bytes ready to read:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::tcp::socket::bytes_readable command;+ * socket.io_control(command);+ * std::size_t bytes_readable = command.get();+ * @endcode+ */+ template <typename IoControlCommand>+ void io_control(IoControlCommand& command)+ {+ asio::error_code ec;+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);+ asio::detail::throw_error(ec, "io_control");+ }++ /// Perform an IO control command on the socket.+ /**+ * This function is used to execute an IO control command on the socket.+ *+ * @param command The IO control command to be performed on the socket.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @sa IoControlCommand @n+ * asio::socket_base::bytes_readable @n+ * asio::socket_base::non_blocking_io+ *+ * @par Example+ * Getting the number of bytes ready to read:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::tcp::socket::bytes_readable command;+ * asio::error_code ec;+ * socket.io_control(command, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * std::size_t bytes_readable = command.get();+ * @endcode+ */+ template <typename IoControlCommand>+ ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,+ asio::error_code& ec)+ {+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Gets the non-blocking mode of the socket.+ /**+ * @returns @c true if the socket's synchronous operations will fail with+ * asio::error::would_block if they are unable to perform the requested+ * operation immediately. If @c false, synchronous operations will block+ * until complete.+ *+ * @note The non-blocking mode has no effect on the behaviour of asynchronous+ * operations. Asynchronous operations will never fail with the error+ * asio::error::would_block.+ */+ bool non_blocking() const+ {+ return impl_.get_service().non_blocking(impl_.get_implementation());+ }++ /// Sets the non-blocking mode of the socket.+ /**+ * @param mode If @c true, the socket's synchronous operations will fail with+ * asio::error::would_block if they are unable to perform the requested+ * operation immediately. If @c false, synchronous operations will block+ * until complete.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The non-blocking mode has no effect on the behaviour of asynchronous+ * operations. Asynchronous operations will never fail with the error+ * asio::error::would_block.+ */+ void non_blocking(bool mode)+ {+ asio::error_code ec;+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);+ asio::detail::throw_error(ec, "non_blocking");+ }++ /// Sets the non-blocking mode of the socket.+ /**+ * @param mode If @c true, the socket's synchronous operations will fail with+ * asio::error::would_block if they are unable to perform the requested+ * operation immediately. If @c false, synchronous operations will block+ * until complete.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note The non-blocking mode has no effect on the behaviour of asynchronous+ * operations. Asynchronous operations will never fail with the error+ * asio::error::would_block.+ */+ ASIO_SYNC_OP_VOID non_blocking(+ bool mode, asio::error_code& ec)+ {+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Gets the non-blocking mode of the native socket implementation.+ /**+ * This function is used to retrieve the non-blocking mode of the underlying+ * native socket. This mode has no effect on the behaviour of the socket+ * object's synchronous operations.+ *+ * @returns @c true if the underlying socket is in non-blocking mode and+ * direct system calls may fail with asio::error::would_block (or the+ * equivalent system error).+ *+ * @note The current non-blocking mode is cached by the socket object.+ * Consequently, the return value may be incorrect if the non-blocking mode+ * was set directly on the native socket.+ *+ * @par Example+ * This function is intended to allow the encapsulation of arbitrary+ * non-blocking system calls as asynchronous operations, in a way that is+ * transparent to the user of the socket object. The following example+ * illustrates how Linux's @c sendfile system call might be encapsulated:+ * @code template <typename Handler>+ * struct sendfile_op+ * {+ * tcp::socket& sock_;+ * int fd_;+ * Handler handler_;+ * off_t offset_;+ * std::size_t total_bytes_transferred_;+ *+ * // Function call operator meeting WriteHandler requirements.+ * // Used as the handler for the async_write_some operation.+ * void operator()(asio::error_code ec, std::size_t)+ * {+ * // Put the underlying socket into non-blocking mode.+ * if (!ec)+ * if (!sock_.native_non_blocking())+ * sock_.native_non_blocking(true, ec);+ *+ * if (!ec)+ * {+ * for (;;)+ * {+ * // Try the system call.+ * errno = 0;+ * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);+ * ec = asio::error_code(n < 0 ? errno : 0,+ * asio::error::get_system_category());+ * total_bytes_transferred_ += ec ? 0 : n;+ *+ * // Retry operation immediately if interrupted by signal.+ * if (ec == asio::error::interrupted)+ * continue;+ *+ * // Check if we need to run the operation again.+ * if (ec == asio::error::would_block+ * || ec == asio::error::try_again)+ * {+ * // We have to wait for the socket to become ready again.+ * sock_.async_wait(tcp::socket::wait_write, *this);+ * return;+ * }+ *+ * if (ec || n == 0)+ * {+ * // An error occurred, or we have reached the end of the file.+ * // Either way we must exit the loop so we can call the handler.+ * break;+ * }+ *+ * // Loop around to try calling sendfile again.+ * }+ * }+ *+ * // Pass result back to user's handler.+ * handler_(ec, total_bytes_transferred_);+ * }+ * };+ *+ * template <typename Handler>+ * void async_sendfile(tcp::socket& sock, int fd, Handler h)+ * {+ * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };+ * sock.async_wait(tcp::socket::wait_write, op);+ * } @endcode+ */+ bool native_non_blocking() const+ {+ return impl_.get_service().native_non_blocking(impl_.get_implementation());+ }++ /// Sets the non-blocking mode of the native socket implementation.+ /**+ * This function is used to modify the non-blocking mode of the underlying+ * native socket. It has no effect on the behaviour of the socket object's+ * synchronous operations.+ *+ * @param mode If @c true, the underlying socket is put into non-blocking+ * mode and direct system calls may fail with asio::error::would_block+ * (or the equivalent system error).+ *+ * @throws asio::system_error Thrown on failure. If the @c mode is+ * @c false, but the current value of @c non_blocking() is @c true, this+ * function fails with asio::error::invalid_argument, as the+ * combination does not make sense.+ *+ * @par Example+ * This function is intended to allow the encapsulation of arbitrary+ * non-blocking system calls as asynchronous operations, in a way that is+ * transparent to the user of the socket object. The following example+ * illustrates how Linux's @c sendfile system call might be encapsulated:+ * @code template <typename Handler>+ * struct sendfile_op+ * {+ * tcp::socket& sock_;+ * int fd_;+ * Handler handler_;+ * off_t offset_;+ * std::size_t total_bytes_transferred_;+ *+ * // Function call operator meeting WriteHandler requirements.+ * // Used as the handler for the async_write_some operation.+ * void operator()(asio::error_code ec, std::size_t)+ * {+ * // Put the underlying socket into non-blocking mode.+ * if (!ec)+ * if (!sock_.native_non_blocking())+ * sock_.native_non_blocking(true, ec);+ *+ * if (!ec)+ * {+ * for (;;)+ * {+ * // Try the system call.+ * errno = 0;+ * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);+ * ec = asio::error_code(n < 0 ? errno : 0,+ * asio::error::get_system_category());+ * total_bytes_transferred_ += ec ? 0 : n;+ *+ * // Retry operation immediately if interrupted by signal.+ * if (ec == asio::error::interrupted)+ * continue;+ *+ * // Check if we need to run the operation again.+ * if (ec == asio::error::would_block+ * || ec == asio::error::try_again)+ * {+ * // We have to wait for the socket to become ready again.+ * sock_.async_wait(tcp::socket::wait_write, *this);+ * return;+ * }+ *+ * if (ec || n == 0)+ * {+ * // An error occurred, or we have reached the end of the file.+ * // Either way we must exit the loop so we can call the handler.+ * break;+ * }+ *+ * // Loop around to try calling sendfile again.+ * }+ * }+ *+ * // Pass result back to user's handler.+ * handler_(ec, total_bytes_transferred_);+ * }+ * };+ *+ * template <typename Handler>+ * void async_sendfile(tcp::socket& sock, int fd, Handler h)+ * {+ * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };+ * sock.async_wait(tcp::socket::wait_write, op);+ * } @endcode+ */+ void native_non_blocking(bool mode)+ {+ asio::error_code ec;+ impl_.get_service().native_non_blocking(+ impl_.get_implementation(), mode, ec);+ asio::detail::throw_error(ec, "native_non_blocking");+ }++ /// Sets the non-blocking mode of the native socket implementation.+ /**+ * This function is used to modify the non-blocking mode of the underlying+ * native socket. It has no effect on the behaviour of the socket object's+ * synchronous operations.+ *+ * @param mode If @c true, the underlying socket is put into non-blocking+ * mode and direct system calls may fail with asio::error::would_block+ * (or the equivalent system error).+ *+ * @param ec Set to indicate what error occurred, if any. If the @c mode is+ * @c false, but the current value of @c non_blocking() is @c true, this+ * function fails with asio::error::invalid_argument, as the+ * combination does not make sense.+ *+ * @par Example+ * This function is intended to allow the encapsulation of arbitrary+ * non-blocking system calls as asynchronous operations, in a way that is+ * transparent to the user of the socket object. The following example+ * illustrates how Linux's @c sendfile system call might be encapsulated:+ * @code template <typename Handler>+ * struct sendfile_op+ * {+ * tcp::socket& sock_;+ * int fd_;+ * Handler handler_;+ * off_t offset_;+ * std::size_t total_bytes_transferred_;+ *+ * // Function call operator meeting WriteHandler requirements.+ * // Used as the handler for the async_write_some operation.+ * void operator()(asio::error_code ec, std::size_t)+ * {+ * // Put the underlying socket into non-blocking mode.+ * if (!ec)+ * if (!sock_.native_non_blocking())+ * sock_.native_non_blocking(true, ec);+ *+ * if (!ec)+ * {+ * for (;;)+ * {+ * // Try the system call.+ * errno = 0;+ * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);+ * ec = asio::error_code(n < 0 ? errno : 0,+ * asio::error::get_system_category());+ * total_bytes_transferred_ += ec ? 0 : n;+ *+ * // Retry operation immediately if interrupted by signal.+ * if (ec == asio::error::interrupted)+ * continue;+ *+ * // Check if we need to run the operation again.+ * if (ec == asio::error::would_block+ * || ec == asio::error::try_again)+ * {+ * // We have to wait for the socket to become ready again.+ * sock_.async_wait(tcp::socket::wait_write, *this);+ * return;+ * }+ *+ * if (ec || n == 0)+ * {+ * // An error occurred, or we have reached the end of the file.+ * // Either way we must exit the loop so we can call the handler.+ * break;+ * }+ *+ * // Loop around to try calling sendfile again.+ * }+ * }+ *+ * // Pass result back to user's handler.+ * handler_(ec, total_bytes_transferred_);+ * }+ * };+ *+ * template <typename Handler>+ * void async_sendfile(tcp::socket& sock, int fd, Handler h)+ * {+ * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };+ * sock.async_wait(tcp::socket::wait_write, op);+ * } @endcode+ */+ ASIO_SYNC_OP_VOID native_non_blocking(+ bool mode, asio::error_code& ec)+ {+ impl_.get_service().native_non_blocking(+ impl_.get_implementation(), mode, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Get the local endpoint of the socket.+ /**+ * This function is used to obtain the locally bound endpoint of the socket.+ *+ * @returns An object that represents the local endpoint of the socket.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint = socket.local_endpoint();+ * @endcode+ */+ endpoint_type local_endpoint() const+ {+ asio::error_code ec;+ endpoint_type ep = impl_.get_service().local_endpoint(+ impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "local_endpoint");+ return ep;+ }++ /// Get the local endpoint of the socket.+ /**+ * This function is used to obtain the locally bound endpoint of the socket.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns An object that represents the local endpoint of the socket.+ * Returns a default-constructed endpoint object if an error occurred.+ *+ * @par Example+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::error_code ec;+ * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ endpoint_type local_endpoint(asio::error_code& ec) const+ {+ return impl_.get_service().local_endpoint(impl_.get_implementation(), ec);+ }++ /// Get the remote endpoint of the socket.+ /**+ * This function is used to obtain the remote endpoint of the socket.+ *+ * @returns An object that represents the remote endpoint of the socket.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint();+ * @endcode+ */+ endpoint_type remote_endpoint() const+ {+ asio::error_code ec;+ endpoint_type ep = impl_.get_service().remote_endpoint(+ impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "remote_endpoint");+ return ep;+ }++ /// Get the remote endpoint of the socket.+ /**+ * This function is used to obtain the remote endpoint of the socket.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns An object that represents the remote endpoint of the socket.+ * Returns a default-constructed endpoint object if an error occurred.+ *+ * @par Example+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::error_code ec;+ * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ endpoint_type remote_endpoint(asio::error_code& ec) const+ {+ return impl_.get_service().remote_endpoint(impl_.get_implementation(), ec);+ }++ /// Disable sends or receives on the socket.+ /**+ * This function is used to disable send operations, receive operations, or+ * both.+ *+ * @param what Determines what types of operation will no longer be allowed.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * Shutting down the send side of the socket:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * socket.shutdown(asio::ip::tcp::socket::shutdown_send);+ * @endcode+ */+ void shutdown(shutdown_type what)+ {+ asio::error_code ec;+ impl_.get_service().shutdown(impl_.get_implementation(), what, ec);+ asio::detail::throw_error(ec, "shutdown");+ }++ /// Disable sends or receives on the socket.+ /**+ * This function is used to disable send operations, receive operations, or+ * both.+ *+ * @param what Determines what types of operation will no longer be allowed.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * Shutting down the send side of the socket:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::error_code ec;+ * socket.shutdown(asio::ip::tcp::socket::shutdown_send, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ ASIO_SYNC_OP_VOID shutdown(shutdown_type what,+ asio::error_code& ec)+ {+ impl_.get_service().shutdown(impl_.get_implementation(), what, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Wait for the socket to become ready to read, ready to write, or to have+ /// pending error conditions.+ /**+ * This function is used to perform a blocking wait for a socket to enter+ * a ready to read, write or error condition state.+ *+ * @param w Specifies the desired socket state.+ *+ * @par Example+ * Waiting for a socket to become readable.+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * socket.wait(asio::ip::tcp::socket::wait_read);+ * @endcode+ */+ void wait(wait_type w)+ {+ asio::error_code ec;+ impl_.get_service().wait(impl_.get_implementation(), w, ec);+ asio::detail::throw_error(ec, "wait");+ }++ /// Wait for the socket to become ready to read, ready to write, or to have+ /// pending error conditions.+ /**+ * This function is used to perform a blocking wait for a socket to enter+ * a ready to read, write or error condition state.+ *+ * @param w Specifies the desired socket state.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * Waiting for a socket to become readable.+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::error_code ec;+ * socket.wait(asio::ip::tcp::socket::wait_read, ec);+ * @endcode+ */+ ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec)+ {+ impl_.get_service().wait(impl_.get_implementation(), w, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Asynchronously wait for the socket to become ready to read, ready to+ /// write, or to have pending error conditions.+ /**+ * This function is used to perform an asynchronous wait for a socket to enter+ * a ready to read, write or error condition state.+ *+ * @param w Specifies the desired socket state.+ *+ * @param handler The handler to be called when the wait operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error // Result of operation+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code+ * void wait_handler(const asio::error_code& error)+ * {+ * if (!error)+ * {+ * // Wait succeeded.+ * }+ * }+ *+ * ...+ *+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * socket.async_wait(asio::ip::tcp::socket::wait_read, wait_handler);+ * @endcode+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))+ WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,+ void (asio::error_code))+ async_wait(wait_type w,+ ASIO_MOVE_ARG(WaitHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WaitHandler, void (asio::error_code)>(+ initiate_async_wait(this), handler, w);+ }++protected:+ /// Protected destructor to prevent deletion through this type.+ /**+ * This function destroys the socket, cancelling any outstanding asynchronous+ * operations associated with the socket as if by calling @c cancel.+ */+ ~basic_socket()+ {+ }++#if defined(ASIO_WINDOWS_RUNTIME)+ detail::io_object_impl<+ detail::null_socket_service<Protocol>, Executor> impl_;+#elif defined(ASIO_HAS_IOCP)+ detail::io_object_impl<+ detail::win_iocp_socket_service<Protocol>, Executor> impl_;+#else+ detail::io_object_impl<+ detail::reactive_socket_service<Protocol>, Executor> impl_;+#endif++private:+ // Disallow copying and assignment.+ basic_socket(const basic_socket&) ASIO_DELETED;+ basic_socket& operator=(const basic_socket&) ASIO_DELETED;++ class initiate_async_connect+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_connect(basic_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ConnectHandler>+ void operator()(ASIO_MOVE_ARG(ConnectHandler) handler,+ const endpoint_type& peer_endpoint,+ const asio::error_code& open_ec) const+ {+ // If you get an error on the following line it means that your handler+ // does not meet the documented type requirements for a ConnectHandler.+ ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check;++ if (open_ec)+ {+ asio::post(self_->impl_.get_executor(),+ asio::detail::bind_handler(+ ASIO_MOVE_CAST(ConnectHandler)(handler), open_ec));+ }+ else+ {+ detail::non_const_lvalue<ConnectHandler> handler2(handler);+ self_->impl_.get_service().async_connect(+ self_->impl_.get_implementation(), peer_endpoint,+ handler2.value, self_->impl_.get_executor());+ }+ }++ private:+ basic_socket* self_;+ };++ class initiate_async_wait+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_wait(basic_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WaitHandler>+ void operator()(ASIO_MOVE_ARG(WaitHandler) handler, wait_type w) 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(), w,+ handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_socket* self_;+ };+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BASIC_SOCKET_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_socket_acceptor.hpp view
@@ -0,0 +1,2501 @@+//+// basic_socket_acceptor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_ACCEPTOR_HPP+#define ASIO_BASIC_SOCKET_ACCEPTOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/any_io_executor.hpp"+#include "asio/basic_socket.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/socket_base.hpp"++#if defined(ASIO_WINDOWS_RUNTIME)+# include "asio/detail/null_socket_service.hpp"+#elif defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_socket_service.hpp"+#else+# include "asio/detail/reactive_socket_service.hpp"+#endif++#if defined(ASIO_HAS_MOVE)+# include <utility>+#endif // defined(ASIO_HAS_MOVE)++#include "asio/detail/push_options.hpp"++namespace asio {++#if !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL)+#define ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename Protocol, typename Executor = any_io_executor>+class basic_socket_acceptor;++#endif // !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL)++/// Provides the ability to accept new connections.+/**+ * The basic_socket_acceptor class template is used for accepting new socket+ * connections.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Example+ * Opening a socket acceptor with the SO_REUSEADDR option enabled:+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port);+ * acceptor.open(endpoint.protocol());+ * acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));+ * acceptor.bind(endpoint);+ * acceptor.listen();+ * @endcode+ */+template <typename Protocol, typename Executor>+class basic_socket_acceptor+ : public socket_base+{+public:+ /// The type of the executor associated with the object.+ typedef Executor executor_type;++ /// Rebinds the acceptor type to another executor.+ template <typename Executor1>+ struct rebind_executor+ {+ /// The socket type when rebound to the specified executor.+ typedef basic_socket_acceptor<Protocol, Executor1> other;+ };++ /// The native representation of an acceptor.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined native_handle_type;+#elif defined(ASIO_WINDOWS_RUNTIME)+ typedef typename detail::null_socket_service<+ Protocol>::native_handle_type native_handle_type;+#elif defined(ASIO_HAS_IOCP)+ typedef typename detail::win_iocp_socket_service<+ Protocol>::native_handle_type native_handle_type;+#else+ typedef typename detail::reactive_socket_service<+ Protocol>::native_handle_type native_handle_type;+#endif++ /// The protocol type.+ typedef Protocol protocol_type;++ /// The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ /// Construct an acceptor without opening it.+ /**+ * This constructor creates an acceptor without opening it to listen for new+ * connections. The open() function must be called before the acceptor can+ * accept new socket connections.+ *+ * @param ex The I/O executor that the acceptor will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * acceptor.+ */+ explicit basic_socket_acceptor(const executor_type& ex)+ : impl_(ex)+ {+ }++ /// Construct an acceptor without opening it.+ /**+ * This constructor creates an acceptor without opening it to listen for new+ * connections. The open() function must be called before the acceptor can+ * accept new socket connections.+ *+ * @param context An execution context which provides the I/O executor that+ * the acceptor will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the acceptor.+ */+ template <typename ExecutionContext>+ explicit basic_socket_acceptor(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ }++ /// Construct an open acceptor.+ /**+ * This constructor creates an acceptor and automatically opens it.+ *+ * @param ex The I/O executor that the acceptor will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * acceptor.+ *+ * @param protocol An object specifying protocol parameters to be used.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_socket_acceptor(const executor_type& ex, const protocol_type& protocol)+ : impl_(ex)+ {+ asio::error_code ec;+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ asio::detail::throw_error(ec, "open");+ }++ /// Construct an open acceptor.+ /**+ * This constructor creates an acceptor and automatically opens it.+ *+ * @param context An execution context which provides the I/O executor that+ * the acceptor will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the acceptor.+ *+ * @param protocol An object specifying protocol parameters to be used.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_socket_acceptor(ExecutionContext& context,+ const protocol_type& protocol,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ asio::detail::throw_error(ec, "open");+ }++ /// Construct an acceptor opened on the given endpoint.+ /**+ * This constructor creates an acceptor and automatically opens it to listen+ * for new connections on the specified endpoint.+ *+ * @param ex The I/O executor that the acceptor will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * acceptor.+ *+ * @param endpoint An endpoint on the local machine on which the acceptor+ * will listen for new connections.+ *+ * @param reuse_addr Whether the constructor should set the socket option+ * socket_base::reuse_address.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note This constructor is equivalent to the following code:+ * @code+ * basic_socket_acceptor<Protocol> acceptor(my_context);+ * acceptor.open(endpoint.protocol());+ * if (reuse_addr)+ * acceptor.set_option(socket_base::reuse_address(true));+ * acceptor.bind(endpoint);+ * acceptor.listen();+ * @endcode+ */+ basic_socket_acceptor(const executor_type& ex,+ const endpoint_type& endpoint, bool reuse_addr = true)+ : impl_(ex)+ {+ asio::error_code ec;+ const protocol_type protocol = endpoint.protocol();+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ asio::detail::throw_error(ec, "open");+ if (reuse_addr)+ {+ impl_.get_service().set_option(impl_.get_implementation(),+ socket_base::reuse_address(true), ec);+ asio::detail::throw_error(ec, "set_option");+ }+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);+ asio::detail::throw_error(ec, "bind");+ impl_.get_service().listen(impl_.get_implementation(),+ socket_base::max_listen_connections, ec);+ asio::detail::throw_error(ec, "listen");+ }++ /// Construct an acceptor opened on the given endpoint.+ /**+ * This constructor creates an acceptor and automatically opens it to listen+ * for new connections on the specified endpoint.+ *+ * @param context An execution context which provides the I/O executor that+ * the acceptor will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the acceptor.+ *+ * @param endpoint An endpoint on the local machine on which the acceptor+ * will listen for new connections.+ *+ * @param reuse_addr Whether the constructor should set the socket option+ * socket_base::reuse_address.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note This constructor is equivalent to the following code:+ * @code+ * basic_socket_acceptor<Protocol> acceptor(my_context);+ * acceptor.open(endpoint.protocol());+ * if (reuse_addr)+ * acceptor.set_option(socket_base::reuse_address(true));+ * acceptor.bind(endpoint);+ * acceptor.listen();+ * @endcode+ */+ template <typename ExecutionContext>+ basic_socket_acceptor(ExecutionContext& context,+ const endpoint_type& endpoint, bool reuse_addr = true,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ const protocol_type protocol = endpoint.protocol();+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ asio::detail::throw_error(ec, "open");+ if (reuse_addr)+ {+ impl_.get_service().set_option(impl_.get_implementation(),+ socket_base::reuse_address(true), ec);+ asio::detail::throw_error(ec, "set_option");+ }+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);+ asio::detail::throw_error(ec, "bind");+ impl_.get_service().listen(impl_.get_implementation(),+ socket_base::max_listen_connections, ec);+ asio::detail::throw_error(ec, "listen");+ }++ /// Construct a basic_socket_acceptor on an existing native acceptor.+ /**+ * This constructor creates an acceptor object to hold an existing native+ * acceptor.+ *+ * @param ex The I/O executor that the acceptor will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * acceptor.+ *+ * @param protocol An object specifying protocol parameters to be used.+ *+ * @param native_acceptor A native acceptor.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_socket_acceptor(const executor_type& ex,+ const protocol_type& protocol, const native_handle_type& native_acceptor)+ : impl_(ex)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(),+ protocol, native_acceptor, ec);+ asio::detail::throw_error(ec, "assign");+ }++ /// Construct a basic_socket_acceptor on an existing native acceptor.+ /**+ * This constructor creates an acceptor object to hold an existing native+ * acceptor.+ *+ * @param context An execution context which provides the I/O executor that+ * the acceptor will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the acceptor.+ *+ * @param protocol An object specifying protocol parameters to be used.+ *+ * @param native_acceptor A native acceptor.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_socket_acceptor(ExecutionContext& context,+ const protocol_type& protocol, const native_handle_type& native_acceptor,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(),+ protocol, native_acceptor, ec);+ asio::detail::throw_error(ec, "assign");+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a basic_socket_acceptor from another.+ /**+ * This constructor moves an acceptor from one object to another.+ *+ * @param other The other basic_socket_acceptor 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_socket_acceptor(const executor_type&)+ * constructor.+ */+ basic_socket_acceptor(basic_socket_acceptor&& other) ASIO_NOEXCEPT+ : impl_(std::move(other.impl_))+ {+ }++ /// Move-assign a basic_socket_acceptor from another.+ /**+ * This assignment operator moves an acceptor from one object to another.+ *+ * @param other The other basic_socket_acceptor 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_socket_acceptor(const executor_type&)+ * constructor.+ */+ basic_socket_acceptor& operator=(basic_socket_acceptor&& other)+ {+ impl_ = std::move(other.impl_);+ return *this;+ }++ // All socket acceptors have access to each other's implementations.+ template <typename Protocol1, typename Executor1>+ friend class basic_socket_acceptor;++ /// Move-construct a basic_socket_acceptor from an acceptor of another+ /// protocol type.+ /**+ * This constructor moves an acceptor from one object to another.+ *+ * @param other The other basic_socket_acceptor 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_socket_acceptor(const executor_type&)+ * constructor.+ */+ template <typename Protocol1, typename Executor1>+ basic_socket_acceptor(basic_socket_acceptor<Protocol1, Executor1>&& other,+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value+ >::type* = 0)+ : impl_(std::move(other.impl_))+ {+ }++ /// Move-assign a basic_socket_acceptor from an acceptor of another protocol+ /// type.+ /**+ * This assignment operator moves an acceptor from one object to another.+ *+ * @param other The other basic_socket_acceptor 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_socket_acceptor(const executor_type&)+ * constructor.+ */+ template <typename Protocol1, typename Executor1>+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value,+ basic_socket_acceptor&+ >::type operator=(basic_socket_acceptor<Protocol1, Executor1>&& other)+ {+ basic_socket_acceptor tmp(std::move(other));+ impl_ = std::move(tmp.impl_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destroys the acceptor.+ /**+ * This function destroys the acceptor, cancelling any outstanding+ * asynchronous operations associated with the acceptor as if by calling+ * @c cancel.+ */+ ~basic_socket_acceptor()+ {+ }++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_NOEXCEPT+ {+ return impl_.get_executor();+ }++ /// Open the acceptor using the specified protocol.+ /**+ * This function opens the socket acceptor so that it will use the specified+ * protocol.+ *+ * @param protocol An object specifying which protocol is to be used.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * acceptor.open(asio::ip::tcp::v4());+ * @endcode+ */+ void open(const protocol_type& protocol = protocol_type())+ {+ asio::error_code ec;+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ asio::detail::throw_error(ec, "open");+ }++ /// Open the acceptor using the specified protocol.+ /**+ * This function opens the socket acceptor so that it will use the specified+ * protocol.+ *+ * @param protocol An object specifying which protocol is to be used.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * asio::error_code ec;+ * acceptor.open(asio::ip::tcp::v4(), ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ ASIO_SYNC_OP_VOID open(const protocol_type& protocol,+ asio::error_code& ec)+ {+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Assigns an existing native acceptor to the acceptor.+ /*+ * This function opens the acceptor to hold an existing native acceptor.+ *+ * @param protocol An object specifying which protocol is to be used.+ *+ * @param native_acceptor A native acceptor.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void assign(const protocol_type& protocol,+ const native_handle_type& native_acceptor)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(),+ protocol, native_acceptor, ec);+ asio::detail::throw_error(ec, "assign");+ }++ /// Assigns an existing native acceptor to the acceptor.+ /*+ * This function opens the acceptor to hold an existing native acceptor.+ *+ * @param protocol An object specifying which protocol is to be used.+ *+ * @param native_acceptor A native acceptor.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ ASIO_SYNC_OP_VOID assign(const protocol_type& protocol,+ const native_handle_type& native_acceptor, asio::error_code& ec)+ {+ impl_.get_service().assign(impl_.get_implementation(),+ protocol, native_acceptor, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Determine whether the acceptor is open.+ bool is_open() const+ {+ return impl_.get_service().is_open(impl_.get_implementation());+ }++ /// Bind the acceptor to the given local endpoint.+ /**+ * This function binds the socket acceptor to the specified endpoint on the+ * local machine.+ *+ * @param endpoint An endpoint on the local machine to which the socket+ * acceptor will be bound.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), 12345);+ * acceptor.open(endpoint.protocol());+ * acceptor.bind(endpoint);+ * @endcode+ */+ void bind(const endpoint_type& endpoint)+ {+ asio::error_code ec;+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);+ asio::detail::throw_error(ec, "bind");+ }++ /// Bind the acceptor to the given local endpoint.+ /**+ * This function binds the socket acceptor to the specified endpoint on the+ * local machine.+ *+ * @param endpoint An endpoint on the local machine to which the socket+ * acceptor will be bound.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), 12345);+ * acceptor.open(endpoint.protocol());+ * asio::error_code ec;+ * acceptor.bind(endpoint, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint,+ asio::error_code& ec)+ {+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Place the acceptor into the state where it will listen for new+ /// connections.+ /**+ * This function puts the socket acceptor into the state where it may accept+ * new connections.+ *+ * @param backlog The maximum length of the queue of pending connections.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void listen(int backlog = socket_base::max_listen_connections)+ {+ asio::error_code ec;+ impl_.get_service().listen(impl_.get_implementation(), backlog, ec);+ asio::detail::throw_error(ec, "listen");+ }++ /// Place the acceptor into the state where it will listen for new+ /// connections.+ /**+ * This function puts the socket acceptor into the state where it may accept+ * new connections.+ *+ * @param backlog The maximum length of the queue of pending connections.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::error_code ec;+ * acceptor.listen(asio::socket_base::max_listen_connections, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ ASIO_SYNC_OP_VOID listen(int backlog, asio::error_code& ec)+ {+ impl_.get_service().listen(impl_.get_implementation(), backlog, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Close the acceptor.+ /**+ * This function is used to close the acceptor. Any asynchronous accept+ * operations will be cancelled immediately.+ *+ * A subsequent call to open() is required before the acceptor can again be+ * used to again perform socket accept operations.+ *+ * @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 acceptor.+ /**+ * This function is used to close the acceptor. Any asynchronous accept+ * operations will be cancelled immediately.+ *+ * A subsequent call to open() is required before the acceptor can again be+ * used to again perform socket accept operations.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::error_code ec;+ * acceptor.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 acceptor.+ /**+ * This function causes all outstanding asynchronous accept operations to+ * finish immediately, and the handlers for cancelled operations will be+ * passed the asio::error::operation_aborted error. Ownership of the+ * native acceptor 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 acceptor.+ /**+ * This function causes all outstanding asynchronous accept operations to+ * finish immediately, and the handlers for cancelled operations will be+ * passed the asio::error::operation_aborted error. Ownership of the+ * native acceptor 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 acceptor representation.+ /**+ * This function may be used to obtain the underlying representation of the+ * acceptor. This is intended to allow access to native acceptor 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 acceptor.+ /**+ * This function causes all outstanding asynchronous connect, send and receive+ * 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 acceptor.+ /**+ * This function causes all outstanding asynchronous connect, send and receive+ * 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);+ }++ /// Set an option on the acceptor.+ /**+ * This function is used to set an option on the acceptor.+ *+ * @param option The new option value to be set on the acceptor.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @sa SettableSocketOption @n+ * asio::socket_base::reuse_address+ * asio::socket_base::enable_connection_aborted+ *+ * @par Example+ * Setting the SOL_SOCKET/SO_REUSEADDR option:+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::acceptor::reuse_address option(true);+ * acceptor.set_option(option);+ * @endcode+ */+ template <typename SettableSocketOption>+ void set_option(const SettableSocketOption& option)+ {+ asio::error_code ec;+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);+ asio::detail::throw_error(ec, "set_option");+ }++ /// Set an option on the acceptor.+ /**+ * This function is used to set an option on the acceptor.+ *+ * @param option The new option value to be set on the acceptor.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @sa SettableSocketOption @n+ * asio::socket_base::reuse_address+ * asio::socket_base::enable_connection_aborted+ *+ * @par Example+ * Setting the SOL_SOCKET/SO_REUSEADDR option:+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::acceptor::reuse_address option(true);+ * asio::error_code ec;+ * acceptor.set_option(option, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ template <typename SettableSocketOption>+ ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option,+ asio::error_code& ec)+ {+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Get an option from the acceptor.+ /**+ * This function is used to get the current value of an option on the+ * acceptor.+ *+ * @param option The option value to be obtained from the acceptor.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @sa GettableSocketOption @n+ * asio::socket_base::reuse_address+ *+ * @par Example+ * Getting the value of the SOL_SOCKET/SO_REUSEADDR option:+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::acceptor::reuse_address option;+ * acceptor.get_option(option);+ * bool is_set = option.get();+ * @endcode+ */+ template <typename GettableSocketOption>+ void get_option(GettableSocketOption& option) const+ {+ asio::error_code ec;+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);+ asio::detail::throw_error(ec, "get_option");+ }++ /// Get an option from the acceptor.+ /**+ * This function is used to get the current value of an option on the+ * acceptor.+ *+ * @param option The option value to be obtained from the acceptor.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @sa GettableSocketOption @n+ * asio::socket_base::reuse_address+ *+ * @par Example+ * Getting the value of the SOL_SOCKET/SO_REUSEADDR option:+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::acceptor::reuse_address option;+ * asio::error_code ec;+ * acceptor.get_option(option, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * bool is_set = option.get();+ * @endcode+ */+ template <typename GettableSocketOption>+ ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option,+ asio::error_code& ec) const+ {+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Perform an IO control command on the acceptor.+ /**+ * This function is used to execute an IO control command on the acceptor.+ *+ * @param command The IO control command to be performed on the acceptor.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @sa IoControlCommand @n+ * asio::socket_base::non_blocking_io+ *+ * @par Example+ * Getting the number of bytes ready to read:+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::acceptor::non_blocking_io command(true);+ * socket.io_control(command);+ * @endcode+ */+ template <typename IoControlCommand>+ void io_control(IoControlCommand& command)+ {+ asio::error_code ec;+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);+ asio::detail::throw_error(ec, "io_control");+ }++ /// Perform an IO control command on the acceptor.+ /**+ * This function is used to execute an IO control command on the acceptor.+ *+ * @param command The IO control command to be performed on the acceptor.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @sa IoControlCommand @n+ * asio::socket_base::non_blocking_io+ *+ * @par Example+ * Getting the number of bytes ready to read:+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::acceptor::non_blocking_io command(true);+ * asio::error_code ec;+ * socket.io_control(command, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ template <typename IoControlCommand>+ ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,+ asio::error_code& ec)+ {+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Gets the non-blocking mode of the acceptor.+ /**+ * @returns @c true if the acceptor's synchronous operations will fail with+ * asio::error::would_block if they are unable to perform the requested+ * operation immediately. If @c false, synchronous operations will block+ * until complete.+ *+ * @note The non-blocking mode has no effect on the behaviour of asynchronous+ * operations. Asynchronous operations will never fail with the error+ * asio::error::would_block.+ */+ bool non_blocking() const+ {+ return impl_.get_service().non_blocking(impl_.get_implementation());+ }++ /// Sets the non-blocking mode of the acceptor.+ /**+ * @param mode If @c true, the acceptor's synchronous operations will fail+ * with asio::error::would_block if they are unable to perform the+ * requested operation immediately. If @c false, synchronous operations will+ * block until complete.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The non-blocking mode has no effect on the behaviour of asynchronous+ * operations. Asynchronous operations will never fail with the error+ * asio::error::would_block.+ */+ void non_blocking(bool mode)+ {+ asio::error_code ec;+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);+ asio::detail::throw_error(ec, "non_blocking");+ }++ /// Sets the non-blocking mode of the acceptor.+ /**+ * @param mode If @c true, the acceptor's synchronous operations will fail+ * with asio::error::would_block if they are unable to perform the+ * requested operation immediately. If @c false, synchronous operations will+ * block until complete.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note The non-blocking mode has no effect on the behaviour of asynchronous+ * operations. Asynchronous operations will never fail with the error+ * asio::error::would_block.+ */+ ASIO_SYNC_OP_VOID non_blocking(+ bool mode, asio::error_code& ec)+ {+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Gets the non-blocking mode of the native acceptor implementation.+ /**+ * This function is used to retrieve the non-blocking mode of the underlying+ * native acceptor. This mode has no effect on the behaviour of the acceptor+ * object's synchronous operations.+ *+ * @returns @c true if the underlying acceptor is in non-blocking mode and+ * direct system calls may fail with asio::error::would_block (or the+ * equivalent system error).+ *+ * @note The current non-blocking mode is cached by the acceptor object.+ * Consequently, the return value may be incorrect if the non-blocking mode+ * was set directly on the native acceptor.+ */+ bool native_non_blocking() const+ {+ return impl_.get_service().native_non_blocking(impl_.get_implementation());+ }++ /// Sets the non-blocking mode of the native acceptor implementation.+ /**+ * This function is used to modify the non-blocking mode of the underlying+ * native acceptor. It has no effect on the behaviour of the acceptor object's+ * synchronous operations.+ *+ * @param mode If @c true, the underlying acceptor is put into non-blocking+ * mode and direct system calls may fail with asio::error::would_block+ * (or the equivalent system error).+ *+ * @throws asio::system_error Thrown on failure. If the @c mode is+ * @c false, but the current value of @c non_blocking() is @c true, this+ * function fails with asio::error::invalid_argument, as the+ * combination does not make sense.+ */+ void native_non_blocking(bool mode)+ {+ asio::error_code ec;+ impl_.get_service().native_non_blocking(+ impl_.get_implementation(), mode, ec);+ asio::detail::throw_error(ec, "native_non_blocking");+ }++ /// Sets the non-blocking mode of the native acceptor implementation.+ /**+ * This function is used to modify the non-blocking mode of the underlying+ * native acceptor. It has no effect on the behaviour of the acceptor object's+ * synchronous operations.+ *+ * @param mode If @c true, the underlying acceptor is put into non-blocking+ * mode and direct system calls may fail with asio::error::would_block+ * (or the equivalent system error).+ *+ * @param ec Set to indicate what error occurred, if any. If the @c mode is+ * @c false, but the current value of @c non_blocking() is @c true, this+ * function fails with asio::error::invalid_argument, as the+ * combination does not make sense.+ */+ ASIO_SYNC_OP_VOID native_non_blocking(+ bool mode, asio::error_code& ec)+ {+ impl_.get_service().native_non_blocking(+ impl_.get_implementation(), mode, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Get the local endpoint of the acceptor.+ /**+ * This function is used to obtain the locally bound endpoint of the acceptor.+ *+ * @returns An object that represents the local endpoint of the acceptor.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint();+ * @endcode+ */+ endpoint_type local_endpoint() const+ {+ asio::error_code ec;+ endpoint_type ep = impl_.get_service().local_endpoint(+ impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "local_endpoint");+ return ep;+ }++ /// Get the local endpoint of the acceptor.+ /**+ * This function is used to obtain the locally bound endpoint of the acceptor.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns An object that represents the local endpoint of the acceptor.+ * Returns a default-constructed endpoint object if an error occurred and the+ * error handler did not throw an exception.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::error_code ec;+ * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ endpoint_type local_endpoint(asio::error_code& ec) const+ {+ return impl_.get_service().local_endpoint(impl_.get_implementation(), ec);+ }++ /// Wait for the acceptor to become ready to read, ready to write, or to have+ /// pending error conditions.+ /**+ * This function is used to perform a blocking wait for an acceptor to enter+ * a ready to read, write or error condition state.+ *+ * @param w Specifies the desired acceptor state.+ *+ * @par Example+ * Waiting for an acceptor to become readable.+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * acceptor.wait(asio::ip::tcp::acceptor::wait_read);+ * @endcode+ */+ void wait(wait_type w)+ {+ asio::error_code ec;+ impl_.get_service().wait(impl_.get_implementation(), w, ec);+ asio::detail::throw_error(ec, "wait");+ }++ /// Wait for the acceptor to become ready to read, ready to write, or to have+ /// pending error conditions.+ /**+ * This function is used to perform a blocking wait for an acceptor to enter+ * a ready to read, write or error condition state.+ *+ * @param w Specifies the desired acceptor state.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * Waiting for an acceptor to become readable.+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::error_code ec;+ * acceptor.wait(asio::ip::tcp::acceptor::wait_read, ec);+ * @endcode+ */+ ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec)+ {+ impl_.get_service().wait(impl_.get_implementation(), w, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Asynchronously wait for the acceptor to become ready to read, ready to+ /// write, or to have pending error conditions.+ /**+ * This function is used to perform an asynchronous wait for an acceptor to+ * enter a ready to read, write or error condition state.+ *+ * @param w Specifies the desired acceptor state.+ *+ * @param handler The handler to be called when the wait operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error // Result of operation+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code+ * void wait_handler(const asio::error_code& error)+ * {+ * if (!error)+ * {+ * // Wait succeeded.+ * }+ * }+ *+ * ...+ *+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * acceptor.async_wait(+ * asio::ip::tcp::acceptor::wait_read,+ * wait_handler);+ * @endcode+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))+ WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,+ void (asio::error_code))+ async_wait(wait_type w,+ ASIO_MOVE_ARG(WaitHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WaitHandler, void (asio::error_code)>(+ initiate_async_wait(this), handler, w);+ }++#if !defined(ASIO_NO_EXTENSIONS)+ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer into the+ * given socket. The function call will block until a new connection has been+ * accepted successfully or an error occurs.+ *+ * @param peer The socket into which the new connection will be accepted.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::socket socket(my_context);+ * acceptor.accept(socket);+ * @endcode+ */+ template <typename Protocol1, typename Executor1>+ void accept(basic_socket<Protocol1, Executor1>& peer,+ typename enable_if<+ is_convertible<Protocol, Protocol1>::value+ >::type* = 0)+ {+ asio::error_code ec;+ impl_.get_service().accept(impl_.get_implementation(),+ peer, static_cast<endpoint_type*>(0), ec);+ asio::detail::throw_error(ec, "accept");+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer into the+ * given socket. The function call will block until a new connection has been+ * accepted successfully or an error occurs.+ *+ * @param peer The socket into which the new connection will be accepted.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::socket socket(my_context);+ * asio::error_code ec;+ * acceptor.accept(socket, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ template <typename Protocol1, typename Executor1>+ ASIO_SYNC_OP_VOID accept(+ basic_socket<Protocol1, Executor1>& peer, asio::error_code& ec,+ typename enable_if<+ is_convertible<Protocol, Protocol1>::value+ >::type* = 0)+ {+ impl_.get_service().accept(impl_.get_implementation(),+ peer, static_cast<endpoint_type*>(0), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Start an asynchronous accept.+ /**+ * This function is used to asynchronously accept a new connection into a+ * socket. The function call always returns immediately.+ *+ * @param peer The socket into which the new connection will be accepted.+ * Ownership of the peer object is retained by the caller, which must+ * guarantee that it is valid until the handler is called.+ *+ * @param handler The handler to be called when the accept operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error // Result of operation.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code+ * void accept_handler(const asio::error_code& error)+ * {+ * if (!error)+ * {+ * // Accept succeeded.+ * }+ * }+ *+ * ...+ *+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::socket socket(my_context);+ * acceptor.async_accept(socket, accept_handler);+ * @endcode+ */+ template <typename Protocol1, typename Executor1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))+ AcceptHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(AcceptHandler,+ void (asio::error_code))+ async_accept(basic_socket<Protocol1, Executor1>& peer,+ ASIO_MOVE_ARG(AcceptHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type),+ typename enable_if<+ is_convertible<Protocol, Protocol1>::value+ >::type* = 0)+ {+ return async_initiate<AcceptHandler, void (asio::error_code)>(+ initiate_async_accept(this), handler,+ &peer, static_cast<endpoint_type*>(0));+ }++ /// Accept a new connection and obtain the endpoint of the peer+ /**+ * This function is used to accept a new connection from a peer into the+ * given socket, and additionally provide the endpoint of the remote peer.+ * The function call will block until a new connection has been accepted+ * successfully or an error occurs.+ *+ * @param peer The socket into which the new connection will be accepted.+ *+ * @param peer_endpoint An endpoint object which will receive the endpoint of+ * the remote peer.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::socket socket(my_context);+ * asio::ip::tcp::endpoint endpoint;+ * acceptor.accept(socket, endpoint);+ * @endcode+ */+ template <typename Executor1>+ void accept(basic_socket<protocol_type, Executor1>& peer,+ endpoint_type& peer_endpoint)+ {+ asio::error_code ec;+ impl_.get_service().accept(impl_.get_implementation(),+ peer, &peer_endpoint, ec);+ asio::detail::throw_error(ec, "accept");+ }++ /// Accept a new connection and obtain the endpoint of the peer+ /**+ * This function is used to accept a new connection from a peer into the+ * given socket, and additionally provide the endpoint of the remote peer.+ * The function call will block until a new connection has been accepted+ * successfully or an error occurs.+ *+ * @param peer The socket into which the new connection will be accepted.+ *+ * @param peer_endpoint An endpoint object which will receive the endpoint of+ * the remote peer.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::socket socket(my_context);+ * asio::ip::tcp::endpoint endpoint;+ * asio::error_code ec;+ * acceptor.accept(socket, endpoint, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ template <typename Executor1>+ ASIO_SYNC_OP_VOID accept(basic_socket<protocol_type, Executor1>& peer,+ endpoint_type& peer_endpoint, asio::error_code& ec)+ {+ impl_.get_service().accept(+ impl_.get_implementation(), peer, &peer_endpoint, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Start an asynchronous accept.+ /**+ * This function is used to asynchronously accept a new connection into a+ * socket, and additionally obtain the endpoint of the remote peer. The+ * function call always returns immediately.+ *+ * @param peer The socket into which the new connection will be accepted.+ * Ownership of the peer object is retained by the caller, which must+ * guarantee that it is valid until the handler is called.+ *+ * @param peer_endpoint An endpoint object into which the endpoint of the+ * remote peer will be written. Ownership of the peer_endpoint object is+ * retained by the caller, which must guarantee that it is valid until the+ * handler is called.+ *+ * @param handler The handler to be called when the accept operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error // Result of operation.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+ template <typename Executor1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))+ AcceptHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(AcceptHandler,+ void (asio::error_code))+ async_accept(basic_socket<protocol_type, Executor1>& peer,+ endpoint_type& peer_endpoint,+ ASIO_MOVE_ARG(AcceptHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<AcceptHandler, void (asio::error_code)>(+ initiate_async_accept(this), handler, &peer, &peer_endpoint);+ }+#endif // !defined(ASIO_NO_EXTENSIONS)++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @returns A socket object representing the newly accepted connection.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::socket socket(acceptor.accept());+ * @endcode+ */+ typename Protocol::socket::template rebind_executor<executor_type>::other+ accept()+ {+ asio::error_code ec;+ typename Protocol::socket::template rebind_executor<+ executor_type>::other peer(impl_.get_executor());+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);+ asio::detail::throw_error(ec, "accept");+ return peer;+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns On success, a socket object representing the newly accepted+ * connection. On error, a socket object where is_open() is false.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::socket socket(acceptor.accept(ec));+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ typename Protocol::socket::template rebind_executor<executor_type>::other+ accept(asio::error_code& ec)+ {+ typename Protocol::socket::template rebind_executor<+ executor_type>::other peer(impl_.get_executor());+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);+ return peer;+ }++ /// Start an asynchronous accept.+ /**+ * This function is used to asynchronously accept a new connection. The+ * function call always returns immediately.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param handler The handler to be called when the accept operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ * // On success, the newly accepted socket.+ * typename Protocol::socket::template+ * rebind_executor<executor_type>::other peer+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code+ * void accept_handler(const asio::error_code& error,+ * asio::ip::tcp::socket peer)+ * {+ * if (!error)+ * {+ * // Accept succeeded.+ * }+ * }+ *+ * ...+ *+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * acceptor.async_accept(accept_handler);+ * @endcode+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ typename Protocol::socket::template rebind_executor<+ executor_type>::other)) MoveAcceptHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,+ void (asio::error_code,+ typename Protocol::socket::template+ rebind_executor<executor_type>::other))+ async_accept(+ ASIO_MOVE_ARG(MoveAcceptHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<MoveAcceptHandler,+ void (asio::error_code, typename Protocol::socket::template+ rebind_executor<executor_type>::other)>(+ initiate_async_move_accept(this), handler,+ impl_.get_executor(), static_cast<endpoint_type*>(0),+ static_cast<typename Protocol::socket::template+ rebind_executor<executor_type>::other*>(0));+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param ex The I/O executor object to be used for the newly+ * accepted socket.+ *+ * @returns A socket object representing the newly accepted connection.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::socket socket(acceptor.accept());+ * @endcode+ */+ template <typename Executor1>+ typename Protocol::socket::template rebind_executor<Executor1>::other+ accept(const Executor1& ex,+ typename enable_if<+ is_executor<Executor1>::value+ || execution::is_executor<Executor1>::value+ >::type* = 0)+ {+ asio::error_code ec;+ typename Protocol::socket::template+ rebind_executor<Executor1>::other peer(ex);+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);+ asio::detail::throw_error(ec, "accept");+ return peer;+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param context The I/O execution context object to be used for the newly+ * accepted socket.+ *+ * @returns A socket object representing the newly accepted connection.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::socket socket(acceptor.accept());+ * @endcode+ */+ template <typename ExecutionContext>+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other+ accept(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ {+ asio::error_code ec;+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other peer(context);+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);+ asio::detail::throw_error(ec, "accept");+ return peer;+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param ex The I/O executor object to be used for the newly accepted+ * socket.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns On success, a socket object representing the newly accepted+ * connection. On error, a socket object where is_open() is false.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec));+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ template <typename Executor1>+ typename Protocol::socket::template rebind_executor<Executor1>::other+ accept(const Executor1& ex, asio::error_code& ec,+ typename enable_if<+ is_executor<Executor1>::value+ || execution::is_executor<Executor1>::value+ >::type* = 0)+ {+ typename Protocol::socket::template+ rebind_executor<Executor1>::other peer(ex);+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);+ return peer;+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param context The I/O execution context object to be used for the newly+ * accepted socket.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns On success, a socket object representing the newly accepted+ * connection. On error, a socket object where is_open() is false.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec));+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ template <typename ExecutionContext>+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other+ accept(ExecutionContext& context, asio::error_code& ec,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ {+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other peer(context);+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);+ return peer;+ }++ /// Start an asynchronous accept.+ /**+ * This function is used to asynchronously accept a new connection. The+ * function call always returns immediately.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param ex The I/O executor object to be used for the newly accepted+ * socket.+ *+ * @param handler The handler to be called when the accept operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * typename Protocol::socket::template rebind_executor<+ * Executor1>::other peer // On success, the newly accepted socket.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code+ * void accept_handler(const asio::error_code& error,+ * asio::ip::tcp::socket peer)+ * {+ * if (!error)+ * {+ * // Accept succeeded.+ * }+ * }+ *+ * ...+ *+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * acceptor.async_accept(my_context2, accept_handler);+ * @endcode+ */+ template <typename Executor1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ typename Protocol::socket::template rebind_executor<+ Executor1>::other)) MoveAcceptHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,+ void (asio::error_code,+ typename Protocol::socket::template rebind_executor<+ Executor1>::other))+ async_accept(const Executor1& ex,+ ASIO_MOVE_ARG(MoveAcceptHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type),+ typename enable_if<+ is_executor<Executor1>::value+ || execution::is_executor<Executor1>::value+ >::type* = 0)+ {+ typedef typename Protocol::socket::template rebind_executor<+ Executor1>::other other_socket_type;++ return async_initiate<MoveAcceptHandler,+ void (asio::error_code, other_socket_type)>(+ initiate_async_move_accept(this), handler,+ ex, static_cast<endpoint_type*>(0),+ static_cast<other_socket_type*>(0));+ }++ /// Start an asynchronous accept.+ /**+ * This function is used to asynchronously accept a new connection. The+ * function call always returns immediately.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param context The I/O execution context object to be used for the newly+ * accepted socket.+ *+ * @param handler The handler to be called when the accept operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * typename Protocol::socket::template rebind_executor<+ * typename ExecutionContext::executor_type>::other peer+ * // On success, the newly accepted socket.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code+ * void accept_handler(const asio::error_code& error,+ * asio::ip::tcp::socket peer)+ * {+ * if (!error)+ * {+ * // Accept succeeded.+ * }+ * }+ *+ * ...+ *+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * acceptor.async_accept(my_context2, accept_handler);+ * @endcode+ */+ template <typename ExecutionContext,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other)) MoveAcceptHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,+ void (asio::error_code,+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other))+ async_accept(ExecutionContext& context,+ ASIO_MOVE_ARG(MoveAcceptHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type),+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ {+ typedef typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other other_socket_type;++ return async_initiate<MoveAcceptHandler,+ void (asio::error_code, other_socket_type)>(+ initiate_async_move_accept(this), handler,+ context.get_executor(), static_cast<endpoint_type*>(0),+ static_cast<other_socket_type*>(0));+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param peer_endpoint An endpoint object into which the endpoint of the+ * remote peer will be written.+ *+ * @returns A socket object representing the newly accepted connection.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint;+ * asio::ip::tcp::socket socket(acceptor.accept(endpoint));+ * @endcode+ */+ typename Protocol::socket::template rebind_executor<executor_type>::other+ accept(endpoint_type& peer_endpoint)+ {+ asio::error_code ec;+ typename Protocol::socket::template rebind_executor<+ executor_type>::other peer(impl_.get_executor());+ impl_.get_service().accept(impl_.get_implementation(),+ peer, &peer_endpoint, ec);+ asio::detail::throw_error(ec, "accept");+ return peer;+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param peer_endpoint An endpoint object into which the endpoint of the+ * remote peer will be written.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns On success, a socket object representing the newly accepted+ * connection. On error, a socket object where is_open() is false.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint;+ * asio::ip::tcp::socket socket(acceptor.accept(endpoint, ec));+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ typename Protocol::socket::template rebind_executor<executor_type>::other+ accept(endpoint_type& peer_endpoint, asio::error_code& ec)+ {+ typename Protocol::socket::template rebind_executor<+ executor_type>::other peer(impl_.get_executor());+ impl_.get_service().accept(impl_.get_implementation(),+ peer, &peer_endpoint, ec);+ return peer;+ }++ /// Start an asynchronous accept.+ /**+ * This function is used to asynchronously accept a new connection. The+ * function call always returns immediately.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param peer_endpoint An endpoint object into which the endpoint of the+ * remote peer will be written. Ownership of the peer_endpoint object is+ * retained by the caller, which must guarantee that it is valid until the+ * handler is called.+ *+ * @param handler The handler to be called when the accept operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ * // On success, the newly accepted socket.+ * typename Protocol::socket::template+ * rebind_executor<executor_type>::other peer+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code+ * void accept_handler(const asio::error_code& error,+ * asio::ip::tcp::socket peer)+ * {+ * if (!error)+ * {+ * // Accept succeeded.+ * }+ * }+ *+ * ...+ *+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint;+ * acceptor.async_accept(endpoint, accept_handler);+ * @endcode+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ typename Protocol::socket::template rebind_executor<+ executor_type>::other)) MoveAcceptHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,+ void (asio::error_code,+ typename Protocol::socket::template+ rebind_executor<executor_type>::other))+ async_accept(endpoint_type& peer_endpoint,+ ASIO_MOVE_ARG(MoveAcceptHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<MoveAcceptHandler,+ void (asio::error_code, typename Protocol::socket::template+ rebind_executor<executor_type>::other)>(+ initiate_async_move_accept(this), handler,+ impl_.get_executor(), &peer_endpoint,+ static_cast<typename Protocol::socket::template+ rebind_executor<executor_type>::other*>(0));+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param ex The I/O executor object to be used for the newly accepted+ * socket.+ *+ * @param peer_endpoint An endpoint object into which the endpoint of the+ * remote peer will be written.+ *+ * @returns A socket object representing the newly accepted connection.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint;+ * asio::ip::tcp::socket socket(+ * acceptor.accept(my_context2, endpoint));+ * @endcode+ */+ template <typename Executor1>+ typename Protocol::socket::template rebind_executor<Executor1>::other+ accept(const Executor1& ex, endpoint_type& peer_endpoint,+ typename enable_if<+ is_executor<Executor1>::value+ || execution::is_executor<Executor1>::value+ >::type* = 0)+ {+ asio::error_code ec;+ typename Protocol::socket::template+ rebind_executor<Executor1>::other peer(ex);+ impl_.get_service().accept(impl_.get_implementation(),+ peer, &peer_endpoint, ec);+ asio::detail::throw_error(ec, "accept");+ return peer;+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param context The I/O execution context object to be used for the newly+ * accepted socket.+ *+ * @param peer_endpoint An endpoint object into which the endpoint of the+ * remote peer will be written.+ *+ * @returns A socket object representing the newly accepted connection.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint;+ * asio::ip::tcp::socket socket(+ * acceptor.accept(my_context2, endpoint));+ * @endcode+ */+ template <typename ExecutionContext>+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other+ accept(ExecutionContext& context, endpoint_type& peer_endpoint,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ {+ asio::error_code ec;+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other peer(context);+ impl_.get_service().accept(impl_.get_implementation(),+ peer, &peer_endpoint, ec);+ asio::detail::throw_error(ec, "accept");+ return peer;+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param ex The I/O executor object to be used for the newly accepted+ * socket.+ *+ * @param peer_endpoint An endpoint object into which the endpoint of the+ * remote peer will be written.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns On success, a socket object representing the newly accepted+ * connection. On error, a socket object where is_open() is false.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint;+ * asio::ip::tcp::socket socket(+ * acceptor.accept(my_context2, endpoint, ec));+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ template <typename Executor1>+ typename Protocol::socket::template rebind_executor<Executor1>::other+ accept(const executor_type& ex,+ endpoint_type& peer_endpoint, asio::error_code& ec,+ typename enable_if<+ is_executor<Executor1>::value+ || execution::is_executor<Executor1>::value+ >::type* = 0)+ {+ typename Protocol::socket::template+ rebind_executor<Executor1>::other peer(ex);+ impl_.get_service().accept(impl_.get_implementation(),+ peer, &peer_endpoint, ec);+ return peer;+ }++ /// Accept a new connection.+ /**+ * This function is used to accept a new connection from a peer. The function+ * call will block until a new connection has been accepted successfully or+ * an error occurs.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param context The I/O execution context object to be used for the newly+ * accepted socket.+ *+ * @param peer_endpoint An endpoint object into which the endpoint of the+ * remote peer will be written.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns On success, a socket object representing the newly accepted+ * connection. On error, a socket object where is_open() is false.+ *+ * @par Example+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint;+ * asio::ip::tcp::socket socket(+ * acceptor.accept(my_context2, endpoint, ec));+ * if (ec)+ * {+ * // An error occurred.+ * }+ * @endcode+ */+ template <typename ExecutionContext>+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other+ accept(ExecutionContext& context,+ endpoint_type& peer_endpoint, asio::error_code& ec,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ {+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other peer(context);+ impl_.get_service().accept(impl_.get_implementation(),+ peer, &peer_endpoint, ec);+ return peer;+ }++ /// Start an asynchronous accept.+ /**+ * This function is used to asynchronously accept a new connection. The+ * function call always returns immediately.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param ex The I/O executor object to be used for the newly accepted+ * socket.+ *+ * @param peer_endpoint An endpoint object into which the endpoint of the+ * remote peer will be written. Ownership of the peer_endpoint object is+ * retained by the caller, which must guarantee that it is valid until the+ * handler is called.+ *+ * @param handler The handler to be called when the accept operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * typename Protocol::socket::template rebind_executor<+ * Executor1>::other peer // On success, the newly accepted socket.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code+ * void accept_handler(const asio::error_code& error,+ * asio::ip::tcp::socket peer)+ * {+ * if (!error)+ * {+ * // Accept succeeded.+ * }+ * }+ *+ * ...+ *+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint;+ * acceptor.async_accept(my_context2, endpoint, accept_handler);+ * @endcode+ */+ template <typename Executor1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ typename Protocol::socket::template rebind_executor<+ Executor1>::other)) MoveAcceptHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,+ void (asio::error_code,+ typename Protocol::socket::template rebind_executor<+ Executor1>::other))+ async_accept(const Executor1& ex, endpoint_type& peer_endpoint,+ ASIO_MOVE_ARG(MoveAcceptHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type),+ typename enable_if<+ is_executor<Executor1>::value+ || execution::is_executor<Executor1>::value+ >::type* = 0)+ {+ typedef typename Protocol::socket::template rebind_executor<+ Executor1>::other other_socket_type;++ return async_initiate<MoveAcceptHandler,+ void (asio::error_code, other_socket_type)>(+ initiate_async_move_accept(this), handler,+ ex, &peer_endpoint,+ static_cast<other_socket_type*>(0));+ }++ /// Start an asynchronous accept.+ /**+ * This function is used to asynchronously accept a new connection. The+ * function call always returns immediately.+ *+ * This overload requires that the Protocol template parameter satisfy the+ * AcceptableProtocol type requirements.+ *+ * @param context The I/O execution context object to be used for the newly+ * accepted socket.+ *+ * @param peer_endpoint An endpoint object into which the endpoint of the+ * remote peer will be written. Ownership of the peer_endpoint object is+ * retained by the caller, which must guarantee that it is valid until the+ * handler is called.+ *+ * @param handler The handler to be called when the accept operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * typename Protocol::socket::template rebind_executor<+ * typename ExecutionContext::executor_type>::other peer+ * // On success, the newly accepted socket.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code+ * void accept_handler(const asio::error_code& error,+ * asio::ip::tcp::socket peer)+ * {+ * if (!error)+ * {+ * // Accept succeeded.+ * }+ * }+ *+ * ...+ *+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::ip::tcp::endpoint endpoint;+ * acceptor.async_accept(my_context2, endpoint, accept_handler);+ * @endcode+ */+ template <typename ExecutionContext,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other)) MoveAcceptHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler,+ void (asio::error_code,+ typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other))+ async_accept(ExecutionContext& context,+ endpoint_type& peer_endpoint,+ ASIO_MOVE_ARG(MoveAcceptHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type),+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ {+ typedef typename Protocol::socket::template rebind_executor<+ typename ExecutionContext::executor_type>::other other_socket_type;++ return async_initiate<MoveAcceptHandler,+ void (asio::error_code, other_socket_type)>(+ initiate_async_move_accept(this), handler,+ context.get_executor(), &peer_endpoint,+ static_cast<other_socket_type*>(0));+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++private:+ // Disallow copying and assignment.+ basic_socket_acceptor(const basic_socket_acceptor&) ASIO_DELETED;+ basic_socket_acceptor& operator=(+ const basic_socket_acceptor&) ASIO_DELETED;++ class initiate_async_wait+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_wait(basic_socket_acceptor* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WaitHandler>+ void operator()(ASIO_MOVE_ARG(WaitHandler) handler, wait_type w) 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(), w,+ handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_socket_acceptor* self_;+ };++ class initiate_async_accept+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_accept(basic_socket_acceptor* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename AcceptHandler, typename Protocol1, typename Executor1>+ void operator()(ASIO_MOVE_ARG(AcceptHandler) handler,+ basic_socket<Protocol1, Executor1>* peer,+ endpoint_type* peer_endpoint) const+ {+ // If you get an error on the following line it means that your handler+ // does not meet the documented type requirements for a AcceptHandler.+ ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check;++ detail::non_const_lvalue<AcceptHandler> handler2(handler);+ self_->impl_.get_service().async_accept(+ self_->impl_.get_implementation(), *peer, peer_endpoint,+ handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_socket_acceptor* self_;+ };++ class initiate_async_move_accept+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_move_accept(basic_socket_acceptor* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename MoveAcceptHandler, typename Executor1, typename Socket>+ void operator()(ASIO_MOVE_ARG(MoveAcceptHandler) handler,+ const Executor1& peer_ex, endpoint_type* peer_endpoint, Socket*) const+ {+ // If you get an error on the following line it means that your handler+ // does not meet the documented type requirements for a MoveAcceptHandler.+ ASIO_MOVE_ACCEPT_HANDLER_CHECK(+ MoveAcceptHandler, handler, Socket) type_check;++ detail::non_const_lvalue<MoveAcceptHandler> handler2(handler);+ self_->impl_.get_service().async_move_accept(+ self_->impl_.get_implementation(), peer_ex, peer_endpoint,+ handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_socket_acceptor* self_;+ };++#if defined(ASIO_WINDOWS_RUNTIME)+ detail::io_object_impl<+ detail::null_socket_service<Protocol>, Executor> impl_;+#elif defined(ASIO_HAS_IOCP)+ detail::io_object_impl<+ detail::win_iocp_socket_service<Protocol>, Executor> impl_;+#else+ detail::io_object_impl<+ detail::reactive_socket_service<Protocol>, Executor> impl_;+#endif+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BASIC_SOCKET_ACCEPTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_socket_iostream.hpp view
@@ -0,0 +1,407 @@+//+// basic_socket_iostream.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_IOSTREAM_HPP+#define ASIO_BASIC_SOCKET_IOSTREAM_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_NO_IOSTREAM)++#include <istream>+#include <ostream>+#include "asio/basic_socket_streambuf.hpp"++#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, Clock, WaitTraits>::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, Clock, WaitTraits>::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"++namespace asio {+namespace detail {++// A separate base class is used to ensure that the streambuf is initialised+// prior to the basic_socket_iostream's basic_iostream base class.+template <typename Protocol, typename Clock, typename WaitTraits>+class socket_iostream_base+{+protected:+ socket_iostream_base()+ {+ }++#if defined(ASIO_HAS_MOVE)+ socket_iostream_base(socket_iostream_base&& other)+ : streambuf_(std::move(other.streambuf_))+ {+ }++ socket_iostream_base(basic_stream_socket<Protocol> s)+ : streambuf_(std::move(s))+ {+ }++ socket_iostream_base& operator=(socket_iostream_base&& other)+ {+ streambuf_ = std::move(other.streambuf_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE)++ basic_socket_streambuf<Protocol, Clock, WaitTraits> streambuf_;+};++} // namespace detail++#if !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)+#define ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename Protocol,+#if defined(ASIO_HAS_BOOST_DATE_TIME) \+ && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+ typename Clock = boost::posix_time::ptime,+ typename WaitTraits = time_traits<Clock> >+#else // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+ typename Clock = chrono::steady_clock,+ typename WaitTraits = wait_traits<Clock> >+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+class basic_socket_iostream;++#endif // !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)++/// Iostream interface for a socket.+#if defined(GENERATING_DOCUMENTATION)+template <typename Protocol,+ typename Clock = chrono::steady_clock,+ typename WaitTraits = wait_traits<Clock> >+#else // defined(GENERATING_DOCUMENTATION)+template <typename Protocol, typename Clock, typename WaitTraits>+#endif // defined(GENERATING_DOCUMENTATION)+class basic_socket_iostream+ : private detail::socket_iostream_base<Protocol, Clock, WaitTraits>,+ public std::basic_iostream<char>+{+private:+ // These typedefs are intended keep this class's implementation independent+ // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.+#if defined(ASIO_HAS_BOOST_DATE_TIME) \+ && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+ typedef WaitTraits traits_helper;+#else // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+ typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)++public:+ /// The protocol type.+ typedef Protocol protocol_type;++ /// The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ /// The clock type.+ typedef Clock clock_type;++#if defined(GENERATING_DOCUMENTATION)+ /// (Deprecated: Use time_point.) The time type.+ typedef typename WaitTraits::time_type time_type;++ /// The time type.+ typedef typename WaitTraits::time_point time_point;++ /// (Deprecated: Use duration.) The duration type.+ typedef typename WaitTraits::duration_type duration_type;++ /// The duration type.+ typedef typename WaitTraits::duration duration;+#else+# if !defined(ASIO_NO_DEPRECATED)+ typedef typename traits_helper::time_type time_type;+ typedef typename traits_helper::duration_type duration_type;+# endif // !defined(ASIO_NO_DEPRECATED)+ typedef typename traits_helper::time_type time_point;+ typedef typename traits_helper::duration_type duration;+#endif++ /// Construct a basic_socket_iostream without establishing a connection.+ basic_socket_iostream()+ : std::basic_iostream<char>(+ &this->detail::socket_iostream_base<+ Protocol, Clock, WaitTraits>::streambuf_)+ {+ this->setf(std::ios_base::unitbuf);+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Construct a basic_socket_iostream from the supplied socket.+ explicit basic_socket_iostream(basic_stream_socket<protocol_type> s)+ : detail::socket_iostream_base<+ Protocol, Clock, WaitTraits>(std::move(s)),+ std::basic_iostream<char>(+ &this->detail::socket_iostream_base<+ Protocol, Clock, WaitTraits>::streambuf_)+ {+ this->setf(std::ios_base::unitbuf);+ }++#if defined(ASIO_HAS_STD_IOSTREAM_MOVE) \+ || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a basic_socket_iostream from another.+ basic_socket_iostream(basic_socket_iostream&& other)+ : detail::socket_iostream_base<+ Protocol, Clock, WaitTraits>(std::move(other)),+ std::basic_iostream<char>(std::move(other))+ {+ this->set_rdbuf(&this->detail::socket_iostream_base<+ Protocol, Clock, WaitTraits>::streambuf_);+ }++ /// Move-assign a basic_socket_iostream from another.+ basic_socket_iostream& operator=(basic_socket_iostream&& other)+ {+ std::basic_iostream<char>::operator=(std::move(other));+ detail::socket_iostream_base<+ Protocol, Clock, WaitTraits>::operator=(std::move(other));+ 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.+ /**+ * This constructor automatically establishes a connection based on the+ * supplied resolver query parameters. The arguments are used to construct+ * 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>+ explicit basic_socket_iostream(T... x)+ : std::basic_iostream<char>(+ &this->detail::socket_iostream_base<+ Protocol, Clock, WaitTraits>::streambuf_)+ {+ this->setf(std::ios_base::unitbuf);+ if (rdbuf()->connect(x...) == 0)+ 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.+ /**+ * This function automatically establishes a connection based on the supplied+ * resolver query parameters. The arguments are used to construct a resolver+ * query object.+ */+ template <typename T1, ..., typename TN>+ void connect(T1 t1, ..., TN tn);+#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)+ template <typename... T>+ void connect(T... x)+ {+ if (rdbuf()->connect(x...) == 0)+ this->setstate(std::ios_base::failbit);+ }+#else+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF)+#endif++ /// Close the connection.+ void close()+ {+ if (rdbuf()->close() == 0)+ this->setstate(std::ios_base::failbit);+ }++ /// Return a pointer to the underlying streambuf.+ basic_socket_streambuf<Protocol, Clock, WaitTraits>* rdbuf() const+ {+ return const_cast<basic_socket_streambuf<Protocol, Clock, WaitTraits>*>(+ &this->detail::socket_iostream_base<+ Protocol, Clock, WaitTraits>::streambuf_);+ }++ /// Get a reference to the underlying socket.+ basic_socket<Protocol>& socket()+ {+ return rdbuf()->socket();+ }++ /// Get the last error associated with the stream.+ /**+ * @return An \c error_code corresponding to the last error from the stream.+ *+ * @par Example+ * To print the error associated with a failure to establish a connection:+ * @code tcp::iostream s("www.boost.org", "http");+ * if (!s)+ * {+ * std::cout << "Error: " << s.error().message() << std::endl;+ * } @endcode+ */+ const asio::error_code& error() const+ {+ return rdbuf()->error();+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use expiry().) Get the stream's expiry time as an absolute+ /// time.+ /**+ * @return An absolute time value representing the stream's expiry time.+ */+ time_point expires_at() const+ {+ return rdbuf()->expires_at();+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Get the stream's expiry time as an absolute time.+ /**+ * @return An absolute time value representing the stream's expiry time.+ */+ time_point expiry() const+ {+ return rdbuf()->expiry();+ }++ /// Set the stream's expiry time as an absolute time.+ /**+ * This function sets the expiry time associated with the stream. Stream+ * operations performed after this time (where the operations cannot be+ * completed using the internal buffers) will fail with the error+ * asio::error::operation_aborted.+ *+ * @param expiry_time The expiry time to be used for the stream.+ */+ void expires_at(const time_point& expiry_time)+ {+ rdbuf()->expires_at(expiry_time);+ }++ /// Set the stream's expiry time relative to now.+ /**+ * This function sets the expiry time associated with the stream. Stream+ * operations performed after this time (where the operations cannot be+ * completed using the internal buffers) will fail with the error+ * asio::error::operation_aborted.+ *+ * @param expiry_time The expiry time to be used for the timer.+ */+ void expires_after(const duration& expiry_time)+ {+ rdbuf()->expires_after(expiry_time);+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use expiry().) Get the stream's expiry time relative to now.+ /**+ * @return A relative time value representing the stream's expiry time.+ */+ duration expires_from_now() const+ {+ return rdbuf()->expires_from_now();+ }++ /// (Deprecated: Use expires_after().) Set the stream's expiry time relative+ /// to now.+ /**+ * This function sets the expiry time associated with the stream. Stream+ * operations performed after this time (where the operations cannot be+ * completed using the internal buffers) will fail with the error+ * asio::error::operation_aborted.+ *+ * @param expiry_time The expiry time to be used for the timer.+ */+ void expires_from_now(const duration& expiry_time)+ {+ rdbuf()->expires_from_now(expiry_time);+ }+#endif // !defined(ASIO_NO_DEPRECATED)++private:+ // Disallow copying and assignment.+ basic_socket_iostream(const basic_socket_iostream&) ASIO_DELETED;+ basic_socket_iostream& operator=(+ const basic_socket_iostream&) ASIO_DELETED;+};++} // namespace asio++#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 // ASIO_BASIC_SOCKET_IOSTREAM_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_socket_streambuf.hpp view
@@ -0,0 +1,687 @@+//+// basic_socket_streambuf.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_STREAMBUF_HPP+#define ASIO_BASIC_SOCKET_STREAMBUF_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_NO_IOSTREAM)++#include <streambuf>+#include <vector>+#include "asio/basic_socket.hpp"+#include "asio/basic_stream_socket.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/io_context.hpp"++#if defined(ASIO_HAS_BOOST_DATE_TIME) \+ && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+# include "asio/detail/deadline_timer_service.hpp"+#else // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+# include "asio/steady_timer.hpp"+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && 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());+// 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()); \+ connect_to_endpoints( \+ resolver.resolve(ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \+ return !ec_ ? this : 0; \+ } \+ /**/++#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// A separate base class is used to ensure that the io_context member is+// initialised prior to the basic_socket_streambuf's basic_socket base class.+class socket_streambuf_io_context+{+protected:+ socket_streambuf_io_context(io_context* ctx)+ : default_io_context_(ctx)+ {+ }++ shared_ptr<io_context> default_io_context_;+};++// A separate base class is used to ensure that the dynamically allocated+// buffers are constructed prior to the basic_socket_streambuf's basic_socket+// base class. This makes moving the socket is the last potentially throwing+// step in the streambuf's move constructor, giving the constructor a strong+// exception safety guarantee.+class socket_streambuf_buffers+{+protected:+ socket_streambuf_buffers()+ : get_buffer_(buffer_size),+ put_buffer_(buffer_size)+ {+ }++ enum { buffer_size = 512 };+ std::vector<char> get_buffer_;+ std::vector<char> put_buffer_;+};++} // namespace detail++#if !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)+#define ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename Protocol,+#if defined(ASIO_HAS_BOOST_DATE_TIME) \+ && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+ typename Clock = boost::posix_time::ptime,+ typename WaitTraits = time_traits<Clock> >+#else // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+ typename Clock = chrono::steady_clock,+ typename WaitTraits = wait_traits<Clock> >+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+class basic_socket_streambuf;++#endif // !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)++/// Iostream streambuf for a socket.+#if defined(GENERATING_DOCUMENTATION)+template <typename Protocol,+ typename Clock = chrono::steady_clock,+ typename WaitTraits = wait_traits<Clock> >+#else // defined(GENERATING_DOCUMENTATION)+template <typename Protocol, typename Clock, typename WaitTraits>+#endif // defined(GENERATING_DOCUMENTATION)+class basic_socket_streambuf+ : public std::streambuf,+ private detail::socket_streambuf_io_context,+ private detail::socket_streambuf_buffers,+#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)+ private basic_socket<Protocol>+#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)+ public basic_socket<Protocol>+#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)+{+private:+ // These typedefs are intended keep this class's implementation independent+ // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.+#if defined(ASIO_HAS_BOOST_DATE_TIME) \+ && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+ typedef WaitTraits traits_helper;+#else // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+ typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)++public:+ /// The protocol type.+ typedef Protocol protocol_type;++ /// The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ /// The clock type.+ typedef Clock clock_type;++#if defined(GENERATING_DOCUMENTATION)+ /// (Deprecated: Use time_point.) The time type.+ typedef typename WaitTraits::time_type time_type;++ /// The time type.+ typedef typename WaitTraits::time_point time_point;++ /// (Deprecated: Use duration.) The duration type.+ typedef typename WaitTraits::duration_type duration_type;++ /// The duration type.+ typedef typename WaitTraits::duration duration;+#else+# if !defined(ASIO_NO_DEPRECATED)+ typedef typename traits_helper::time_type time_type;+ typedef typename traits_helper::duration_type duration_type;+# endif // !defined(ASIO_NO_DEPRECATED)+ typedef typename traits_helper::time_type time_point;+ typedef typename traits_helper::duration_type duration;+#endif++ /// Construct a basic_socket_streambuf without establishing a connection.+ basic_socket_streambuf()+ : detail::socket_streambuf_io_context(new io_context),+ basic_socket<Protocol>(*default_io_context_),+ expiry_time_(max_expiry_time())+ {+ init_buffers();+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Construct a basic_socket_streambuf from the supplied socket.+ explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s)+ : detail::socket_streambuf_io_context(0),+ basic_socket<Protocol>(std::move(s)),+ expiry_time_(max_expiry_time())+ {+ init_buffers();+ }++ /// Move-construct a basic_socket_streambuf from another.+ basic_socket_streambuf(basic_socket_streambuf&& other)+ : detail::socket_streambuf_io_context(other),+ basic_socket<Protocol>(std::move(other.socket())),+ ec_(other.ec_),+ expiry_time_(other.expiry_time_)+ {+ get_buffer_.swap(other.get_buffer_);+ put_buffer_.swap(other.put_buffer_);+ setg(other.eback(), other.gptr(), other.egptr());+ setp(other.pptr(), other.epptr());+ other.ec_ = asio::error_code();+ other.expiry_time_ = max_expiry_time();+ other.init_buffers();+ }++ /// Move-assign a basic_socket_streambuf from another.+ basic_socket_streambuf& operator=(basic_socket_streambuf&& other)+ {+ this->close();+ socket() = std::move(other.socket());+ detail::socket_streambuf_io_context::operator=(other);+ ec_ = other.ec_;+ expiry_time_ = other.expiry_time_;+ get_buffer_.swap(other.get_buffer_);+ put_buffer_.swap(other.put_buffer_);+ setg(other.eback(), other.gptr(), other.egptr());+ setp(other.pptr(), other.epptr());+ other.ec_ = asio::error_code();+ other.expiry_time_ = max_expiry_time();+ other.put_buffer_.resize(buffer_size);+ other.init_buffers();+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destructor flushes buffered data.+ virtual ~basic_socket_streambuf()+ {+ if (pptr() != pbase())+ overflow(traits_type::eof());+ }++ /// Establish a connection.+ /**+ * This function establishes a connection to the specified endpoint.+ *+ * @return \c this if a connection was successfully established, a null+ * pointer otherwise.+ */+ basic_socket_streambuf* connect(const endpoint_type& endpoint)+ {+ init_buffers();+ ec_ = asio::error_code();+ this->connect_to_endpoints(&endpoint, &endpoint + 1);+ return !ec_ ? this : 0;+ }++#if defined(GENERATING_DOCUMENTATION)+ /// Establish a connection.+ /**+ * This function automatically establishes a connection based on the supplied+ * resolver query parameters. The arguments are used to construct a resolver+ * query object.+ *+ * @return \c this if a connection was successfully established, a null+ * pointer otherwise.+ */+ template <typename T1, ..., typename TN>+ basic_socket_streambuf* connect(T1 t1, ..., TN tn);+#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)+ template <typename... T>+ basic_socket_streambuf* connect(T... x)+ {+ init_buffers();+ typedef typename Protocol::resolver resolver_type;+ resolver_type resolver(socket().get_executor());+ connect_to_endpoints(resolver.resolve(x..., ec_));+ return !ec_ ? this : 0;+ }+#else+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF)+#endif++ /// Close the connection.+ /**+ * @return \c this if a connection was successfully established, a null+ * pointer otherwise.+ */+ basic_socket_streambuf* close()+ {+ sync();+ socket().close(ec_);+ if (!ec_)+ init_buffers();+ return !ec_ ? this : 0;+ }++ /// Get a reference to the underlying socket.+ basic_socket<Protocol>& socket()+ {+ return *this;+ }++ /// Get the last error associated with the stream buffer.+ /**+ * @return An \c error_code corresponding to the last error from the stream+ * buffer.+ */+ const asio::error_code& error() const+ {+ return ec_;+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use error().) Get the last error associated with the stream+ /// buffer.+ /**+ * @return An \c error_code corresponding to the last error from the stream+ * buffer.+ */+ const asio::error_code& puberror() const+ {+ return error();+ }++ /// (Deprecated: Use expiry().) Get the stream buffer's expiry time as an+ /// absolute time.+ /**+ * @return An absolute time value representing the stream buffer's expiry+ * time.+ */+ time_point expires_at() const+ {+ return expiry_time_;+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Get the stream buffer's expiry time as an absolute time.+ /**+ * @return An absolute time value representing the stream buffer's expiry+ * time.+ */+ time_point expiry() const+ {+ return expiry_time_;+ }++ /// Set the stream buffer's expiry time as an absolute time.+ /**+ * This function sets the expiry time associated with the stream. Stream+ * operations performed after this time (where the operations cannot be+ * completed using the internal buffers) will fail with the error+ * asio::error::operation_aborted.+ *+ * @param expiry_time The expiry time to be used for the stream.+ */+ void expires_at(const time_point& expiry_time)+ {+ expiry_time_ = expiry_time;+ }++ /// Set the stream buffer's expiry time relative to now.+ /**+ * This function sets the expiry time associated with the stream. Stream+ * operations performed after this time (where the operations cannot be+ * completed using the internal buffers) will fail with the error+ * asio::error::operation_aborted.+ *+ * @param expiry_time The expiry time to be used for the timer.+ */+ void expires_after(const duration& expiry_time)+ {+ expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use expiry().) Get the stream buffer's expiry time relative+ /// to now.+ /**+ * @return A relative time value representing the stream buffer's expiry time.+ */+ duration expires_from_now() const+ {+ return traits_helper::subtract(expires_at(), traits_helper::now());+ }++ /// (Deprecated: Use expires_after().) Set the stream buffer's expiry time+ /// relative to now.+ /**+ * This function sets the expiry time associated with the stream. Stream+ * operations performed after this time (where the operations cannot be+ * completed using the internal buffers) will fail with the error+ * asio::error::operation_aborted.+ *+ * @param expiry_time The expiry time to be used for the timer.+ */+ void expires_from_now(const duration& expiry_time)+ {+ expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);+ }+#endif // !defined(ASIO_NO_DEPRECATED)++protected:+ int_type underflow()+ {+#if defined(ASIO_WINDOWS_RUNTIME)+ ec_ = asio::error::operation_not_supported;+ return traits_type::eof();+#else // defined(ASIO_WINDOWS_RUNTIME)+ if (gptr() != egptr())+ return traits_type::eof();++ for (;;)+ {+ // Check if we are past the expiry time.+ if (traits_helper::less_than(expiry_time_, traits_helper::now()))+ {+ ec_ = asio::error::timed_out;+ return traits_type::eof();+ }++ // Try to complete the operation without blocking.+ if (!socket().native_non_blocking())+ socket().native_non_blocking(true, ec_);+ detail::buffer_sequence_adapter<mutable_buffer, mutable_buffer>+ bufs(asio::buffer(get_buffer_) + putback_max);+ detail::signed_size_type bytes = detail::socket_ops::recv(+ socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);++ // Check if operation succeeded.+ if (bytes > 0)+ {+ setg(&get_buffer_[0], &get_buffer_[0] + putback_max,+ &get_buffer_[0] + putback_max + bytes);+ return traits_type::to_int_type(*gptr());+ }++ // Check for EOF.+ if (bytes == 0)+ {+ ec_ = asio::error::eof;+ return traits_type::eof();+ }++ // Operation failed.+ if (ec_ != asio::error::would_block+ && ec_ != asio::error::try_again)+ return traits_type::eof();++ // Wait for socket to become ready.+ if (detail::socket_ops::poll_read(+ socket().native_handle(), 0, timeout(), ec_) < 0)+ return traits_type::eof();+ }+#endif // defined(ASIO_WINDOWS_RUNTIME)+ }++ int_type overflow(int_type c)+ {+#if defined(ASIO_WINDOWS_RUNTIME)+ ec_ = asio::error::operation_not_supported;+ return traits_type::eof();+#else // defined(ASIO_WINDOWS_RUNTIME)+ char_type ch = traits_type::to_char_type(c);++ // Determine what needs to be sent.+ const_buffer output_buffer;+ if (put_buffer_.empty())+ {+ if (traits_type::eq_int_type(c, traits_type::eof()))+ return traits_type::not_eof(c); // Nothing to do.+ output_buffer = asio::buffer(&ch, sizeof(char_type));+ }+ else+ {+ output_buffer = asio::buffer(pbase(),+ (pptr() - pbase()) * sizeof(char_type));+ }++ while (output_buffer.size() > 0)+ {+ // Check if we are past the expiry time.+ if (traits_helper::less_than(expiry_time_, traits_helper::now()))+ {+ ec_ = asio::error::timed_out;+ return traits_type::eof();+ }++ // Try to complete the operation without blocking.+ if (!socket().native_non_blocking())+ socket().native_non_blocking(true, ec_);+ detail::buffer_sequence_adapter<+ const_buffer, const_buffer> bufs(output_buffer);+ detail::signed_size_type bytes = detail::socket_ops::send(+ socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);++ // Check if operation succeeded.+ if (bytes > 0)+ {+ output_buffer += static_cast<std::size_t>(bytes);+ continue;+ }++ // Operation failed.+ if (ec_ != asio::error::would_block+ && ec_ != asio::error::try_again)+ return traits_type::eof();++ // Wait for socket to become ready.+ if (detail::socket_ops::poll_write(+ socket().native_handle(), 0, timeout(), ec_) < 0)+ return traits_type::eof();+ }++ if (!put_buffer_.empty())+ {+ setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());++ // If the new character is eof then our work here is done.+ if (traits_type::eq_int_type(c, traits_type::eof()))+ return traits_type::not_eof(c);++ // Add the new character to the output buffer.+ *pptr() = ch;+ pbump(1);+ }++ return c;+#endif // defined(ASIO_WINDOWS_RUNTIME)+ }++ int sync()+ {+ return overflow(traits_type::eof());+ }++ std::streambuf* setbuf(char_type* s, std::streamsize n)+ {+ if (pptr() == pbase() && s == 0 && n == 0)+ {+ put_buffer_.clear();+ setp(0, 0);+ sync();+ return this;+ }++ return 0;+ }++private:+ // Disallow copying and assignment.+ basic_socket_streambuf(const basic_socket_streambuf&) ASIO_DELETED;+ basic_socket_streambuf& operator=(+ const basic_socket_streambuf&) ASIO_DELETED;++ void init_buffers()+ {+ setg(&get_buffer_[0],+ &get_buffer_[0] + putback_max,+ &get_buffer_[0] + putback_max);++ if (put_buffer_.empty())+ setp(0, 0);+ else+ setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());+ }++ int timeout() const+ {+ int64_t msec = traits_helper::to_posix_duration(+ traits_helper::subtract(expiry_time_,+ traits_helper::now())).total_milliseconds();+ if (msec > (std::numeric_limits<int>::max)())+ msec = (std::numeric_limits<int>::max)();+ else if (msec < 0)+ msec = 0;+ return static_cast<int>(msec);+ }++ template <typename EndpointSequence>+ void connect_to_endpoints(const EndpointSequence& endpoints)+ {+ this->connect_to_endpoints(endpoints.begin(), endpoints.end());+ }++ template <typename EndpointIterator>+ void connect_to_endpoints(EndpointIterator begin, EndpointIterator end)+ {+#if defined(ASIO_WINDOWS_RUNTIME)+ ec_ = asio::error::operation_not_supported;+#else // defined(ASIO_WINDOWS_RUNTIME)+ if (ec_)+ return;++ ec_ = asio::error::not_found;+ for (EndpointIterator i = begin; i != end; ++i)+ {+ // Check if we are past the expiry time.+ if (traits_helper::less_than(expiry_time_, traits_helper::now()))+ {+ ec_ = asio::error::timed_out;+ return;+ }++ // Close and reopen the socket.+ typename Protocol::endpoint ep(*i);+ socket().close(ec_);+ socket().open(ep.protocol(), ec_);+ if (ec_)+ continue;++ // Try to complete the operation without blocking.+ if (!socket().native_non_blocking())+ socket().native_non_blocking(true, ec_);+ detail::socket_ops::connect(socket().native_handle(),+ ep.data(), ep.size(), ec_);++ // Check if operation succeeded.+ if (!ec_)+ return;++ // Operation failed.+ if (ec_ != asio::error::in_progress+ && ec_ != asio::error::would_block)+ continue;++ // Wait for socket to become ready.+ if (detail::socket_ops::poll_connect(+ socket().native_handle(), timeout(), ec_) < 0)+ continue;++ // Get the error code from the connect operation.+ int connect_error = 0;+ size_t connect_error_len = sizeof(connect_error);+ if (detail::socket_ops::getsockopt(socket().native_handle(), 0,+ SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec_)+ == detail::socket_error_retval)+ return;++ // Check the result of the connect operation.+ ec_ = asio::error_code(connect_error,+ asio::error::get_system_category());+ if (!ec_)+ return;+ }+#endif // defined(ASIO_WINDOWS_RUNTIME)+ }++ // Helper function to get the maximum expiry time.+ static time_point max_expiry_time()+ {+#if defined(ASIO_HAS_BOOST_DATE_TIME) \+ && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+ return boost::posix_time::pos_infin;+#else // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+ return (time_point::max)();+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)+ // && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)+ }++ enum { putback_max = 8 };+ asio::error_code ec_;+ time_point expiry_time_;+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)+# undef ASIO_PRIVATE_CONNECT_DEF+#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)++#endif // !defined(ASIO_NO_IOSTREAM)++#endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_stream_socket.hpp view
@@ -0,0 +1,1053 @@+//+// basic_stream_socket.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_HPP+#define ASIO_BASIC_STREAM_SOCKET_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/async_result.hpp"+#include "asio/basic_socket.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_SOCKET_FWD_DECL)+#define ASIO_BASIC_STREAM_SOCKET_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename Protocol, typename Executor = any_io_executor>+class basic_stream_socket;++#endif // !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL)++/// Provides stream-oriented socket functionality.+/**+ * The basic_stream_socket class template provides asynchronous and blocking+ * stream-oriented socket functionality.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Concepts:+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.+ */+template <typename Protocol, typename Executor>+class basic_stream_socket+ : public basic_socket<Protocol, Executor>+{+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_stream_socket<Protocol, Executor1> other;+ };++ /// The native representation of a socket.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined native_handle_type;+#else+ typedef typename basic_socket<Protocol,+ Executor>::native_handle_type native_handle_type;+#endif++ /// The protocol type.+ typedef Protocol protocol_type;++ /// The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ /// Construct a basic_stream_socket without opening it.+ /**+ * This constructor creates a stream 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 ex The I/O executor that the socket will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the socket.+ */+ explicit basic_stream_socket(const executor_type& ex)+ : basic_socket<Protocol, Executor>(ex)+ {+ }++ /// Construct a basic_stream_socket without opening it.+ /**+ * This constructor creates a stream 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_stream_socket(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context)+ {+ }++ /// Construct and open a basic_stream_socket.+ /**+ * This constructor creates and opens a stream socket. The socket needs to be+ * connected or accepted before data can be sent or received on it.+ *+ * @param ex 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.+ */+ basic_stream_socket(const executor_type& ex, const protocol_type& protocol)+ : basic_socket<Protocol, Executor>(ex, protocol)+ {+ }++ /// Construct and open a basic_stream_socket.+ /**+ * This constructor creates and opens a stream 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_stream_socket(ExecutionContext& context, const protocol_type& protocol,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context, protocol)+ {+ }++ /// Construct a basic_stream_socket, opening it and binding it to the given+ /// local endpoint.+ /**+ * This constructor creates a stream 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 ex 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 stream+ * socket will be bound.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_stream_socket(const executor_type& ex, const endpoint_type& endpoint)+ : basic_socket<Protocol, Executor>(ex, endpoint)+ {+ }++ /// Construct a basic_stream_socket, opening it and binding it to the given+ /// local endpoint.+ /**+ * This constructor creates a stream 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 stream+ * socket will be bound.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_stream_socket(ExecutionContext& context, const endpoint_type& endpoint,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context, endpoint)+ {+ }++ /// Construct a basic_stream_socket on an existing native socket.+ /**+ * This constructor creates a stream socket object to hold an existing native+ * socket.+ *+ * @param ex 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.+ */+ basic_stream_socket(const executor_type& ex,+ const protocol_type& protocol, const native_handle_type& native_socket)+ : basic_socket<Protocol, Executor>(ex, protocol, native_socket)+ {+ }++ /// Construct a basic_stream_socket on an existing native socket.+ /**+ * This constructor creates a stream 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_stream_socket(ExecutionContext& context,+ const protocol_type& protocol, const native_handle_type& native_socket,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(context, protocol, native_socket)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a basic_stream_socket from another.+ /**+ * This constructor moves a stream socket from one object to another.+ *+ * @param other The other basic_stream_socket 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_socket(const executor_type&)+ * constructor.+ */+ basic_stream_socket(basic_stream_socket&& other) ASIO_NOEXCEPT+ : basic_socket<Protocol, Executor>(std::move(other))+ {+ }++ /// Move-assign a basic_stream_socket from another.+ /**+ * This assignment operator moves a stream socket from one object to another.+ *+ * @param other The other basic_stream_socket 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_socket(const executor_type&)+ * constructor.+ */+ basic_stream_socket& operator=(basic_stream_socket&& other)+ {+ basic_socket<Protocol, Executor>::operator=(std::move(other));+ return *this;+ }++ /// Move-construct a basic_stream_socket from a socket of another protocol+ /// type.+ /**+ * This constructor moves a stream socket from one object to another.+ *+ * @param other The other basic_stream_socket 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_socket(const executor_type&)+ * constructor.+ */+ template <typename Protocol1, typename Executor1>+ basic_stream_socket(basic_stream_socket<Protocol1, Executor1>&& other,+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value+ >::type* = 0)+ : basic_socket<Protocol, Executor>(std::move(other))+ {+ }++ /// Move-assign a basic_stream_socket from a socket of another protocol type.+ /**+ * This assignment operator moves a stream socket from one object to another.+ *+ * @param other The other basic_stream_socket 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_socket(const executor_type&)+ * constructor.+ */+ template <typename Protocol1, typename Executor1>+ typename enable_if<+ is_convertible<Protocol1, Protocol>::value+ && is_convertible<Executor1, Executor>::value,+ basic_stream_socket&+ >::type operator=(basic_stream_socket<Protocol1, Executor1>&& other)+ {+ basic_socket<Protocol, Executor>::operator=(std::move(other));+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destroys the socket.+ /**+ * This function destroys the socket, cancelling any outstanding asynchronous+ * operations associated with the socket as if by calling @c cancel.+ */+ ~basic_stream_socket()+ {+ }++ /// Send some data on the socket.+ /**+ * This function is used to send data on the stream socket. The function+ * call will block until one or more bytes of the data has been sent+ * successfully, or an until error occurs.+ *+ * @param buffers One or more data buffers to be sent on the socket.+ *+ * @returns The number of bytes sent.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The send 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 send a single data buffer use the @ref buffer function as follows:+ * @code+ * socket.send(asio::buffer(data, size));+ * @endcode+ * See the @ref buffer documentation for information on sending multiple+ * buffers in one go, and how to use it with arrays, boost::array or+ * std::vector.+ */+ template <typename ConstBufferSequence>+ std::size_t send(const ConstBufferSequence& buffers)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().send(+ this->impl_.get_implementation(), buffers, 0, ec);+ asio::detail::throw_error(ec, "send");+ return s;+ }++ /// Send some data on the socket.+ /**+ * This function is used to send data on the stream socket. The function+ * call will block until one or more bytes of the data has been sent+ * successfully, or an until error occurs.+ *+ * @param buffers One or more data buffers to be sent on the socket.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @returns The number of bytes sent.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The send 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 send a single data buffer use the @ref buffer function as follows:+ * @code+ * socket.send(asio::buffer(data, size), 0);+ * @endcode+ * See the @ref buffer documentation for information on sending multiple+ * buffers in one go, and how to use it with arrays, boost::array or+ * std::vector.+ */+ template <typename ConstBufferSequence>+ std::size_t send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().send(+ this->impl_.get_implementation(), buffers, flags, ec);+ asio::detail::throw_error(ec, "send");+ return s;+ }++ /// Send some data on the socket.+ /**+ * This function is used to send data on the stream socket. The function+ * call will block until one or more bytes of the data has been sent+ * successfully, or an until error occurs.+ *+ * @param buffers One or more data buffers to be sent on the socket.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes sent. Returns 0 if an error occurred.+ *+ * @note The send 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 send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ return this->impl_.get_service().send(+ this->impl_.get_implementation(), buffers, flags, ec);+ }++ /// Start an asynchronous send.+ /**+ * This function is used to asynchronously send data on the stream socket.+ * The function call always returns immediately.+ *+ * @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+ * memory blocks is retained by the caller, which must guarantee that they+ * remain valid until the handler is called.+ *+ * @param handler The handler to be called when the send operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes sent.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The send 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 send a single data buffer use the @ref buffer function as follows:+ * @code+ * socket.async_send(asio::buffer(data, size), handler);+ * @endcode+ * See the @ref buffer documentation for information on sending 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)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_send(const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send(this), handler,+ buffers, socket_base::message_flags(0));+ }++ /// Start an asynchronous send.+ /**+ * This function is used to asynchronously send data on the stream socket.+ * The function call always returns immediately.+ *+ * @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+ * memory blocks is retained by the caller, which must guarantee that they+ * remain valid until the handler is called.+ *+ * @param flags Flags specifying how the send call is to be made.+ *+ * @param handler The handler to be called when the send operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes sent.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The send 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 send a single data buffer use the @ref buffer function as follows:+ * @code+ * socket.async_send(asio::buffer(data, size), 0, handler);+ * @endcode+ * See the @ref buffer documentation for information on sending 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)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_send(const ConstBufferSequence& buffers,+ socket_base::message_flags flags,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send(this), handler, buffers, flags);+ }++ /// Receive some data on the socket.+ /**+ * This function is used to receive data on the stream socket. The function+ * call will block until one or more bytes of data has been received+ * successfully, or until an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @returns The number of bytes received.+ *+ * @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 receive operation may not receive 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 receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * socket.receive(asio::buffer(data, size));+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence>+ std::size_t receive(const MutableBufferSequence& buffers)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive(+ this->impl_.get_implementation(), buffers, 0, ec);+ asio::detail::throw_error(ec, "receive");+ return s;+ }++ /// Receive some data on the socket.+ /**+ * This function is used to receive data on the stream socket. The function+ * call will block until one or more bytes of data has been received+ * successfully, or until an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @returns The number of bytes received.+ *+ * @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 receive operation may not receive 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 receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * socket.receive(asio::buffer(data, size), 0);+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence>+ std::size_t receive(const MutableBufferSequence& buffers,+ socket_base::message_flags flags)+ {+ asio::error_code ec;+ std::size_t s = this->impl_.get_service().receive(+ this->impl_.get_implementation(), buffers, flags, ec);+ asio::detail::throw_error(ec, "receive");+ return s;+ }++ /// Receive some data on a connected socket.+ /**+ * This function is used to receive data on the stream socket. The function+ * call will block until one or more bytes of data has been received+ * successfully, or until an error occurs.+ *+ * @param buffers One or more buffers into which the data will be received.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes received. Returns 0 if an error occurred.+ *+ * @note The receive operation may not receive 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 receive(const MutableBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ return this->impl_.get_service().receive(+ this->impl_.get_implementation(), buffers, flags, ec);+ }++ /// Start an asynchronous receive.+ /**+ * This function is used to asynchronously receive data from the stream+ * socket. The function call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The receive operation may not receive 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 received before the asynchronous+ * operation completes.+ *+ * @par Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * socket.async_receive(asio::buffer(data, size), handler);+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive(const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive(this), handler,+ buffers, socket_base::message_flags(0));+ }++ /// Start an asynchronous receive.+ /**+ * This function is used to asynchronously receive data from the stream+ * socket. The function call always returns immediately.+ *+ * @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+ * underlying memory blocks is retained by the caller, which must guarantee+ * that they remain valid until the handler is called.+ *+ * @param flags Flags specifying how the receive call is to be made.+ *+ * @param handler The handler to be called when the receive operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes received.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note The receive operation may not receive 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 received before the asynchronous+ * operation completes.+ *+ * @par Example+ * To receive into a single data buffer use the @ref buffer function as+ * follows:+ * @code+ * socket.async_receive(asio::buffer(data, size), 0, handler);+ * @endcode+ * 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+ * std::vector.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_receive(const MutableBufferSequence& buffers,+ socket_base::message_flags flags,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive(this), handler, buffers, flags);+ }++ /// Write some data to the socket.+ /**+ * This function is used to write data to the stream socket. 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 socket.+ *+ * @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+ * socket.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().send(+ this->impl_.get_implementation(), buffers, 0, ec);+ asio::detail::throw_error(ec, "write_some");+ return s;+ }++ /// Write some data to the socket.+ /**+ * This function is used to write data to the stream socket. 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 socket.+ *+ * @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().send(+ this->impl_.get_implementation(), buffers, 0, ec);+ }++ /// Start an asynchronous write.+ /**+ * This function is used to asynchronously write data to the stream socket.+ * The function call always returns immediately.+ *+ * @param buffers One or more data buffers to be written to the socket.+ * 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 handler is called.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the 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 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().+ *+ * @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+ * socket.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)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_write_some(const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_send(this), handler,+ buffers, socket_base::message_flags(0));+ }++ /// Read some data from the socket.+ /**+ * This function is used to read data from the stream socket. 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+ * socket.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().receive(+ this->impl_.get_implementation(), buffers, 0, ec);+ asio::detail::throw_error(ec, "read_some");+ return s;+ }++ /// Read some data from the socket.+ /**+ * This function is used to read data from the stream socket. 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().receive(+ this->impl_.get_implementation(), buffers, 0, ec);+ }++ /// Start an asynchronous read.+ /**+ * This function is used to asynchronously read data from the stream socket.+ * The function call 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 handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the 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 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().+ *+ * @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+ * socket.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)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_read_some(const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_receive(this), handler,+ buffers, socket_base::message_flags(0));+ }++private:+ // Disallow copying and assignment.+ basic_stream_socket(const basic_stream_socket&) ASIO_DELETED;+ basic_stream_socket& operator=(const basic_stream_socket&) ASIO_DELETED;++ class initiate_async_send+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_send(basic_stream_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(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_stream_socket* self_;+ };++ class initiate_async_receive+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_receive(basic_stream_socket* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ const MutableBufferSequence& 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 ReadHandler.+ ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;++ detail::non_const_lvalue<ReadHandler> handler2(handler);+ self_->impl_.get_service().async_receive(+ self_->impl_.get_implementation(), buffers, flags,+ handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_stream_socket* self_;+ };+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BASIC_STREAM_SOCKET_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_streambuf.hpp view
@@ -0,0 +1,452 @@+//+// basic_streambuf.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STREAMBUF_HPP+#define ASIO_BASIC_STREAMBUF_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_NO_IOSTREAM)++#include <algorithm>+#include <cstring>+#include <stdexcept>+#include <streambuf>+#include <vector>+#include "asio/basic_streambuf_fwd.hpp"+#include "asio/buffer.hpp"+#include "asio/detail/limits.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/throw_exception.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Automatically resizable buffer class based on std::streambuf.+/**+ * The @c basic_streambuf class is derived from @c std::streambuf to associate+ * the streambuf's input and output sequences with one or more character+ * arrays. These character arrays are internal to the @c basic_streambuf+ * object, but direct access to the array elements is provided to permit them+ * to be used efficiently with I/O operations. Characters written to the output+ * sequence of a @c basic_streambuf object are appended to the input sequence+ * of the same object.+ *+ * The @c basic_streambuf class's public interface is intended to permit the+ * following implementation strategies:+ *+ * @li A single contiguous character array, which is reallocated as necessary+ * to accommodate changes in the size of the character sequence. This is the+ * implementation approach currently used in Asio.+ *+ * @li A sequence of one or more character arrays, where each array is of the+ * same size. Additional character array objects are appended to the sequence+ * to accommodate changes in the size of the character sequence.+ *+ * @li A sequence of one or more character arrays of varying sizes. Additional+ * character array objects are appended to the sequence to accommodate changes+ * in the size of the character sequence.+ *+ * The constructor for basic_streambuf accepts a @c size_t argument specifying+ * the maximum of the sum of the sizes of the input sequence and output+ * sequence. During the lifetime of the @c basic_streambuf object, the following+ * invariant holds:+ * @code size() <= max_size()@endcode+ * Any member function that would, if successful, cause the invariant to be+ * violated shall throw an exception of class @c std::length_error.+ *+ * The constructor for @c basic_streambuf takes an Allocator argument. A copy+ * of this argument is used for any memory allocation performed, by the+ * constructor and by all member functions, during the lifetime of each @c+ * basic_streambuf object.+ *+ * @par Examples+ * Writing directly from an streambuf to a socket:+ * @code+ * asio::streambuf b;+ * std::ostream os(&b);+ * os << "Hello, World!\n";+ *+ * // try sending some data in input sequence+ * size_t n = sock.send(b.data());+ *+ * b.consume(n); // sent data is removed from input sequence+ * @endcode+ *+ * Reading from a socket directly into a streambuf:+ * @code+ * asio::streambuf b;+ *+ * // reserve 512 bytes in output sequence+ * asio::streambuf::mutable_buffers_type bufs = b.prepare(512);+ *+ * size_t n = sock.receive(bufs);+ *+ * // received data is "committed" from output sequence to input sequence+ * b.commit(n);+ *+ * std::istream is(&b);+ * std::string s;+ * is >> s;+ * @endcode+ */+#if defined(GENERATING_DOCUMENTATION)+template <typename Allocator = std::allocator<char> >+#else+template <typename Allocator>+#endif+class basic_streambuf+ : public std::streambuf,+ private noncopyable+{+public:+#if defined(GENERATING_DOCUMENTATION)+ /// The type used to represent the input sequence as a list of buffers.+ typedef implementation_defined const_buffers_type;++ /// The type used to represent the output sequence as a list of buffers.+ typedef implementation_defined mutable_buffers_type;+#else+ typedef ASIO_CONST_BUFFER const_buffers_type;+ typedef ASIO_MUTABLE_BUFFER mutable_buffers_type;+#endif++ /// Construct a basic_streambuf object.+ /**+ * Constructs a streambuf with the specified maximum size. The initial size+ * of the streambuf's input sequence is 0.+ */+ explicit basic_streambuf(+ std::size_t maximum_size = (std::numeric_limits<std::size_t>::max)(),+ const Allocator& allocator = Allocator())+ : max_size_(maximum_size),+ buffer_(allocator)+ {+ std::size_t pend = (std::min<std::size_t>)(max_size_, buffer_delta);+ buffer_.resize((std::max<std::size_t>)(pend, 1));+ setg(&buffer_[0], &buffer_[0], &buffer_[0]);+ setp(&buffer_[0], &buffer_[0] + pend);+ }++ /// Get the size of the input sequence.+ /**+ * @returns The size of the input sequence. The value is equal to that+ * calculated for @c s in the following code:+ * @code+ * size_t s = 0;+ * const_buffers_type bufs = data();+ * const_buffers_type::const_iterator i = bufs.begin();+ * while (i != bufs.end())+ * {+ * const_buffer buf(*i++);+ * s += buf.size();+ * }+ * @endcode+ */+ std::size_t size() const ASIO_NOEXCEPT+ {+ return pptr() - gptr();+ }++ /// Get the maximum size of the basic_streambuf.+ /**+ * @returns The allowed maximum of the sum of the sizes of the input sequence+ * and output sequence.+ */+ std::size_t max_size() const ASIO_NOEXCEPT+ {+ return max_size_;+ }++ /// Get the current capacity of the basic_streambuf.+ /**+ * @returns The current total capacity of the streambuf, i.e. for both the+ * input sequence and output sequence.+ */+ std::size_t capacity() const ASIO_NOEXCEPT+ {+ return buffer_.capacity();+ }++ /// Get a list of buffers that represents the input sequence.+ /**+ * @returns An object of type @c const_buffers_type that satisfies+ * ConstBufferSequence requirements, representing all character arrays in the+ * input sequence.+ *+ * @note The returned object is invalidated by any @c basic_streambuf member+ * function that modifies the input sequence or output sequence.+ */+ const_buffers_type data() const ASIO_NOEXCEPT+ {+ return asio::buffer(asio::const_buffer(gptr(),+ (pptr() - gptr()) * sizeof(char_type)));+ }++ /// Get a list of buffers that represents the output sequence, with the given+ /// size.+ /**+ * Ensures that the output sequence can accommodate @c n characters,+ * reallocating character array objects as necessary.+ *+ * @returns An object of type @c mutable_buffers_type that satisfies+ * MutableBufferSequence requirements, representing character array objects+ * at the start of the output sequence such that the sum of the buffer sizes+ * is @c n.+ *+ * @throws std::length_error If <tt>size() + n > max_size()</tt>.+ *+ * @note The returned object is invalidated by any @c basic_streambuf member+ * function that modifies the input sequence or output sequence.+ */+ mutable_buffers_type prepare(std::size_t n)+ {+ reserve(n);+ return asio::buffer(asio::mutable_buffer(+ pptr(), n * sizeof(char_type)));+ }++ /// Move characters from the output sequence to the input sequence.+ /**+ * Appends @c n characters from the start of the output sequence to the input+ * sequence. The beginning of the output sequence is advanced by @c n+ * characters.+ *+ * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and+ * no intervening operations that modify the input or output sequence.+ *+ * @note If @c n is greater than the size of the output sequence, the entire+ * output sequence is moved to the input sequence and no error is issued.+ */+ void commit(std::size_t n)+ {+ n = std::min<std::size_t>(n, epptr() - pptr());+ pbump(static_cast<int>(n));+ setg(eback(), gptr(), pptr());+ }++ /// Remove characters from the input sequence.+ /**+ * Removes @c n characters from the beginning of the input sequence.+ *+ * @note If @c n is greater than the size of the input sequence, the entire+ * input sequence is consumed and no error is issued.+ */+ void consume(std::size_t n)+ {+ if (egptr() < pptr())+ setg(&buffer_[0], gptr(), pptr());+ if (gptr() + n > pptr())+ n = pptr() - gptr();+ gbump(static_cast<int>(n));+ }++protected:+ enum { buffer_delta = 128 };++ /// Override std::streambuf behaviour.+ /**+ * Behaves according to the specification of @c std::streambuf::underflow().+ */+ int_type underflow()+ {+ if (gptr() < pptr())+ {+ setg(&buffer_[0], gptr(), pptr());+ return traits_type::to_int_type(*gptr());+ }+ else+ {+ return traits_type::eof();+ }+ }++ /// Override std::streambuf behaviour.+ /**+ * Behaves according to the specification of @c std::streambuf::overflow(),+ * with the specialisation that @c std::length_error is thrown if appending+ * the character to the input sequence would require the condition+ * <tt>size() > max_size()</tt> to be true.+ */+ int_type overflow(int_type c)+ {+ if (!traits_type::eq_int_type(c, traits_type::eof()))+ {+ if (pptr() == epptr())+ {+ std::size_t buffer_size = pptr() - gptr();+ if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta)+ {+ reserve(max_size_ - buffer_size);+ }+ else+ {+ reserve(buffer_delta);+ }+ }++ *pptr() = traits_type::to_char_type(c);+ pbump(1);+ return c;+ }++ return traits_type::not_eof(c);+ }++ void reserve(std::size_t n)+ {+ // Get current stream positions as offsets.+ std::size_t gnext = gptr() - &buffer_[0];+ std::size_t pnext = pptr() - &buffer_[0];+ std::size_t pend = epptr() - &buffer_[0];++ // Check if there is already enough space in the put area.+ if (n <= pend - pnext)+ {+ return;+ }++ // Shift existing contents of get area to start of buffer.+ if (gnext > 0)+ {+ pnext -= gnext;+ std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext);+ }++ // Ensure buffer is large enough to hold at least the specified size.+ if (n > pend - pnext)+ {+ if (n <= max_size_ && pnext <= max_size_ - n)+ {+ pend = pnext + n;+ buffer_.resize((std::max<std::size_t>)(pend, 1));+ }+ else+ {+ std::length_error ex("asio::streambuf too long");+ asio::detail::throw_exception(ex);+ }+ }++ // Update stream positions.+ setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext);+ setp(&buffer_[0] + pnext, &buffer_[0] + pend);+ }++private:+ std::size_t max_size_;+ std::vector<char_type, Allocator> buffer_;++ // Helper function to get the preferred size for reading data.+ friend std::size_t read_size_helper(+ basic_streambuf& sb, std::size_t max_size)+ {+ return std::min<std::size_t>(+ std::max<std::size_t>(512, sb.buffer_.capacity() - sb.size()),+ std::min<std::size_t>(max_size, sb.max_size() - sb.size()));+ }+};++/// Adapts basic_streambuf to the dynamic buffer sequence type requirements.+#if defined(GENERATING_DOCUMENTATION)+template <typename Allocator = std::allocator<char> >+#else+template <typename Allocator>+#endif+class basic_streambuf_ref+{+public:+ /// The type used to represent the input sequence as a list of buffers.+ typedef typename basic_streambuf<Allocator>::const_buffers_type+ const_buffers_type;++ /// The type used to represent the output sequence as a list of buffers.+ typedef typename basic_streambuf<Allocator>::mutable_buffers_type+ mutable_buffers_type;++ /// Construct a basic_streambuf_ref for the given basic_streambuf object.+ explicit basic_streambuf_ref(basic_streambuf<Allocator>& sb)+ : sb_(sb)+ {+ }++ /// Copy construct a basic_streambuf_ref.+ basic_streambuf_ref(const basic_streambuf_ref& other) ASIO_NOEXCEPT+ : sb_(other.sb_)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move construct a basic_streambuf_ref.+ basic_streambuf_ref(basic_streambuf_ref&& other) ASIO_NOEXCEPT+ : sb_(other.sb_)+ {+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Get the size of the input sequence.+ std::size_t size() const ASIO_NOEXCEPT+ {+ return sb_.size();+ }++ /// Get the maximum size of the dynamic buffer.+ std::size_t max_size() const ASIO_NOEXCEPT+ {+ return sb_.max_size();+ }++ /// Get the current capacity of the dynamic buffer.+ std::size_t capacity() const ASIO_NOEXCEPT+ {+ return sb_.capacity();+ }++ /// Get a list of buffers that represents the input sequence.+ const_buffers_type data() const ASIO_NOEXCEPT+ {+ return sb_.data();+ }++ /// Get a list of buffers that represents the output sequence, with the given+ /// size.+ mutable_buffers_type prepare(std::size_t n)+ {+ return sb_.prepare(n);+ }++ /// Move bytes from the output sequence to the input sequence.+ void commit(std::size_t n)+ {+ return sb_.commit(n);+ }++ /// Remove characters from the input sequence.+ void consume(std::size_t n)+ {+ return sb_.consume(n);+ }++private:+ basic_streambuf<Allocator>& sb_;+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_IOSTREAM)++#endif // ASIO_BASIC_STREAMBUF_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_streambuf_fwd.hpp view
@@ -0,0 +1,36 @@+//+// basic_streambuf_fwd.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STREAMBUF_FWD_HPP+#define ASIO_BASIC_STREAMBUF_FWD_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_NO_IOSTREAM)++#include <memory>++namespace asio {++template <typename Allocator = std::allocator<char> >+class basic_streambuf;++template <typename Allocator = std::allocator<char> >+class basic_streambuf_ref;++} // namespace asio++#endif // !defined(ASIO_NO_IOSTREAM)++#endif // ASIO_BASIC_STREAMBUF_FWD_HPP
+ link/modules/asio-standalone/asio/include/asio/basic_waitable_timer.hpp view
@@ -0,0 +1,811 @@+//+// basic_waitable_timer.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WAITABLE_TIMER_HPP+#define ASIO_BASIC_WAITABLE_TIMER_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#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/io_object_impl.hpp"+#include "asio/detail/non_const_lvalue.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"+#include "asio/wait_traits.hpp"++#if defined(ASIO_HAS_MOVE)+# include <utility>+#endif // defined(ASIO_HAS_MOVE)++#include "asio/detail/push_options.hpp"++namespace asio {++#if !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)+#define ASIO_BASIC_WAITABLE_TIMER_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename Clock,+ typename WaitTraits = asio::wait_traits<Clock>,+ typename Executor = any_io_executor>+class basic_waitable_timer;++#endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)++/// Provides waitable timer functionality.+/**+ * The basic_waitable_timer class template provides the ability to perform a+ * blocking or asynchronous wait for a timer to expire.+ *+ * A waitable timer is always in one of two states: "expired" or "not expired".+ * If the wait() or async_wait() function is called on an expired timer, the+ * wait operation will complete immediately.+ *+ * Most applications will use one of the asio::steady_timer,+ * asio::system_timer or asio::high_resolution_timer typedefs.+ *+ * @note This waitable timer functionality is for use with the C++11 standard+ * library's @c <chrono> facility, or with the Boost.Chrono library.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Examples+ * Performing a blocking wait (C++11):+ * @code+ * // Construct a timer without setting an expiry time.+ * asio::steady_timer timer(my_context);+ *+ * // Set an expiry time relative to now.+ * timer.expires_after(std::chrono::seconds(5));+ *+ * // Wait for the timer to expire.+ * timer.wait();+ * @endcode+ *+ * @par + * Performing an asynchronous wait (C++11):+ * @code+ * void handler(const asio::error_code& error)+ * {+ * if (!error)+ * {+ * // Timer expired.+ * }+ * }+ *+ * ...+ *+ * // Construct a timer with an absolute expiry time.+ * asio::steady_timer timer(my_context,+ * std::chrono::steady_clock::now() + std::chrono::seconds(60));+ *+ * // Start an asynchronous wait.+ * timer.async_wait(handler);+ * @endcode+ *+ * @par Changing an active waitable timer's expiry time+ *+ * Changing the expiry time of a timer while there are pending asynchronous+ * waits causes those wait operations to be cancelled. To ensure that the action+ * associated with the timer is performed only once, use something like this:+ * used:+ *+ * @code+ * void on_some_event()+ * {+ * if (my_timer.expires_after(seconds(5)) > 0)+ * {+ * // We managed to cancel the timer. Start new asynchronous wait.+ * my_timer.async_wait(on_timeout);+ * }+ * else+ * {+ * // Too late, timer has already expired!+ * }+ * }+ *+ * void on_timeout(const asio::error_code& e)+ * {+ * if (e != asio::error::operation_aborted)+ * {+ * // Timer was not cancelled, take necessary action.+ * }+ * }+ * @endcode+ *+ * @li The asio::basic_waitable_timer::expires_after() function+ * cancels any pending asynchronous waits, and returns the number of+ * asynchronous waits that were cancelled. If it returns 0 then you were too+ * late and the wait handler has already been executed, or will soon be+ * executed. If it returns 1 then the wait handler was successfully cancelled.+ *+ * @li If a wait handler is cancelled, the asio::error_code passed to+ * it contains the value asio::error::operation_aborted.+ */+template <typename Clock, typename WaitTraits, typename Executor>+class basic_waitable_timer+{+public:+ /// The type of the executor associated with the object.+ 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.+ typedef Clock clock_type;++ /// The duration type of the clock.+ typedef typename clock_type::duration duration;++ /// The time point type of the clock.+ typedef typename clock_type::time_point time_point;++ /// The wait traits type.+ typedef WaitTraits traits_type;++ /// 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 ex The I/O executor that the timer will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the timer.+ */+ explicit basic_waitable_timer(const executor_type& ex)+ : impl_(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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ }++ /// Constructor to set a particular expiry time as an absolute time.+ /**+ * This constructor creates a timer and sets the expiry time.+ *+ * @param ex The I/O executor object 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.+ */+ basic_waitable_timer(const executor_type& ex, const time_point& expiry_time)+ : impl_(ex)+ {+ asio::error_code 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code 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 relative to now.+ /**+ * This constructor creates a timer and sets the expiry time.+ *+ * @param ex 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.+ */+ basic_waitable_timer(const executor_type& ex, const duration& expiry_time)+ : impl_(ex)+ {+ asio::error_code ec;+ impl_.get_service().expires_after(+ 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,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ impl_.get_service().expires_after(+ impl_.get_implementation(), expiry_time, ec);+ asio::detail::throw_error(ec, "expires_after");+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// 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.+ */+ basic_waitable_timer(basic_waitable_timer&& other)+ : 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.+ */+ basic_waitable_timer& operator=(basic_waitable_timer&& 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,+ typename enable_if<+ is_convertible<Executor1, Executor>::value+ >::type* = 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>+ typename enable_if<+ is_convertible<Executor1, Executor>::value,+ basic_waitable_timer&+ >::type operator=(basic_waitable_timer<Clock, WaitTraits, Executor1>&& other)+ {+ basic_waitable_timer tmp(std::move(other));+ impl_ = std::move(tmp.impl_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destroys the timer.+ /**+ * This function destroys the timer, cancelling any outstanding asynchronous+ * wait operations associated with the timer as if by calling @c cancel.+ */+ ~basic_waitable_timer()+ {+ }++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_NOEXCEPT+ {+ return impl_.get_executor();+ }++ /// Cancel any asynchronous operations that are waiting on the timer.+ /**+ * This function forces the completion of any pending asynchronous wait+ * operations against the timer. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * Cancelling the timer does not change the expiry time.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note If the timer has already expired when cancel() is called, then the+ * handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t cancel()+ {+ asio::error_code ec;+ std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "cancel");+ return s;+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use non-error_code overload.) Cancel any asynchronous+ /// operations that are waiting on the timer.+ /**+ * This function forces the completion of any pending asynchronous wait+ * operations against the timer. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * Cancelling the timer does not change the expiry time.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @note If the timer has already expired when cancel() is called, then the+ * handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t cancel(asio::error_code& ec)+ {+ return impl_.get_service().cancel(impl_.get_implementation(), ec);+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Cancels one asynchronous operation that is waiting on the timer.+ /**+ * This function forces the completion of one pending asynchronous wait+ * operation against the timer. Handlers are cancelled in FIFO order. The+ * handler for the cancelled operation will be invoked with the+ * asio::error::operation_aborted error code.+ *+ * Cancelling the timer does not change the expiry time.+ *+ * @return The number of asynchronous operations that were cancelled. That is,+ * either 0 or 1.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note If the timer has already expired when cancel_one() is called, then+ * the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t cancel_one()+ {+ asio::error_code ec;+ std::size_t s = impl_.get_service().cancel_one(+ impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "cancel_one");+ return s;+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use non-error_code overload.) Cancels one asynchronous+ /// operation that is waiting on the timer.+ /**+ * This function forces the completion of one pending asynchronous wait+ * operation against the timer. Handlers are cancelled in FIFO order. The+ * handler for the cancelled operation will be invoked with the+ * asio::error::operation_aborted error code.+ *+ * Cancelling the timer does not change the expiry time.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of asynchronous operations that were cancelled. That is,+ * either 0 or 1.+ *+ * @note If the timer has already expired when cancel_one() is called, then+ * the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t cancel_one(asio::error_code& ec)+ {+ return impl_.get_service().cancel_one(impl_.get_implementation(), ec);+ }++ /// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute+ /// time.+ /**+ * This function may be used to obtain the timer's current expiry time.+ * Whether the timer has expired or not does not affect this value.+ */+ time_point expires_at() const+ {+ return impl_.get_service().expires_at(impl_.get_implementation());+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Get the timer's expiry time as an absolute time.+ /**+ * This function may be used to obtain the timer's current expiry time.+ * Whether the timer has expired or not does not affect this value.+ */+ time_point expiry() const+ {+ return impl_.get_service().expiry(impl_.get_implementation());+ }++ /// Set the timer's expiry time as an absolute time.+ /**+ * This function sets the expiry time. Any pending asynchronous wait+ * operations will be cancelled. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * @param expiry_time The expiry time to be used for the timer.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note If the timer has already expired when expires_at() is called, then+ * the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t expires_at(const time_point& expiry_time)+ {+ asio::error_code ec;+ std::size_t s = impl_.get_service().expires_at(+ impl_.get_implementation(), expiry_time, ec);+ asio::detail::throw_error(ec, "expires_at");+ return s;+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use non-error_code overload.) Set the timer's expiry time as+ /// an absolute time.+ /**+ * This function sets the expiry time. Any pending asynchronous wait+ * operations will be cancelled. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * @param expiry_time The expiry time to be used for the timer.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @note If the timer has already expired when expires_at() is called, then+ * the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t expires_at(const time_point& expiry_time,+ asio::error_code& ec)+ {+ return impl_.get_service().expires_at(+ impl_.get_implementation(), expiry_time, ec);+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Set the timer's expiry time relative to now.+ /**+ * This function sets the expiry time. Any pending asynchronous wait+ * operations will be cancelled. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * @param expiry_time The expiry time to be used for the timer.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note If the timer has already expired when expires_after() is called,+ * then the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t expires_after(const duration& expiry_time)+ {+ asio::error_code ec;+ std::size_t s = impl_.get_service().expires_after(+ impl_.get_implementation(), expiry_time, ec);+ asio::detail::throw_error(ec, "expires_after");+ return s;+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use expiry().) Get the timer's expiry time relative to now.+ /**+ * This function may be used to obtain the timer's current expiry time.+ * Whether the timer has expired or not does not affect this value.+ */+ duration expires_from_now() const+ {+ return impl_.get_service().expires_from_now(impl_.get_implementation());+ }++ /// (Deprecated: Use expires_after().) Set the timer's expiry time relative+ /// to now.+ /**+ * This function sets the expiry time. Any pending asynchronous wait+ * operations will be cancelled. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * @param expiry_time The expiry time to be used for the timer.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note If the timer has already expired when expires_from_now() is called,+ * then the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t expires_from_now(const duration& expiry_time)+ {+ asio::error_code ec;+ std::size_t s = impl_.get_service().expires_from_now(+ impl_.get_implementation(), expiry_time, ec);+ asio::detail::throw_error(ec, "expires_from_now");+ return s;+ }++ /// (Deprecated: Use expires_after().) Set the timer's expiry time relative+ /// to now.+ /**+ * This function sets the expiry time. Any pending asynchronous wait+ * operations will be cancelled. The handler for each cancelled operation will+ * be invoked with the asio::error::operation_aborted error code.+ *+ * @param expiry_time The expiry time to be used for the timer.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of asynchronous operations that were cancelled.+ *+ * @note If the timer has already expired when expires_from_now() is called,+ * then the handlers for asynchronous wait operations will:+ *+ * @li have already been invoked; or+ *+ * @li have been queued for invocation in the near future.+ *+ * These handlers can no longer be cancelled, and therefore are passed an+ * error code that indicates the successful completion of the wait operation.+ */+ std::size_t expires_from_now(const duration& expiry_time,+ asio::error_code& ec)+ {+ return impl_.get_service().expires_from_now(+ impl_.get_implementation(), expiry_time, ec);+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Perform a blocking wait on the timer.+ /**+ * This function is used to wait for the timer to expire. This function+ * blocks and does not return until the timer has expired.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void wait()+ {+ asio::error_code ec;+ impl_.get_service().wait(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "wait");+ }++ /// Perform a blocking wait on the timer.+ /**+ * This function is used to wait for the timer to expire. This function+ * blocks and does not return until the timer has expired.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ void wait(asio::error_code& ec)+ {+ impl_.get_service().wait(impl_.get_implementation(), ec);+ }++ /// Start an asynchronous wait on the timer.+ /**+ * This function may be used to initiate an asynchronous wait against the+ * timer. It always returns immediately.+ *+ * For each call to async_wait(), the supplied handler will be called exactly+ * once. The handler will be called when:+ *+ * @li The timer has expired.+ *+ * @li The timer was cancelled, in which case the handler is passed the error+ * code asio::error::operation_aborted.+ *+ * @param handler The handler to be called when the timer expires. Copies+ * will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error // Result of operation.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))+ WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,+ void (asio::error_code))+ async_wait(+ ASIO_MOVE_ARG(WaitHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WaitHandler, void (asio::error_code)>(+ initiate_async_wait(this), handler);+ }++private:+ // Disallow copying and assignment.+ basic_waitable_timer(const basic_waitable_timer&) ASIO_DELETED;+ basic_waitable_timer& operator=(+ 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)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WaitHandler>+ void operator()(ASIO_MOVE_ARG(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++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BASIC_WAITABLE_TIMER_HPP
+ link/modules/asio-standalone/asio/include/asio/bind_executor.hpp view
@@ -0,0 +1,575 @@+//+// bind_executor.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTOR_HPP+#define ASIO_BIND_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/detail/variadic_templates.hpp"+#include "asio/associated_executor.hpp"+#include "asio/associated_allocator.hpp"+#include "asio/async_result.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution_context.hpp"+#include "asio/is_executor.hpp"+#include "asio/uses_executor.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 executor_binder_result_type+{+protected:+ typedef void result_type_or_void;+};++template <typename T>+struct executor_binder_result_type<T,+ typename void_type<typename T::result_type>::type>+{+ typedef typename T::result_type result_type;+protected:+ typedef result_type result_type_or_void;+};++template <typename R>+struct executor_binder_result_type<R(*)()>+{+ typedef R result_type;+protected:+ typedef result_type result_type_or_void;+};++template <typename R>+struct executor_binder_result_type<R(&)()>+{+ typedef R result_type;+protected:+ typedef result_type result_type_or_void;+};++template <typename R, typename A1>+struct executor_binder_result_type<R(*)(A1)>+{+ typedef R result_type;+protected:+ typedef result_type result_type_or_void;+};++template <typename R, typename A1>+struct 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 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 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 executor_binder_argument_type {};++template <typename T>+struct executor_binder_argument_type<T,+ typename void_type<typename T::argument_type>::type>+{+ typedef typename T::argument_type argument_type;+};++template <typename R, typename A1>+struct executor_binder_argument_type<R(*)(A1)>+{+ typedef A1 argument_type;+};++template <typename R, typename A1>+struct 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 executor_binder_argument_types {};++template <typename T>+struct executor_binder_argument_types<T,+ typename void_type<typename T::first_argument_type>::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 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 executor_binder_argument_type<R(&)(A1, A2)>+{+ typedef A1 first_argument_type;+ typedef A2 second_argument_type;+};++// Helper to perform uses_executor construction of the target type, if+// required.++template <typename T, typename Executor, bool UsesExecutor>+class executor_binder_base;++template <typename T, typename Executor>+class executor_binder_base<T, Executor, true>+{+protected:+ template <typename E, typename U>+ executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u)+ : executor_(ASIO_MOVE_CAST(E)(e)),+ target_(executor_arg_t(), executor_, ASIO_MOVE_CAST(U)(u))+ {+ }++ Executor executor_;+ T target_;+};++template <typename T, typename Executor>+class executor_binder_base<T, Executor, false>+{+protected:+ template <typename E, typename U>+ executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u)+ : executor_(ASIO_MOVE_CAST(E)(e)),+ target_(ASIO_MOVE_CAST(U)(u))+ {+ }++ Executor executor_;+ 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 void_type<typename result_of<T()>::type>::type>+{+ typedef typename result_of<T()>::type type;+};++} // namespace detail++/// A call wrapper type to bind an executor of type @c Executor to an object of+/// type @c T.+template <typename T, typename Executor>+class executor_binder+#if !defined(GENERATING_DOCUMENTATION)+ : public detail::executor_binder_result_type<T>,+ public detail::executor_binder_argument_type<T>,+ public detail::executor_binder_argument_types<T>,+ private detail::executor_binder_base<+ T, Executor, uses_executor<T, Executor>::value>+#endif // !defined(GENERATING_DOCUMENTATION)+{+public:+ /// The type of the target object.+ typedef T target_type;++ /// The type of the associated executor.+ typedef Executor 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 an 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>+ executor_binder(executor_arg_t, const executor_type& e,+ ASIO_MOVE_ARG(U) u)+ : base_type(e, ASIO_MOVE_CAST(U)(u))+ {+ }++ /// Copy constructor.+ executor_binder(const executor_binder& other)+ : base_type(other.get_executor(), other.get())+ {+ }++ /// Construct a copy, but specify a different executor.+ executor_binder(executor_arg_t, const executor_type& e,+ const executor_binder& other)+ : base_type(e, other.get())+ {+ }++ /// Construct a copy of a different 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>+ executor_binder(const executor_binder<U, OtherExecutor>& other)+ : base_type(other.get_executor(), other.get())+ {+ }++ /// Construct a copy of a different executor wrapper type, but specify a+ /// different executor.+ /**+ * This constructor is only valid if the type @c T is constructible from type+ * @c U.+ */+ template <typename U, typename OtherExecutor>+ executor_binder(executor_arg_t, const executor_type& e,+ const executor_binder<U, OtherExecutor>& other)+ : base_type(e, other.get())+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Move constructor.+ executor_binder(executor_binder&& other)+ : base_type(ASIO_MOVE_CAST(executor_type)(other.get_executor()),+ ASIO_MOVE_CAST(T)(other.get()))+ {+ }++ /// Move construct the target object, but specify a different executor.+ executor_binder(executor_arg_t, const executor_type& e,+ executor_binder&& other)+ : base_type(e, ASIO_MOVE_CAST(T)(other.get()))+ {+ }++ /// Move construct from a different executor wrapper type.+ template <typename U, typename OtherExecutor>+ executor_binder(executor_binder<U, OtherExecutor>&& other)+ : base_type(ASIO_MOVE_CAST(OtherExecutor)(other.get_executor()),+ ASIO_MOVE_CAST(U)(other.get()))+ {+ }++ /// Move construct from a different executor wrapper type, but specify a+ /// different executor.+ template <typename U, typename OtherExecutor>+ executor_binder(executor_arg_t, const executor_type& e,+ executor_binder<U, OtherExecutor>&& other)+ : base_type(e, ASIO_MOVE_CAST(U)(other.get()))+ {+ }++#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destructor.+ ~executor_binder()+ {+ }++ /// Obtain a reference to the target object.+ target_type& get() ASIO_NOEXCEPT+ {+ return this->target_;+ }++ /// Obtain a reference to the target object.+ const target_type& get() const ASIO_NOEXCEPT+ {+ return this->target_;+ }++ /// Obtain the associated executor.+ executor_type get_executor() const ASIO_NOEXCEPT+ {+ 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.+ template <typename... Args>+ typename result_of<T(Args...)>::type operator()(+ ASIO_MOVE_ARG(Args)... args)+ {+ return this->target_(ASIO_MOVE_CAST(Args)(args)...);+ }++ /// Forwarding function call operator.+ template <typename... Args>+ typename result_of<T(Args...)>::type operator()(+ ASIO_MOVE_ARG(Args)... args) const+ {+ return this->target_(ASIO_MOVE_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:+ typedef detail::executor_binder_base<T, Executor,+ uses_executor<T, Executor>::value> base_type;+};++/// Associate an object of type @c T with an executor of type @c Executor.+template <typename Executor, typename T>+inline executor_binder<typename decay<T>::type, Executor>+bind_executor(const Executor& ex, ASIO_MOVE_ARG(T) t,+ typename enable_if<+ is_executor<Executor>::value || execution::is_executor<Executor>::value+ >::type* = 0)+{+ return executor_binder<typename decay<T>::type, Executor>(+ executor_arg_t(), ex, ASIO_MOVE_CAST(T)(t));+}++/// Associate an object of type @c T with an execution context's executor.+template <typename ExecutionContext, typename T>+inline executor_binder<typename decay<T>::type,+ typename ExecutionContext::executor_type>+bind_executor(ExecutionContext& ctx, ASIO_MOVE_ARG(T) t,+ typename enable_if<is_convertible<+ ExecutionContext&, execution_context&>::value>::type* = 0)+{+ return executor_binder<typename decay<T>::type,+ typename ExecutionContext::executor_type>(+ executor_arg_t(), ctx.get_executor(), ASIO_MOVE_CAST(T)(t));+}++#if !defined(GENERATING_DOCUMENTATION)++template <typename T, typename Executor>+struct uses_executor<executor_binder<T, Executor>, Executor>+ : true_type {};++template <typename T, typename Executor, typename Signature>+class async_result<executor_binder<T, Executor>, Signature>+{+public:+ typedef executor_binder<+ typename async_result<T, Signature>::completion_handler_type, Executor>+ completion_handler_type;++ typedef typename async_result<T, Signature>::return_type return_type;++ explicit async_result(executor_binder<T, Executor>& b)+ : target_(b.get())+ {+ }++ return_type 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_;+};++template <typename T, typename Executor, typename Allocator>+struct associated_allocator<executor_binder<T, Executor>, Allocator>+{+ typedef typename associated_allocator<T, Allocator>::type type;++ static type get(const executor_binder<T, Executor>& b,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<T, Allocator>::get(b.get(), a);+ }+};++template <typename T, typename Executor, typename Executor1>+struct associated_executor<executor_binder<T, Executor>, Executor1>+{+ typedef Executor type;++ static type get(const executor_binder<T, Executor>& b,+ const Executor1& = Executor1()) ASIO_NOEXCEPT+ {+ return b.get_executor();+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BIND_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/buffer.hpp view
@@ -0,0 +1,2496 @@+//+// buffer.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HPP+#define ASIO_BUFFER_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include <cstring>+#include <limits>+#include <stdexcept>+#include <string>+#include <vector>+#include "asio/detail/array_fwd.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/string_view.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/detail/type_traits.hpp"++#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1700)+# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0)+# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)+# define ASIO_ENABLE_BUFFER_DEBUGGING+# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)+# endif // defined(_HAS_ITERATOR_DEBUGGING)+#endif // defined(ASIO_MSVC) && (ASIO_MSVC >= 1700)++#if defined(__GNUC__)+# if defined(_GLIBCXX_DEBUG)+# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)+# define ASIO_ENABLE_BUFFER_DEBUGGING+# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)+# endif // defined(_GLIBCXX_DEBUG)+#endif // defined(__GNUC__)++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+# include "asio/detail/functional.hpp"+#endif // ASIO_ENABLE_BUFFER_DEBUGGING++#if defined(ASIO_HAS_BOOST_WORKAROUND)+# include <boost/detail/workaround.hpp>+# if !defined(__clang__)+# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))+# define ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND+# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))+# elif BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))+# define ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND+# endif // BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))+#endif // defined(ASIO_HAS_BOOST_WORKAROUND)++#if defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND)+# include "asio/detail/type_traits.hpp"+#endif // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND)++#include "asio/detail/push_options.hpp"++namespace asio {++class mutable_buffer;+class const_buffer;++/// Holds a buffer that can be modified.+/**+ * The mutable_buffer class provides a safe representation of a buffer that can+ * be modified. It does not own the underlying data, and so is cheap to copy or+ * assign.+ *+ * @par Accessing Buffer Contents+ *+ * The contents of a buffer may be accessed using the @c data() and @c size()+ * member functions:+ *+ * @code asio::mutable_buffer b1 = ...;+ * std::size_t s1 = b1.size();+ * unsigned char* p1 = static_cast<unsigned char*>(b1.data());+ * @endcode+ *+ * The @c data() member function permits violations of type safety, so uses of+ * it in application code should be carefully considered.+ */+class mutable_buffer+{+public:+ /// Construct an empty buffer.+ mutable_buffer() ASIO_NOEXCEPT+ : data_(0),+ size_(0)+ {+ }++ /// Construct a buffer to represent a given memory range.+ mutable_buffer(void* data, std::size_t size) ASIO_NOEXCEPT+ : data_(data),+ size_(size)+ {+ }++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ mutable_buffer(void* data, std::size_t size,+ asio::detail::function<void()> debug_check)+ : data_(data),+ size_(size),+ debug_check_(debug_check)+ {+ }++ const asio::detail::function<void()>& get_debug_check() const+ {+ return debug_check_;+ }+#endif // ASIO_ENABLE_BUFFER_DEBUGGING++ /// Get a pointer to the beginning of the memory range.+ void* data() const ASIO_NOEXCEPT+ {+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ if (size_ && debug_check_)+ debug_check_();+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ return data_;+ }++ /// Get the size of the memory range.+ std::size_t size() const ASIO_NOEXCEPT+ {+ return size_;+ }++ /// Move the start of the buffer by the specified number of bytes.+ mutable_buffer& operator+=(std::size_t n) ASIO_NOEXCEPT+ {+ std::size_t offset = n < size_ ? n : size_;+ data_ = static_cast<char*>(data_) + offset;+ size_ -= offset;+ return *this;+ }++private:+ void* data_;+ std::size_t size_;++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ asio::detail::function<void()> debug_check_;+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+};++#if !defined(ASIO_NO_DEPRECATED)++/// (Deprecated: Use mutable_buffer.) Adapts a single modifiable buffer so that+/// it meets the requirements of the MutableBufferSequence concept.+class mutable_buffers_1+ : public mutable_buffer+{+public:+ /// The type for each element in the list of buffers.+ typedef mutable_buffer value_type;++ /// A random-access iterator type that may be used to read elements.+ typedef const mutable_buffer* const_iterator;++ /// Construct to represent a given memory range.+ mutable_buffers_1(void* data, std::size_t size) ASIO_NOEXCEPT+ : mutable_buffer(data, size)+ {+ }++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ mutable_buffers_1(void* data, std::size_t size,+ asio::detail::function<void()> debug_check)+ : mutable_buffer(data, size, debug_check)+ {+ }+#endif // ASIO_ENABLE_BUFFER_DEBUGGING++ /// Construct to represent a single modifiable buffer.+ explicit mutable_buffers_1(const mutable_buffer& b) ASIO_NOEXCEPT+ : mutable_buffer(b)+ {+ }++ /// Get a random-access iterator to the first element.+ const_iterator begin() const ASIO_NOEXCEPT+ {+ return this;+ }++ /// Get a random-access iterator for one past the last element.+ const_iterator end() const ASIO_NOEXCEPT+ {+ return begin() + 1;+ }+};++#endif // !defined(ASIO_NO_DEPRECATED)++/// Holds a buffer that cannot be modified.+/**+ * The const_buffer class provides a safe representation of a buffer that cannot+ * be modified. It does not own the underlying data, and so is cheap to copy or+ * assign.+ *+ * @par Accessing Buffer Contents+ *+ * The contents of a buffer may be accessed using the @c data() and @c size()+ * member functions:+ *+ * @code asio::const_buffer b1 = ...;+ * std::size_t s1 = b1.size();+ * const unsigned char* p1 = static_cast<const unsigned char*>(b1.data());+ * @endcode+ *+ * The @c data() member function permits violations of type safety, so uses of+ * it in application code should be carefully considered.+ */+class const_buffer+{+public:+ /// Construct an empty buffer.+ const_buffer() ASIO_NOEXCEPT+ : data_(0),+ size_(0)+ {+ }++ /// Construct a buffer to represent a given memory range.+ const_buffer(const void* data, std::size_t size) ASIO_NOEXCEPT+ : data_(data),+ size_(size)+ {+ }++ /// Construct a non-modifiable buffer from a modifiable one.+ const_buffer(const mutable_buffer& b) ASIO_NOEXCEPT+ : data_(b.data()),+ size_(b.size())+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , debug_check_(b.get_debug_check())+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ {+ }++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ const_buffer(const void* data, std::size_t size,+ asio::detail::function<void()> debug_check)+ : data_(data),+ size_(size),+ debug_check_(debug_check)+ {+ }++ const asio::detail::function<void()>& get_debug_check() const+ {+ return debug_check_;+ }+#endif // ASIO_ENABLE_BUFFER_DEBUGGING++ /// Get a pointer to the beginning of the memory range.+ const void* data() const ASIO_NOEXCEPT+ {+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ if (size_ && debug_check_)+ debug_check_();+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ return data_;+ }++ /// Get the size of the memory range.+ std::size_t size() const ASIO_NOEXCEPT+ {+ return size_;+ }++ /// Move the start of the buffer by the specified number of bytes.+ const_buffer& operator+=(std::size_t n) ASIO_NOEXCEPT+ {+ std::size_t offset = n < size_ ? n : size_;+ data_ = static_cast<const char*>(data_) + offset;+ size_ -= offset;+ return *this;+ }++private:+ const void* data_;+ std::size_t size_;++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ asio::detail::function<void()> debug_check_;+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+};++#if !defined(ASIO_NO_DEPRECATED)++/// (Deprecated: Use const_buffer.) Adapts a single non-modifiable buffer so+/// that it meets the requirements of the ConstBufferSequence concept.+class const_buffers_1+ : public const_buffer+{+public:+ /// The type for each element in the list of buffers.+ typedef const_buffer value_type;++ /// A random-access iterator type that may be used to read elements.+ typedef const const_buffer* const_iterator;++ /// Construct to represent a given memory range.+ const_buffers_1(const void* data, std::size_t size) ASIO_NOEXCEPT+ : const_buffer(data, size)+ {+ }++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ const_buffers_1(const void* data, std::size_t size,+ asio::detail::function<void()> debug_check)+ : const_buffer(data, size, debug_check)+ {+ }+#endif // ASIO_ENABLE_BUFFER_DEBUGGING++ /// Construct to represent a single non-modifiable buffer.+ explicit const_buffers_1(const const_buffer& b) ASIO_NOEXCEPT+ : const_buffer(b)+ {+ }++ /// Get a random-access iterator to the first element.+ const_iterator begin() const ASIO_NOEXCEPT+ {+ return this;+ }++ /// Get a random-access iterator for one past the last element.+ const_iterator end() const ASIO_NOEXCEPT+ {+ return begin() + 1;+ }+};++#endif // !defined(ASIO_NO_DEPRECATED)++/// (Deprecated: Use the socket/descriptor wait() and async_wait() member+/// functions.) An implementation of both the ConstBufferSequence and+/// MutableBufferSequence concepts to represent a null buffer sequence.+class null_buffers+{+public:+ /// The type for each element in the list of buffers.+ typedef mutable_buffer value_type;++ /// A random-access iterator type that may be used to read elements.+ typedef const mutable_buffer* const_iterator;++ /// Get a random-access iterator to the first element.+ const_iterator begin() const ASIO_NOEXCEPT+ {+ return &buf_;+ }++ /// Get a random-access iterator for one past the last element.+ const_iterator end() const ASIO_NOEXCEPT+ {+ return &buf_;+ }++private:+ mutable_buffer buf_;+};++/** @defgroup buffer_sequence_begin asio::buffer_sequence_begin+ *+ * @brief The asio::buffer_sequence_begin function returns an iterator+ * pointing to the first element in a buffer sequence.+ */+/*@{*/++/// Get an iterator to the first element in a buffer sequence.+template <typename MutableBuffer>+inline const mutable_buffer* buffer_sequence_begin(const MutableBuffer& b,+ typename enable_if<+ is_convertible<const MutableBuffer*, const mutable_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT+{+ return static_cast<const mutable_buffer*>(detail::addressof(b));+}++/// Get an iterator to the first element in a buffer sequence.+template <typename ConstBuffer>+inline const const_buffer* buffer_sequence_begin(const ConstBuffer& b,+ typename enable_if<+ is_convertible<const ConstBuffer*, const const_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT+{+ return static_cast<const const_buffer*>(detail::addressof(b));+}++#if defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)++/// Get an iterator to the first element in a buffer sequence.+template <typename C>+inline auto buffer_sequence_begin(C& c,+ typename enable_if<+ !is_convertible<const C*, const mutable_buffer*>::value+ && !is_convertible<const C*, const const_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT -> decltype(c.begin())+{+ return c.begin();+}++/// Get an iterator to the first element in a buffer sequence.+template <typename C>+inline auto buffer_sequence_begin(const C& c,+ typename enable_if<+ !is_convertible<const C*, const mutable_buffer*>::value+ && !is_convertible<const C*, const const_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT -> decltype(c.begin())+{+ return c.begin();+}++#else // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)++template <typename C>+inline typename C::iterator buffer_sequence_begin(C& c,+ typename enable_if<+ !is_convertible<const C*, const mutable_buffer*>::value+ && !is_convertible<const C*, const const_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT+{+ return c.begin();+}++template <typename C>+inline typename C::const_iterator buffer_sequence_begin(const C& c,+ typename enable_if<+ !is_convertible<const C*, const mutable_buffer*>::value+ && !is_convertible<const C*, const const_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT+{+ return c.begin();+}++#endif // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)++/*@}*/++/** @defgroup buffer_sequence_end asio::buffer_sequence_end+ *+ * @brief The asio::buffer_sequence_end function returns an iterator+ * pointing to one past the end element in a buffer sequence.+ */+/*@{*/++/// Get an iterator to one past the end element in a buffer sequence.+template <typename MutableBuffer>+inline const mutable_buffer* buffer_sequence_end(const MutableBuffer& b,+ typename enable_if<+ is_convertible<const MutableBuffer*, const mutable_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT+{+ return static_cast<const mutable_buffer*>(detail::addressof(b)) + 1;+}++/// Get an iterator to one past the end element in a buffer sequence.+template <typename ConstBuffer>+inline const const_buffer* buffer_sequence_end(const ConstBuffer& b,+ typename enable_if<+ is_convertible<const ConstBuffer*, const const_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT+{+ return static_cast<const const_buffer*>(detail::addressof(b)) + 1;+}++#if defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)++/// Get an iterator to one past the end element in a buffer sequence.+template <typename C>+inline auto buffer_sequence_end(C& c,+ typename enable_if<+ !is_convertible<const C*, const mutable_buffer*>::value+ && !is_convertible<const C*, const const_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT -> decltype(c.end())+{+ return c.end();+}++/// Get an iterator to one past the end element in a buffer sequence.+template <typename C>+inline auto buffer_sequence_end(const C& c,+ typename enable_if<+ !is_convertible<const C*, const mutable_buffer*>::value+ && !is_convertible<const C*, const const_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT -> decltype(c.end())+{+ return c.end();+}++#else // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)++template <typename C>+inline typename C::iterator buffer_sequence_end(C& c,+ typename enable_if<+ !is_convertible<const C*, const mutable_buffer*>::value+ && !is_convertible<const C*, const const_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT+{+ return c.end();+}++template <typename C>+inline typename C::const_iterator buffer_sequence_end(const C& c,+ typename enable_if<+ !is_convertible<const C*, const mutable_buffer*>::value+ && !is_convertible<const C*, const const_buffer*>::value+ >::type* = 0) ASIO_NOEXCEPT+{+ return c.end();+}++#endif // defined(ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION)++/*@}*/++namespace detail {++// Tag types used to select appropriately optimised overloads.+struct one_buffer {};+struct multiple_buffers {};++// Helper trait to detect single buffers.+template <typename BufferSequence>+struct buffer_sequence_cardinality :+ conditional<+ is_same<BufferSequence, mutable_buffer>::value+#if !defined(ASIO_NO_DEPRECATED)+ || is_same<BufferSequence, mutable_buffers_1>::value+ || is_same<BufferSequence, const_buffers_1>::value+#endif // !defined(ASIO_NO_DEPRECATED)+ || is_same<BufferSequence, const_buffer>::value,+ one_buffer, multiple_buffers>::type {};++template <typename Iterator>+inline std::size_t buffer_size(one_buffer,+ Iterator begin, Iterator) ASIO_NOEXCEPT+{+ return const_buffer(*begin).size();+}++template <typename Iterator>+inline std::size_t buffer_size(multiple_buffers,+ Iterator begin, Iterator end) ASIO_NOEXCEPT+{+ std::size_t total_buffer_size = 0;++ Iterator iter = begin;+ for (; iter != end; ++iter)+ {+ const_buffer b(*iter);+ total_buffer_size += b.size();+ }++ return total_buffer_size;+}++} // namespace detail++/// Get the total number of bytes in a buffer sequence.+/**+ * The @c buffer_size function determines the total size of all buffers in the+ * buffer sequence, as if computed as follows:+ *+ * @code size_t total_size = 0;+ * auto i = asio::buffer_sequence_begin(buffers);+ * auto end = asio::buffer_sequence_end(buffers);+ * for (; i != end; ++i)+ * {+ * const_buffer b(*i);+ * total_size += b.size();+ * }+ * return total_size; @endcode+ *+ * The @c BufferSequence template parameter may meet either of the @c+ * ConstBufferSequence or @c MutableBufferSequence type requirements.+ */+template <typename BufferSequence>+inline std::size_t buffer_size(const BufferSequence& b) ASIO_NOEXCEPT+{+ return detail::buffer_size(+ detail::buffer_sequence_cardinality<BufferSequence>(),+ asio::buffer_sequence_begin(b),+ asio::buffer_sequence_end(b));+}++#if !defined(ASIO_NO_DEPRECATED)++/** @defgroup buffer_cast asio::buffer_cast+ *+ * @brief (Deprecated: Use the @c data() member function.) The+ * asio::buffer_cast function is used to obtain a pointer to the+ * underlying memory region associated with a buffer.+ *+ * @par Examples:+ *+ * To access the memory of a non-modifiable buffer, use:+ * @code asio::const_buffer b1 = ...;+ * const unsigned char* p1 = asio::buffer_cast<const unsigned char*>(b1);+ * @endcode+ *+ * To access the memory of a modifiable buffer, use:+ * @code asio::mutable_buffer b2 = ...;+ * unsigned char* p2 = asio::buffer_cast<unsigned char*>(b2);+ * @endcode+ *+ * The asio::buffer_cast function permits violations of type safety, so+ * uses of it in application code should be carefully considered.+ */+/*@{*/++/// Cast a non-modifiable buffer to a specified pointer to POD type.+template <typename PointerToPodType>+inline PointerToPodType buffer_cast(const mutable_buffer& b) ASIO_NOEXCEPT+{+ return static_cast<PointerToPodType>(b.data());+}++/// Cast a non-modifiable buffer to a specified pointer to POD type.+template <typename PointerToPodType>+inline PointerToPodType buffer_cast(const const_buffer& b) ASIO_NOEXCEPT+{+ return static_cast<PointerToPodType>(b.data());+}++/*@}*/++#endif // !defined(ASIO_NO_DEPRECATED)++/// Create a new modifiable buffer that is offset from the start of another.+/**+ * @relates mutable_buffer+ */+inline mutable_buffer operator+(const mutable_buffer& b,+ std::size_t n) ASIO_NOEXCEPT+{+ std::size_t offset = n < b.size() ? n : b.size();+ char* new_data = static_cast<char*>(b.data()) + offset;+ std::size_t new_size = b.size() - offset;+ return mutable_buffer(new_data, new_size+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , b.get_debug_check()+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++/// Create a new modifiable buffer that is offset from the start of another.+/**+ * @relates mutable_buffer+ */+inline mutable_buffer operator+(std::size_t n,+ const mutable_buffer& b) ASIO_NOEXCEPT+{+ return b + n;+}++/// Create a new non-modifiable buffer that is offset from the start of another.+/**+ * @relates const_buffer+ */+inline const_buffer operator+(const const_buffer& b,+ std::size_t n) ASIO_NOEXCEPT+{+ std::size_t offset = n < b.size() ? n : b.size();+ const char* new_data = static_cast<const char*>(b.data()) + offset;+ std::size_t new_size = b.size() - offset;+ return const_buffer(new_data, new_size+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , b.get_debug_check()+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++/// Create a new non-modifiable buffer that is offset from the start of another.+/**+ * @relates const_buffer+ */+inline const_buffer operator+(std::size_t n,+ const const_buffer& b) ASIO_NOEXCEPT+{+ return b + n;+}++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+namespace detail {++template <typename Iterator>+class buffer_debug_check+{+public:+ buffer_debug_check(Iterator iter)+ : iter_(iter)+ {+ }++ ~buffer_debug_check()+ {+#if defined(ASIO_MSVC) && (ASIO_MSVC == 1400)+ // MSVC 8's string iterator checking may crash in a std::string::iterator+ // object's destructor when the iterator points to an already-destroyed+ // std::string object, unless the iterator is cleared first.+ iter_ = Iterator();+#endif // defined(ASIO_MSVC) && (ASIO_MSVC == 1400)+ }++ void operator()()+ {+ (void)*iter_;+ }++private:+ Iterator iter_;+};++} // namespace detail+#endif // ASIO_ENABLE_BUFFER_DEBUGGING++/** @defgroup buffer asio::buffer+ *+ * @brief The asio::buffer function is used to create a buffer object to+ * represent raw memory, an array of POD elements, a vector of POD elements,+ * or a std::string.+ *+ * A buffer object represents a contiguous region of memory as a 2-tuple+ * consisting of a pointer and size in bytes. A tuple of the form <tt>{void*,+ * size_t}</tt> specifies a mutable (modifiable) region of memory. Similarly, a+ * tuple of the form <tt>{const void*, size_t}</tt> specifies a const+ * (non-modifiable) region of memory. These two forms correspond to the classes+ * mutable_buffer and const_buffer, respectively. To mirror C++'s conversion+ * rules, a mutable_buffer is implicitly convertible to a const_buffer, and the+ * opposite conversion is not permitted.+ *+ * The simplest use case involves reading or writing a single buffer of a+ * specified size:+ *+ * @code sock.send(asio::buffer(data, size)); @endcode+ *+ * In the above example, the return value of asio::buffer meets the+ * requirements of the ConstBufferSequence concept so that it may be directly+ * passed to the socket's write function. A buffer created for modifiable+ * memory also meets the requirements of the MutableBufferSequence concept.+ *+ * An individual buffer may be created from a builtin array, std::vector,+ * std::array or boost::array of POD elements. This helps prevent buffer+ * overruns by automatically determining the size of the buffer:+ *+ * @code char d1[128];+ * size_t bytes_transferred = sock.receive(asio::buffer(d1));+ *+ * std::vector<char> d2(128);+ * bytes_transferred = sock.receive(asio::buffer(d2));+ *+ * std::array<char, 128> d3;+ * bytes_transferred = sock.receive(asio::buffer(d3));+ *+ * boost::array<char, 128> d4;+ * bytes_transferred = sock.receive(asio::buffer(d4)); @endcode+ *+ * In all three cases above, the buffers created are exactly 128 bytes long.+ * Note that a vector is @e never automatically resized when creating or using+ * a buffer. The buffer size is determined using the vector's <tt>size()</tt>+ * member function, and not its capacity.+ *+ * @par Accessing Buffer Contents+ *+ * The contents of a buffer may be accessed using the @c data() and @c size()+ * member functions:+ *+ * @code asio::mutable_buffer b1 = ...;+ * std::size_t s1 = b1.size();+ * unsigned char* p1 = static_cast<unsigned char*>(b1.data());+ *+ * asio::const_buffer b2 = ...;+ * std::size_t s2 = b2.size();+ * const void* p2 = b2.data(); @endcode+ *+ * The @c data() member function permits violations of type safety, so+ * uses of it in application code should be carefully considered.+ *+ * For convenience, a @ref buffer_size function is provided that works with+ * both buffers and buffer sequences (that is, types meeting the+ * ConstBufferSequence or MutableBufferSequence type requirements). In this+ * case, the function returns the total size of all buffers in the sequence.+ *+ * @par Buffer Copying+ *+ * The @ref buffer_copy function may be used to copy raw bytes between+ * individual buffers and buffer sequences.+*+ * In particular, when used with the @ref buffer_size function, the @ref+ * buffer_copy function can be used to linearise a sequence of buffers. For+ * example:+ *+ * @code vector<const_buffer> buffers = ...;+ *+ * vector<unsigned char> data(asio::buffer_size(buffers));+ * asio::buffer_copy(asio::buffer(data), buffers); @endcode+ *+ * Note that @ref buffer_copy is implemented in terms of @c memcpy, and+ * consequently it cannot be used to copy between overlapping memory regions.+ *+ * @par Buffer Invalidation+ *+ * A buffer object does not have any ownership of the memory it refers to. It+ * is the responsibility of the application to ensure the memory region remains+ * valid until it is no longer required for an I/O operation. When the memory+ * is no longer available, the buffer is said to have been invalidated.+ *+ * For the asio::buffer overloads that accept an argument of type+ * std::vector, the buffer objects returned are invalidated by any vector+ * operation that also invalidates all references, pointers and iterators+ * referring to the elements in the sequence (C++ Std, 23.2.4)+ *+ * For the asio::buffer overloads that accept an argument of type+ * std::basic_string, the buffer objects returned are invalidated according to+ * the rules defined for invalidation of references, pointers and iterators+ * referring to elements of the sequence (C++ Std, 21.3).+ *+ * @par Buffer Arithmetic+ *+ * Buffer objects may be manipulated using simple arithmetic in a safe way+ * which helps prevent buffer overruns. Consider an array initialised as+ * follows:+ *+ * @code boost::array<char, 6> a = { 'a', 'b', 'c', 'd', 'e' }; @endcode+ *+ * A buffer object @c b1 created using:+ *+ * @code b1 = asio::buffer(a); @endcode+ *+ * represents the entire array, <tt>{ 'a', 'b', 'c', 'd', 'e' }</tt>. An+ * optional second argument to the asio::buffer function may be used to+ * limit the size, in bytes, of the buffer:+ *+ * @code b2 = asio::buffer(a, 3); @endcode+ *+ * such that @c b2 represents the data <tt>{ 'a', 'b', 'c' }</tt>. Even if the+ * size argument exceeds the actual size of the array, the size of the buffer+ * object created will be limited to the array size.+ *+ * An offset may be applied to an existing buffer to create a new one:+ *+ * @code b3 = b1 + 2; @endcode+ *+ * where @c b3 will set to represent <tt>{ 'c', 'd', 'e' }</tt>. If the offset+ * exceeds the size of the existing buffer, the newly created buffer will be+ * empty.+ *+ * Both an offset and size may be specified to create a buffer that corresponds+ * to a specific range of bytes within an existing buffer:+ *+ * @code b4 = asio::buffer(b1 + 1, 3); @endcode+ *+ * so that @c b4 will refer to the bytes <tt>{ 'b', 'c', 'd' }</tt>.+ *+ * @par Buffers and Scatter-Gather I/O+ *+ * To read or write using multiple buffers (i.e. scatter-gather I/O), multiple+ * buffer objects may be assigned into a container that supports the+ * MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts:+ *+ * @code+ * char d1[128];+ * std::vector<char> d2(128);+ * boost::array<char, 128> d3;+ *+ * boost::array<mutable_buffer, 3> bufs1 = {+ * asio::buffer(d1),+ * asio::buffer(d2),+ * asio::buffer(d3) };+ * bytes_transferred = sock.receive(bufs1);+ *+ * std::vector<const_buffer> bufs2;+ * bufs2.push_back(asio::buffer(d1));+ * bufs2.push_back(asio::buffer(d2));+ * bufs2.push_back(asio::buffer(d3));+ * bytes_transferred = sock.send(bufs2); @endcode+ */+/*@{*/++#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)+# define ASIO_MUTABLE_BUFFER mutable_buffer+# define ASIO_CONST_BUFFER const_buffer+#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)+# define ASIO_MUTABLE_BUFFER mutable_buffers_1+# define ASIO_CONST_BUFFER const_buffers_1+#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)++/// Create a new modifiable buffer from an existing buffer.+/**+ * @returns <tt>mutable_buffer(b)</tt>.+ */+inline ASIO_MUTABLE_BUFFER buffer(+ const mutable_buffer& b) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(b);+}++/// Create a new modifiable buffer from an existing buffer.+/**+ * @returns A mutable_buffer value equivalent to:+ * @code mutable_buffer(+ * b.data(),+ * min(b.size(), max_size_in_bytes)); @endcode+ */+inline ASIO_MUTABLE_BUFFER buffer(const mutable_buffer& b,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(+ mutable_buffer(b.data(),+ b.size() < max_size_in_bytes+ ? b.size() : max_size_in_bytes+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , b.get_debug_check()+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ ));+}++/// Create a new non-modifiable buffer from an existing buffer.+/**+ * @returns <tt>const_buffer(b)</tt>.+ */+inline ASIO_CONST_BUFFER buffer(+ const const_buffer& b) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(b);+}++/// Create a new non-modifiable buffer from an existing buffer.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * b.data(),+ * min(b.size(), max_size_in_bytes)); @endcode+ */+inline ASIO_CONST_BUFFER buffer(const const_buffer& b,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(b.data(),+ b.size() < max_size_in_bytes+ ? b.size() : max_size_in_bytes+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , b.get_debug_check()+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++/// Create a new modifiable buffer that represents the given memory range.+/**+ * @returns <tt>mutable_buffer(data, size_in_bytes)</tt>.+ */+inline ASIO_MUTABLE_BUFFER buffer(void* data,+ std::size_t size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(data, size_in_bytes);+}++/// Create a new non-modifiable buffer that represents the given memory range.+/**+ * @returns <tt>const_buffer(data, size_in_bytes)</tt>.+ */+inline ASIO_CONST_BUFFER buffer(const void* data,+ std::size_t size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data, size_in_bytes);+}++/// Create a new modifiable buffer that represents the given POD array.+/**+ * @returns A mutable_buffer value equivalent to:+ * @code mutable_buffer(+ * static_cast<void*>(data),+ * N * sizeof(PodType)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N]) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(data, N * sizeof(PodType));+}+ +/// Create a new modifiable buffer that represents the given POD array.+/**+ * @returns A mutable_buffer value equivalent to:+ * @code mutable_buffer(+ * static_cast<void*>(data),+ * min(N * sizeof(PodType), max_size_in_bytes)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N],+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(data,+ N * sizeof(PodType) < max_size_in_bytes+ ? N * sizeof(PodType) : max_size_in_bytes);+}+ +/// Create a new non-modifiable buffer that represents the given POD array.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * static_cast<const void*>(data),+ * N * sizeof(PodType)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_CONST_BUFFER buffer(+ const PodType (&data)[N]) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data, N * sizeof(PodType));+}++/// Create a new non-modifiable buffer that represents the given POD array.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * static_cast<const void*>(data),+ * min(N * sizeof(PodType), max_size_in_bytes)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_CONST_BUFFER buffer(const PodType (&data)[N],+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data,+ N * sizeof(PodType) < max_size_in_bytes+ ? N * sizeof(PodType) : max_size_in_bytes);+}++#if defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND)++// Borland C++ and Sun Studio think the overloads:+//+// unspecified buffer(boost::array<PodType, N>& array ...);+//+// and+//+// unspecified buffer(boost::array<const PodType, N>& array ...);+//+// are ambiguous. This will be worked around by using a buffer_types traits+// class that contains typedefs for the appropriate buffer and container+// classes, based on whether PodType is const or non-const.++namespace detail {++template <bool IsConst>+struct buffer_types_base;++template <>+struct buffer_types_base<false>+{+ typedef mutable_buffer buffer_type;+ typedef ASIO_MUTABLE_BUFFER container_type;+};++template <>+struct buffer_types_base<true>+{+ typedef const_buffer buffer_type;+ typedef ASIO_CONST_BUFFER container_type;+};++template <typename PodType>+struct buffer_types+ : public buffer_types_base<is_const<PodType>::value>+{+};++} // namespace detail++template <typename PodType, std::size_t N>+inline typename detail::buffer_types<PodType>::container_type+buffer(boost::array<PodType, N>& data) ASIO_NOEXCEPT+{+ typedef typename asio::detail::buffer_types<PodType>::buffer_type+ buffer_type;+ typedef typename asio::detail::buffer_types<PodType>::container_type+ container_type;+ return container_type(+ buffer_type(data.c_array(), data.size() * sizeof(PodType)));+}++template <typename PodType, std::size_t N>+inline typename detail::buffer_types<PodType>::container_type+buffer(boost::array<PodType, N>& data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ typedef typename asio::detail::buffer_types<PodType>::buffer_type+ buffer_type;+ typedef typename asio::detail::buffer_types<PodType>::container_type+ container_type;+ return container_type(+ buffer_type(data.c_array(),+ data.size() * sizeof(PodType) < max_size_in_bytes+ ? data.size() * sizeof(PodType) : max_size_in_bytes));+}++#else // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND)++/// Create a new modifiable buffer that represents the given POD array.+/**+ * @returns A mutable_buffer value equivalent to:+ * @code mutable_buffer(+ * data.data(),+ * data.size() * sizeof(PodType)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_MUTABLE_BUFFER buffer(+ boost::array<PodType, N>& data) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(+ data.c_array(), data.size() * sizeof(PodType));+}++/// Create a new modifiable buffer that represents the given POD array.+/**+ * @returns A mutable_buffer value equivalent to:+ * @code mutable_buffer(+ * data.data(),+ * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_MUTABLE_BUFFER buffer(boost::array<PodType, N>& data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(data.c_array(),+ data.size() * sizeof(PodType) < max_size_in_bytes+ ? data.size() * sizeof(PodType) : max_size_in_bytes);+}++/// Create a new non-modifiable buffer that represents the given POD array.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * data.data(),+ * data.size() * sizeof(PodType)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_CONST_BUFFER buffer(+ boost::array<const PodType, N>& data) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));+}++/// Create a new non-modifiable buffer that represents the given POD array.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * data.data(),+ * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_CONST_BUFFER buffer(boost::array<const PodType, N>& data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.data(),+ data.size() * sizeof(PodType) < max_size_in_bytes+ ? data.size() * sizeof(PodType) : max_size_in_bytes);+}++#endif // defined(ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND)++/// Create a new non-modifiable buffer that represents the given POD array.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * data.data(),+ * data.size() * sizeof(PodType)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_CONST_BUFFER buffer(+ const boost::array<PodType, N>& data) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));+}++/// Create a new non-modifiable buffer that represents the given POD array.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * data.data(),+ * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_CONST_BUFFER buffer(const boost::array<PodType, N>& data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.data(),+ data.size() * sizeof(PodType) < max_size_in_bytes+ ? data.size() * sizeof(PodType) : max_size_in_bytes);+}++#if defined(ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION)++/// Create a new modifiable buffer that represents the given POD array.+/**+ * @returns A mutable_buffer value equivalent to:+ * @code mutable_buffer(+ * data.data(),+ * data.size() * sizeof(PodType)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_MUTABLE_BUFFER buffer(+ std::array<PodType, N>& data) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(data.data(), data.size() * sizeof(PodType));+}++/// Create a new modifiable buffer that represents the given POD array.+/**+ * @returns A mutable_buffer value equivalent to:+ * @code mutable_buffer(+ * data.data(),+ * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_MUTABLE_BUFFER buffer(std::array<PodType, N>& data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(data.data(),+ data.size() * sizeof(PodType) < max_size_in_bytes+ ? data.size() * sizeof(PodType) : max_size_in_bytes);+}++/// Create a new non-modifiable buffer that represents the given POD array.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * data.data(),+ * data.size() * sizeof(PodType)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_CONST_BUFFER buffer(+ std::array<const PodType, N>& data) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));+}++/// Create a new non-modifiable buffer that represents the given POD array.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * data.data(),+ * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_CONST_BUFFER buffer(std::array<const PodType, N>& data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.data(),+ data.size() * sizeof(PodType) < max_size_in_bytes+ ? data.size() * sizeof(PodType) : max_size_in_bytes);+}++/// Create a new non-modifiable buffer that represents the given POD array.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * data.data(),+ * data.size() * sizeof(PodType)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_CONST_BUFFER buffer(+ const std::array<PodType, N>& data) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType));+}++/// Create a new non-modifiable buffer that represents the given POD array.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * data.data(),+ * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode+ */+template <typename PodType, std::size_t N>+inline ASIO_CONST_BUFFER buffer(const std::array<PodType, N>& data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.data(),+ data.size() * sizeof(PodType) < max_size_in_bytes+ ? data.size() * sizeof(PodType) : max_size_in_bytes);+}++#endif // defined(ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION)++/// Create a new modifiable buffer that represents the given POD vector.+/**+ * @returns A mutable_buffer value equivalent to:+ * @code mutable_buffer(+ * data.size() ? &data[0] : 0,+ * data.size() * sizeof(PodType)); @endcode+ *+ * @note The buffer is invalidated by any vector operation that would also+ * invalidate iterators.+ */+template <typename PodType, typename Allocator>+inline ASIO_MUTABLE_BUFFER buffer(+ std::vector<PodType, Allocator>& data) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(+ data.size() ? &data[0] : 0, data.size() * sizeof(PodType)+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , detail::buffer_debug_check<+ typename std::vector<PodType, Allocator>::iterator+ >(data.begin())+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++/// Create a new modifiable buffer that represents the given POD vector.+/**+ * @returns A mutable_buffer value equivalent to:+ * @code mutable_buffer(+ * data.size() ? &data[0] : 0,+ * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode+ *+ * @note The buffer is invalidated by any vector operation that would also+ * invalidate iterators.+ */+template <typename PodType, typename Allocator>+inline ASIO_MUTABLE_BUFFER buffer(std::vector<PodType, Allocator>& data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0,+ data.size() * sizeof(PodType) < max_size_in_bytes+ ? data.size() * sizeof(PodType) : max_size_in_bytes+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , detail::buffer_debug_check<+ typename std::vector<PodType, Allocator>::iterator+ >(data.begin())+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++/// Create a new non-modifiable buffer that represents the given POD vector.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * data.size() ? &data[0] : 0,+ * data.size() * sizeof(PodType)); @endcode+ *+ * @note The buffer is invalidated by any vector operation that would also+ * invalidate iterators.+ */+template <typename PodType, typename Allocator>+inline ASIO_CONST_BUFFER buffer(+ const std::vector<PodType, Allocator>& data) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(+ data.size() ? &data[0] : 0, data.size() * sizeof(PodType)+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , detail::buffer_debug_check<+ typename std::vector<PodType, Allocator>::const_iterator+ >(data.begin())+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++/// Create a new non-modifiable buffer that represents the given POD vector.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * data.size() ? &data[0] : 0,+ * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode+ *+ * @note The buffer is invalidated by any vector operation that would also+ * invalidate iterators.+ */+template <typename PodType, typename Allocator>+inline ASIO_CONST_BUFFER buffer(+ const std::vector<PodType, Allocator>& data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0,+ data.size() * sizeof(PodType) < max_size_in_bytes+ ? data.size() * sizeof(PodType) : max_size_in_bytes+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , detail::buffer_debug_check<+ typename std::vector<PodType, Allocator>::const_iterator+ >(data.begin())+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++/// Create a new modifiable buffer that represents the given string.+/**+ * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0,+ * data.size() * sizeof(Elem))</tt>.+ *+ * @note The buffer is invalidated by any non-const operation called on the+ * given string object.+ */+template <typename Elem, typename Traits, typename Allocator>+inline ASIO_MUTABLE_BUFFER buffer(+ std::basic_string<Elem, Traits, Allocator>& data) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0,+ data.size() * sizeof(Elem)+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , detail::buffer_debug_check<+ typename std::basic_string<Elem, Traits, Allocator>::iterator+ >(data.begin())+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++/// Create a new modifiable buffer that represents the given string.+/**+ * @returns A mutable_buffer value equivalent to:+ * @code mutable_buffer(+ * data.size() ? &data[0] : 0,+ * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode+ *+ * @note The buffer is invalidated by any non-const operation called on the+ * given string object.+ */+template <typename Elem, typename Traits, typename Allocator>+inline ASIO_MUTABLE_BUFFER buffer(+ std::basic_string<Elem, Traits, Allocator>& data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0,+ data.size() * sizeof(Elem) < max_size_in_bytes+ ? data.size() * sizeof(Elem) : max_size_in_bytes+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , detail::buffer_debug_check<+ typename std::basic_string<Elem, Traits, Allocator>::iterator+ >(data.begin())+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++/// Create a new non-modifiable buffer that represents the given string.+/**+ * @returns <tt>const_buffer(data.data(), data.size() * sizeof(Elem))</tt>.+ *+ * @note The buffer is invalidated by any non-const operation called on the+ * given string object.+ */+template <typename Elem, typename Traits, typename Allocator>+inline ASIO_CONST_BUFFER buffer(+ const std::basic_string<Elem, Traits, Allocator>& data) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(Elem)+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , detail::buffer_debug_check<+ typename std::basic_string<Elem, Traits, Allocator>::const_iterator+ >(data.begin())+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++/// Create a new non-modifiable buffer that represents the given string.+/**+ * @returns A const_buffer value equivalent to:+ * @code const_buffer(+ * data.data(),+ * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode+ *+ * @note The buffer is invalidated by any non-const operation called on the+ * given string object.+ */+template <typename Elem, typename Traits, typename Allocator>+inline ASIO_CONST_BUFFER buffer(+ const std::basic_string<Elem, Traits, Allocator>& data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.data(),+ data.size() * sizeof(Elem) < max_size_in_bytes+ ? data.size() * sizeof(Elem) : max_size_in_bytes+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , detail::buffer_debug_check<+ typename std::basic_string<Elem, Traits, Allocator>::const_iterator+ >(data.begin())+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++#if defined(ASIO_HAS_STRING_VIEW) \+ || defined(GENERATING_DOCUMENTATION)++/// Create a new modifiable buffer that represents the given string_view.+/**+ * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0,+ * data.size() * sizeof(Elem))</tt>.+ */+template <typename Elem, typename Traits>+inline ASIO_CONST_BUFFER buffer(+ basic_string_view<Elem, Traits> data) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0,+ data.size() * sizeof(Elem)+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , detail::buffer_debug_check<+ typename basic_string_view<Elem, Traits>::iterator+ >(data.begin())+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++/// Create a new non-modifiable buffer that represents the given string.+/**+ * @returns A mutable_buffer value equivalent to:+ * @code mutable_buffer(+ * data.size() ? &data[0] : 0,+ * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode+ */+template <typename Elem, typename Traits>+inline ASIO_CONST_BUFFER buffer(+ basic_string_view<Elem, Traits> data,+ std::size_t max_size_in_bytes) ASIO_NOEXCEPT+{+ return ASIO_CONST_BUFFER(data.size() ? &data[0] : 0,+ data.size() * sizeof(Elem) < max_size_in_bytes+ ? data.size() * sizeof(Elem) : max_size_in_bytes+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ , detail::buffer_debug_check<+ typename basic_string_view<Elem, Traits>::iterator+ >(data.begin())+#endif // ASIO_ENABLE_BUFFER_DEBUGGING+ );+}++#endif // defined(ASIO_HAS_STRING_VIEW)+ // || defined(GENERATING_DOCUMENTATION)++/*@}*/++/// Adapt a basic_string to the DynamicBuffer requirements.+/**+ * Requires that <tt>sizeof(Elem) == 1</tt>.+ */+template <typename Elem, typename Traits, typename Allocator>+class dynamic_string_buffer+{+public:+ /// The type used to represent a sequence of constant buffers that refers to+ /// the underlying memory.+ typedef ASIO_CONST_BUFFER const_buffers_type;++ /// The type used to represent a sequence of mutable buffers that refers to+ /// the underlying memory.+ typedef ASIO_MUTABLE_BUFFER mutable_buffers_type;++ /// Construct a dynamic buffer from a string.+ /**+ * @param s The string to be used as backing storage for the dynamic buffer.+ * The object stores a reference to the string and the user is responsible+ * for ensuring that the string object remains valid while the+ * dynamic_string_buffer object, and copies of the object, are in use.+ *+ * @b DynamicBuffer_v1: Any existing data in the string is treated as the+ * dynamic buffer's input sequence.+ *+ * @param maximum_size Specifies a maximum size for the buffer, in bytes.+ */+ explicit dynamic_string_buffer(std::basic_string<Elem, Traits, Allocator>& s,+ std::size_t maximum_size =+ (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT+ : string_(s),+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ size_((std::numeric_limits<std::size_t>::max)()),+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ max_size_(maximum_size)+ {+ }++ /// @b DynamicBuffer_v2: Copy construct a dynamic buffer.+ dynamic_string_buffer(const dynamic_string_buffer& other) ASIO_NOEXCEPT+ : string_(other.string_),+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ size_(other.size_),+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ max_size_(other.max_size_)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move construct a dynamic buffer.+ dynamic_string_buffer(dynamic_string_buffer&& other) ASIO_NOEXCEPT+ : string_(other.string_),+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ size_(other.size_),+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ max_size_(other.max_size_)+ {+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// @b DynamicBuffer_v1: Get the size of the input sequence.+ /// @b DynamicBuffer_v2: Get the current size of the underlying memory.+ /**+ * @returns @b DynamicBuffer_v1 The current size of the input sequence.+ * @b DynamicBuffer_v2: The current size of the underlying string if less than+ * max_size(). Otherwise returns max_size().+ */+ std::size_t size() const ASIO_NOEXCEPT+ {+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ if (size_ != (std::numeric_limits<std::size_t>::max)())+ return size_;+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ return (std::min)(string_.size(), max_size());+ }++ /// Get the maximum size of the dynamic buffer.+ /**+ * @returns The allowed maximum size of the underlying memory.+ */+ std::size_t max_size() const ASIO_NOEXCEPT+ {+ return max_size_;+ }++ /// Get the maximum size that the buffer may grow to without triggering+ /// reallocation.+ /**+ * @returns The current capacity of the underlying string if less than+ * max_size(). Otherwise returns max_size().+ */+ std::size_t capacity() const ASIO_NOEXCEPT+ {+ return (std::min)(string_.capacity(), max_size());+ }++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ /// @b DynamicBuffer_v1: Get a list of buffers that represents the input+ /// sequence.+ /**+ * @returns An object of type @c const_buffers_type that satisfies+ * ConstBufferSequence requirements, representing the basic_string memory in+ * the input sequence.+ *+ * @note The returned object is invalidated by any @c dynamic_string_buffer+ * or @c basic_string member function that resizes or erases the string.+ */+ const_buffers_type data() const ASIO_NOEXCEPT+ {+ return const_buffers_type(asio::buffer(string_, size_));+ }+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++ /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the+ /// underlying memory.+ /**+ * @param pos Position of the first byte to represent in the buffer sequence+ *+ * @param n The number of bytes to return in the buffer sequence. If the+ * underlying memory is shorter, the buffer sequence represents as many bytes+ * as are available.+ *+ * @returns An object of type @c mutable_buffers_type that satisfies+ * MutableBufferSequence requirements, representing the basic_string memory.+ *+ * @note The returned object is invalidated by any @c dynamic_string_buffer+ * or @c basic_string member function that resizes or erases the string.+ */+ mutable_buffers_type data(std::size_t pos, std::size_t n) ASIO_NOEXCEPT+ {+ return mutable_buffers_type(asio::buffer(+ asio::buffer(string_, max_size_) + pos, n));+ }++ /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the+ /// underlying memory.+ /**+ * @param pos Position of the first byte to represent in the buffer sequence+ *+ * @param n The number of bytes to return in the buffer sequence. If the+ * underlying memory is shorter, the buffer sequence represents as many bytes+ * as are available.+ *+ * @note The returned object is invalidated by any @c dynamic_string_buffer+ * or @c basic_string member function that resizes or erases the string.+ */+ const_buffers_type data(std::size_t pos,+ std::size_t n) const ASIO_NOEXCEPT+ {+ return const_buffers_type(asio::buffer(+ asio::buffer(string_, max_size_) + pos, n));+ }++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ /// @b DynamicBuffer_v1: Get a list of buffers that represents the output+ /// sequence, with the given size.+ /**+ * Ensures that the output sequence can accommodate @c n bytes, resizing the+ * basic_string object as necessary.+ *+ * @returns An object of type @c mutable_buffers_type that satisfies+ * MutableBufferSequence requirements, representing basic_string memory+ * at the start of the output sequence of size @c n.+ *+ * @throws std::length_error If <tt>size() + n > max_size()</tt>.+ *+ * @note The returned object is invalidated by any @c dynamic_string_buffer+ * or @c basic_string member function that modifies the input sequence or+ * output sequence.+ */+ mutable_buffers_type prepare(std::size_t n)+ {+ if (size() > max_size() || max_size() - size() < n)+ {+ std::length_error ex("dynamic_string_buffer too long");+ asio::detail::throw_exception(ex);+ }++ if (size_ == (std::numeric_limits<std::size_t>::max)())+ size_ = string_.size(); // Enable v1 behaviour.++ string_.resize(size_ + n);++ return asio::buffer(asio::buffer(string_) + size_, n);+ }++ /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input+ /// sequence.+ /**+ * @param n The number of bytes to append from the start of the output+ * sequence to the end of the input sequence. The remainder of the output+ * sequence is discarded.+ *+ * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and+ * no intervening operations that modify the input or output sequence.+ *+ * @note If @c n is greater than the size of the output sequence, the entire+ * output sequence is moved to the input sequence and no error is issued.+ */+ void commit(std::size_t n)+ {+ size_ += (std::min)(n, string_.size() - size_);+ string_.resize(size_);+ }+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++ /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of+ /// bytes.+ /**+ * Resizes the string to accommodate an additional @c n bytes at the end.+ *+ * @throws std::length_error If <tt>size() + n > max_size()</tt>.+ */+ void grow(std::size_t n)+ {+ if (size() > max_size() || max_size() - size() < n)+ {+ std::length_error ex("dynamic_string_buffer too long");+ asio::detail::throw_exception(ex);+ }++ string_.resize(size() + n);+ }++ /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number+ /// of bytes.+ /**+ * Erases @c n bytes from the end of the string by resizing the basic_string+ * object. If @c n is greater than the current size of the string, the string+ * is emptied.+ */+ void shrink(std::size_t n)+ {+ string_.resize(n > size() ? 0 : size() - n);+ }++ /// @b DynamicBuffer_v1: Remove characters from the input sequence.+ /// @b DynamicBuffer_v2: Consume the specified number of bytes from the+ /// beginning of the underlying memory.+ /**+ * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the+ * input sequence. @note If @c n is greater than the size of the input+ * sequence, the entire input sequence is consumed and no error is issued.+ *+ * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the string.+ * If @c n is greater than the current size of the string, the string is+ * emptied.+ */+ void consume(std::size_t n)+ {+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ if (size_ != (std::numeric_limits<std::size_t>::max)())+ {+ std::size_t consume_length = (std::min)(n, size_);+ string_.erase(0, consume_length);+ size_ -= consume_length;+ return;+ }+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ string_.erase(0, n);+ }++private:+ std::basic_string<Elem, Traits, Allocator>& string_;+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ std::size_t size_;+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ const std::size_t max_size_;+};++/// Adapt a vector to the DynamicBuffer requirements.+/**+ * Requires that <tt>sizeof(Elem) == 1</tt>.+ */+template <typename Elem, typename Allocator>+class dynamic_vector_buffer+{+public:+ /// The type used to represent a sequence of constant buffers that refers to+ /// the underlying memory.+ typedef ASIO_CONST_BUFFER const_buffers_type;++ /// The type used to represent a sequence of mutable buffers that refers to+ /// the underlying memory.+ typedef ASIO_MUTABLE_BUFFER mutable_buffers_type;++ /// Construct a dynamic buffer from a vector.+ /**+ * @param v The vector to be used as backing storage for the dynamic buffer.+ * The object stores a reference to the vector and the user is responsible+ * for ensuring that the vector object remains valid while the+ * dynamic_vector_buffer object, and copies of the object, are in use.+ *+ * @param maximum_size Specifies a maximum size for the buffer, in bytes.+ */+ explicit dynamic_vector_buffer(std::vector<Elem, Allocator>& v,+ std::size_t maximum_size =+ (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT+ : vector_(v),+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ size_((std::numeric_limits<std::size_t>::max)()),+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ max_size_(maximum_size)+ {+ }++ /// @b DynamicBuffer_v2: Copy construct a dynamic buffer.+ dynamic_vector_buffer(const dynamic_vector_buffer& other) ASIO_NOEXCEPT+ : vector_(other.vector_),+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ size_(other.size_),+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ max_size_(other.max_size_)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move construct a dynamic buffer.+ dynamic_vector_buffer(dynamic_vector_buffer&& other) ASIO_NOEXCEPT+ : vector_(other.vector_),+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ size_(other.size_),+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ max_size_(other.max_size_)+ {+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// @b DynamicBuffer_v1: Get the size of the input sequence.+ /// @b DynamicBuffer_v2: Get the current size of the underlying memory.+ /**+ * @returns @b DynamicBuffer_v1 The current size of the input sequence.+ * @b DynamicBuffer_v2: The current size of the underlying vector if less than+ * max_size(). Otherwise returns max_size().+ */+ std::size_t size() const ASIO_NOEXCEPT+ {+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ if (size_ != (std::numeric_limits<std::size_t>::max)())+ return size_;+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ return (std::min)(vector_.size(), max_size());+ }++ /// Get the maximum size of the dynamic buffer.+ /**+ * @returns @b DynamicBuffer_v1: The allowed maximum of the sum of the sizes+ * of the input sequence and output sequence. @b DynamicBuffer_v2: The allowed+ * maximum size of the underlying memory.+ */+ std::size_t max_size() const ASIO_NOEXCEPT+ {+ return max_size_;+ }++ /// Get the maximum size that the buffer may grow to without triggering+ /// reallocation.+ /**+ * @returns @b DynamicBuffer_v1: The current total capacity of the buffer,+ * i.e. for both the input sequence and output sequence. @b DynamicBuffer_v2:+ * The current capacity of the underlying vector if less than max_size().+ * Otherwise returns max_size().+ */+ std::size_t capacity() const ASIO_NOEXCEPT+ {+ return (std::min)(vector_.capacity(), max_size());+ }++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ /// @b DynamicBuffer_v1: Get a list of buffers that represents the input+ /// sequence.+ /**+ * @returns An object of type @c const_buffers_type that satisfies+ * ConstBufferSequence requirements, representing the vector memory in the+ * input sequence.+ *+ * @note The returned object is invalidated by any @c dynamic_vector_buffer+ * or @c vector member function that modifies the input sequence or output+ * sequence.+ */+ const_buffers_type data() const ASIO_NOEXCEPT+ {+ return const_buffers_type(asio::buffer(vector_, size_));+ }+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++ /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the+ /// underlying memory.+ /**+ * @param pos Position of the first byte to represent in the buffer sequence+ *+ * @param n The number of bytes to return in the buffer sequence. If the+ * underlying memory is shorter, the buffer sequence represents as many bytes+ * as are available.+ *+ * @returns An object of type @c mutable_buffers_type that satisfies+ * MutableBufferSequence requirements, representing the vector memory.+ *+ * @note The returned object is invalidated by any @c dynamic_vector_buffer+ * or @c vector member function that resizes or erases the vector.+ */+ mutable_buffers_type data(std::size_t pos, std::size_t n) ASIO_NOEXCEPT+ {+ return mutable_buffers_type(asio::buffer(+ asio::buffer(vector_, max_size_) + pos, n));+ }++ /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the+ /// underlying memory.+ /**+ * @param pos Position of the first byte to represent in the buffer sequence+ *+ * @param n The number of bytes to return in the buffer sequence. If the+ * underlying memory is shorter, the buffer sequence represents as many bytes+ * as are available.+ *+ * @note The returned object is invalidated by any @c dynamic_vector_buffer+ * or @c vector member function that resizes or erases the vector.+ */+ const_buffers_type data(std::size_t pos,+ std::size_t n) const ASIO_NOEXCEPT+ {+ return const_buffers_type(asio::buffer(+ asio::buffer(vector_, max_size_) + pos, n));+ }++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ /// @b DynamicBuffer_v1: Get a list of buffers that represents the output+ /// sequence, with the given size.+ /**+ * Ensures that the output sequence can accommodate @c n bytes, resizing the+ * vector object as necessary.+ *+ * @returns An object of type @c mutable_buffers_type that satisfies+ * MutableBufferSequence requirements, representing vector memory at the+ * start of the output sequence of size @c n.+ *+ * @throws std::length_error If <tt>size() + n > max_size()</tt>.+ *+ * @note The returned object is invalidated by any @c dynamic_vector_buffer+ * or @c vector member function that modifies the input sequence or output+ * sequence.+ */+ mutable_buffers_type prepare(std::size_t n)+ {+ if (size () > max_size() || max_size() - size() < n)+ {+ std::length_error ex("dynamic_vector_buffer too long");+ asio::detail::throw_exception(ex);+ }++ if (size_ == (std::numeric_limits<std::size_t>::max)())+ size_ = vector_.size(); // Enable v1 behaviour.++ vector_.resize(size_ + n);++ return asio::buffer(asio::buffer(vector_) + size_, n);+ }++ /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input+ /// sequence.+ /**+ * @param n The number of bytes to append from the start of the output+ * sequence to the end of the input sequence. The remainder of the output+ * sequence is discarded.+ *+ * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and+ * no intervening operations that modify the input or output sequence.+ *+ * @note If @c n is greater than the size of the output sequence, the entire+ * output sequence is moved to the input sequence and no error is issued.+ */+ void commit(std::size_t n)+ {+ size_ += (std::min)(n, vector_.size() - size_);+ vector_.resize(size_);+ }+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++ /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of+ /// bytes.+ /**+ * Resizes the vector to accommodate an additional @c n bytes at the end.+ *+ * @throws std::length_error If <tt>size() + n > max_size()</tt>.+ */+ void grow(std::size_t n)+ {+ if (size() > max_size() || max_size() - size() < n)+ {+ std::length_error ex("dynamic_vector_buffer too long");+ asio::detail::throw_exception(ex);+ }++ vector_.resize(size() + n);+ }++ /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number+ /// of bytes.+ /**+ * Erases @c n bytes from the end of the vector by resizing the vector+ * object. If @c n is greater than the current size of the vector, the vector+ * is emptied.+ */+ void shrink(std::size_t n)+ {+ vector_.resize(n > size() ? 0 : size() - n);+ }++ /// @b DynamicBuffer_v1: Remove characters from the input sequence.+ /// @b DynamicBuffer_v2: Consume the specified number of bytes from the+ /// beginning of the underlying memory.+ /**+ * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the+ * input sequence. @note If @c n is greater than the size of the input+ * sequence, the entire input sequence is consumed and no error is issued.+ *+ * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the vector.+ * If @c n is greater than the current size of the vector, the vector is+ * emptied.+ */+ void consume(std::size_t n)+ {+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ if (size_ != (std::numeric_limits<std::size_t>::max)())+ {+ std::size_t consume_length = (std::min)(n, size_);+ vector_.erase(vector_.begin(), vector_.begin() + consume_length);+ size_ -= consume_length;+ return;+ }+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ vector_.erase(vector_.begin(), vector_.begin() + (std::min)(size(), n));+ }++private:+ std::vector<Elem, Allocator>& vector_;+#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ std::size_t size_;+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ const std::size_t max_size_;+};++/** @defgroup dynamic_buffer asio::dynamic_buffer+ *+ * @brief The asio::dynamic_buffer function is used to create a+ * dynamically resized buffer from a @c std::basic_string or @c std::vector.+ */+/*@{*/++/// Create a new dynamic buffer that represents the given string.+/**+ * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data)</tt>.+ */+template <typename Elem, typename Traits, typename Allocator>+inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer(+ std::basic_string<Elem, Traits, Allocator>& data) ASIO_NOEXCEPT+{+ return dynamic_string_buffer<Elem, Traits, Allocator>(data);+}++/// Create a new dynamic buffer that represents the given string.+/**+ * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data,+ * max_size)</tt>.+ */+template <typename Elem, typename Traits, typename Allocator>+inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer(+ std::basic_string<Elem, Traits, Allocator>& data,+ std::size_t max_size) ASIO_NOEXCEPT+{+ return dynamic_string_buffer<Elem, Traits, Allocator>(data, max_size);+}++/// Create a new dynamic buffer that represents the given vector.+/**+ * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data)</tt>.+ */+template <typename Elem, typename Allocator>+inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer(+ std::vector<Elem, Allocator>& data) ASIO_NOEXCEPT+{+ return dynamic_vector_buffer<Elem, Allocator>(data);+}++/// Create a new dynamic buffer that represents the given vector.+/**+ * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data, max_size)</tt>.+ */+template <typename Elem, typename Allocator>+inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer(+ std::vector<Elem, Allocator>& data,+ std::size_t max_size) ASIO_NOEXCEPT+{+ return dynamic_vector_buffer<Elem, Allocator>(data, max_size);+}++/*@}*/++/** @defgroup buffer_copy asio::buffer_copy+ *+ * @brief The asio::buffer_copy function is used to copy bytes from a+ * source buffer (or buffer sequence) to a target buffer (or buffer sequence).+ *+ * The @c buffer_copy function is available in two forms:+ *+ * @li A 2-argument form: @c buffer_copy(target, source)+ *+ * @li A 3-argument form: @c buffer_copy(target, source, max_bytes_to_copy)+ *+ * Both forms return the number of bytes actually copied. The number of bytes+ * copied is the lesser of:+ *+ * @li @c buffer_size(target)+ *+ * @li @c buffer_size(source)+ *+ * @li @c If specified, @c max_bytes_to_copy.+ *+ * This prevents buffer overflow, regardless of the buffer sizes used in the+ * copy operation.+ *+ * Note that @ref buffer_copy is implemented in terms of @c memcpy, and+ * consequently it cannot be used to copy between overlapping memory regions.+ */+/*@{*/++namespace detail {++inline std::size_t buffer_copy_1(const mutable_buffer& target,+ const const_buffer& source)+{+ using namespace std; // For memcpy.+ std::size_t target_size = target.size();+ std::size_t source_size = source.size();+ std::size_t n = target_size < source_size ? target_size : source_size;+ if (n > 0)+ memcpy(target.data(), source.data(), n);+ return n;+}++template <typename TargetIterator, typename SourceIterator>+inline std::size_t buffer_copy(one_buffer, one_buffer,+ TargetIterator target_begin, TargetIterator,+ SourceIterator source_begin, SourceIterator) ASIO_NOEXCEPT+{+ return (buffer_copy_1)(*target_begin, *source_begin);+}++template <typename TargetIterator, typename SourceIterator>+inline std::size_t buffer_copy(one_buffer, one_buffer,+ TargetIterator target_begin, TargetIterator,+ SourceIterator source_begin, SourceIterator,+ std::size_t max_bytes_to_copy) ASIO_NOEXCEPT+{+ return (buffer_copy_1)(*target_begin,+ asio::buffer(*source_begin, max_bytes_to_copy));+}++template <typename TargetIterator, typename SourceIterator>+std::size_t buffer_copy(one_buffer, multiple_buffers,+ TargetIterator target_begin, TargetIterator,+ SourceIterator source_begin, SourceIterator source_end,+ std::size_t max_bytes_to_copy+ = (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT+{+ std::size_t total_bytes_copied = 0;+ SourceIterator source_iter = source_begin;++ for (mutable_buffer target_buffer(+ asio::buffer(*target_begin, max_bytes_to_copy));+ target_buffer.size() && source_iter != source_end; ++source_iter)+ {+ const_buffer source_buffer(*source_iter);+ std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer);+ total_bytes_copied += bytes_copied;+ target_buffer += bytes_copied;+ }++ return total_bytes_copied;+}++template <typename TargetIterator, typename SourceIterator>+std::size_t buffer_copy(multiple_buffers, one_buffer,+ TargetIterator target_begin, TargetIterator target_end,+ SourceIterator source_begin, SourceIterator,+ std::size_t max_bytes_to_copy+ = (std::numeric_limits<std::size_t>::max)()) ASIO_NOEXCEPT+{+ std::size_t total_bytes_copied = 0;+ TargetIterator target_iter = target_begin;++ for (const_buffer source_buffer(+ asio::buffer(*source_begin, max_bytes_to_copy));+ source_buffer.size() && target_iter != target_end; ++target_iter)+ {+ mutable_buffer target_buffer(*target_iter);+ std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer);+ total_bytes_copied += bytes_copied;+ source_buffer += bytes_copied;+ }++ return total_bytes_copied;+}++template <typename TargetIterator, typename SourceIterator>+std::size_t buffer_copy(multiple_buffers, multiple_buffers,+ TargetIterator target_begin, TargetIterator target_end,+ SourceIterator source_begin, SourceIterator source_end) ASIO_NOEXCEPT+{+ std::size_t total_bytes_copied = 0;++ TargetIterator target_iter = target_begin;+ std::size_t target_buffer_offset = 0;++ SourceIterator source_iter = source_begin;+ std::size_t source_buffer_offset = 0;++ while (target_iter != target_end && source_iter != source_end)+ {+ mutable_buffer target_buffer =+ mutable_buffer(*target_iter) + target_buffer_offset;++ const_buffer source_buffer =+ const_buffer(*source_iter) + source_buffer_offset;++ std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer);+ total_bytes_copied += bytes_copied;++ if (bytes_copied == target_buffer.size())+ {+ ++target_iter;+ target_buffer_offset = 0;+ }+ else+ target_buffer_offset += bytes_copied;++ if (bytes_copied == source_buffer.size())+ {+ ++source_iter;+ source_buffer_offset = 0;+ }+ else+ source_buffer_offset += bytes_copied;+ }++ return total_bytes_copied;+}++template <typename TargetIterator, typename SourceIterator>+std::size_t buffer_copy(multiple_buffers, multiple_buffers,+ TargetIterator target_begin, TargetIterator target_end,+ SourceIterator source_begin, SourceIterator source_end,+ std::size_t max_bytes_to_copy) ASIO_NOEXCEPT+{+ std::size_t total_bytes_copied = 0;++ TargetIterator target_iter = target_begin;+ std::size_t target_buffer_offset = 0;++ SourceIterator source_iter = source_begin;+ std::size_t source_buffer_offset = 0;++ while (total_bytes_copied != max_bytes_to_copy+ && target_iter != target_end && source_iter != source_end)+ {+ mutable_buffer target_buffer =+ mutable_buffer(*target_iter) + target_buffer_offset;++ const_buffer source_buffer =+ const_buffer(*source_iter) + source_buffer_offset;++ std::size_t bytes_copied = (buffer_copy_1)(+ target_buffer, asio::buffer(source_buffer,+ max_bytes_to_copy - total_bytes_copied));+ total_bytes_copied += bytes_copied;++ if (bytes_copied == target_buffer.size())+ {+ ++target_iter;+ target_buffer_offset = 0;+ }+ else+ target_buffer_offset += bytes_copied;++ if (bytes_copied == source_buffer.size())+ {+ ++source_iter;+ source_buffer_offset = 0;+ }+ else+ source_buffer_offset += bytes_copied;+ }++ return total_bytes_copied;+}++} // namespace detail++/// Copies bytes from a source buffer sequence to a target buffer sequence.+/**+ * @param target A modifiable buffer sequence representing the memory regions to+ * which the bytes will be copied.+ *+ * @param source A non-modifiable buffer sequence representing the memory+ * regions from which the bytes will be copied.+ *+ * @returns The number of bytes copied.+ *+ * @note The number of bytes copied is the lesser of:+ *+ * @li @c buffer_size(target)+ *+ * @li @c buffer_size(source)+ *+ * This function is implemented in terms of @c memcpy, and consequently it+ * cannot be used to copy between overlapping memory regions.+ */+template <typename MutableBufferSequence, typename ConstBufferSequence>+inline std::size_t buffer_copy(const MutableBufferSequence& target,+ const ConstBufferSequence& source) ASIO_NOEXCEPT+{+ return detail::buffer_copy(+ detail::buffer_sequence_cardinality<MutableBufferSequence>(),+ detail::buffer_sequence_cardinality<ConstBufferSequence>(),+ asio::buffer_sequence_begin(target),+ asio::buffer_sequence_end(target),+ asio::buffer_sequence_begin(source),+ asio::buffer_sequence_end(source));+}++/// Copies a limited number of bytes from a source buffer sequence to a target+/// buffer sequence.+/**+ * @param target A modifiable buffer sequence representing the memory regions to+ * which the bytes will be copied.+ *+ * @param source A non-modifiable buffer sequence representing the memory+ * regions from which the bytes will be copied.+ *+ * @param max_bytes_to_copy The maximum number of bytes to be copied.+ *+ * @returns The number of bytes copied.+ *+ * @note The number of bytes copied is the lesser of:+ *+ * @li @c buffer_size(target)+ *+ * @li @c buffer_size(source)+ *+ * @li @c max_bytes_to_copy+ *+ * This function is implemented in terms of @c memcpy, and consequently it+ * cannot be used to copy between overlapping memory regions.+ */+template <typename MutableBufferSequence, typename ConstBufferSequence>+inline std::size_t buffer_copy(const MutableBufferSequence& target,+ const ConstBufferSequence& source,+ std::size_t max_bytes_to_copy) ASIO_NOEXCEPT+{+ return detail::buffer_copy(+ detail::buffer_sequence_cardinality<MutableBufferSequence>(),+ detail::buffer_sequence_cardinality<ConstBufferSequence>(),+ asio::buffer_sequence_begin(target),+ asio::buffer_sequence_end(target),+ asio::buffer_sequence_begin(source),+ asio::buffer_sequence_end(source), max_bytes_to_copy);+}++/*@}*/++} // namespace asio++#include "asio/detail/pop_options.hpp"+#include "asio/detail/is_buffer_sequence.hpp"+#include "asio/detail/push_options.hpp"++namespace asio {++/// Trait to determine whether a type satisfies the MutableBufferSequence+/// requirements.+template <typename T>+struct is_mutable_buffer_sequence+#if defined(GENERATING_DOCUMENTATION)+ : integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ : asio::detail::is_buffer_sequence<T, mutable_buffer>+#endif // defined(GENERATING_DOCUMENTATION)+{+};++/// Trait to determine whether a type satisfies the ConstBufferSequence+/// requirements.+template <typename T>+struct is_const_buffer_sequence+#if defined(GENERATING_DOCUMENTATION)+ : integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ : asio::detail::is_buffer_sequence<T, const_buffer>+#endif // defined(GENERATING_DOCUMENTATION)+{+};++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)+/// Trait to determine whether a type satisfies the DynamicBuffer_v1+/// requirements.+template <typename T>+struct is_dynamic_buffer_v1+#if defined(GENERATING_DOCUMENTATION)+ : integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ : asio::detail::is_dynamic_buffer_v1<T>+#endif // defined(GENERATING_DOCUMENTATION)+{+};+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Trait to determine whether a type satisfies the DynamicBuffer_v2+/// requirements.+template <typename T>+struct is_dynamic_buffer_v2+#if defined(GENERATING_DOCUMENTATION)+ : integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ : asio::detail::is_dynamic_buffer_v2<T>+#endif // defined(GENERATING_DOCUMENTATION)+{+};++/// Trait to determine whether a type satisfies the DynamicBuffer requirements.+/**+ * If @c ASIO_NO_DYNAMIC_BUFFER_V1 is not defined, determines whether the+ * type satisfies the DynamicBuffer_v1 requirements. Otherwise, if @c+ * ASIO_NO_DYNAMIC_BUFFER_V1 is defined, determines whether the type+ * satisfies the DynamicBuffer_v2 requirements.+ */+template <typename T>+struct is_dynamic_buffer+#if defined(GENERATING_DOCUMENTATION)+ : integral_constant<bool, automatically_determined>+#elif defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ : asio::is_dynamic_buffer_v2<T>+#else // defined(ASIO_NO_DYNAMIC_BUFFER_V1)+ : asio::is_dynamic_buffer_v1<T>+#endif // defined(ASIO_NO_DYNAMIC_BUFFER_V1)+{+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BUFFER_HPP
+ link/modules/asio-standalone/asio/include/asio/buffered_read_stream.hpp view
@@ -0,0 +1,253 @@+//+// buffered_read_stream.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BUFFERED_READ_STREAM_HPP+#define ASIO_BUFFERED_READ_STREAM_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/async_result.hpp"+#include "asio/buffered_read_stream_fwd.hpp"+#include "asio/buffer.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_resize_guard.hpp"+#include "asio/detail/buffered_stream_storage.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Adds buffering to the read-related operations of a stream.+/**+ * The buffered_read_stream class template can be used to add buffering to the+ * synchronous and asynchronous read operations of a stream.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Concepts:+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.+ */+template <typename Stream>+class buffered_read_stream+ : private noncopyable+{+public:+ /// The type of the next layer.+ typedef typename remove_reference<Stream>::type next_layer_type;++ /// The type of the lowest layer.+ typedef typename next_layer_type::lowest_layer_type lowest_layer_type;++ /// The type of the executor associated with the object.+ typedef typename lowest_layer_type::executor_type executor_type;++#if defined(GENERATING_DOCUMENTATION)+ /// The default buffer size.+ static const std::size_t default_buffer_size = implementation_defined;+#else+ ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);+#endif++ /// Construct, passing the specified argument to initialise the next layer.+ template <typename Arg>+ explicit buffered_read_stream(Arg& a)+ : next_layer_(a),+ storage_(default_buffer_size)+ {+ }++ /// Construct, passing the specified argument to initialise the next layer.+ template <typename Arg>+ buffered_read_stream(Arg& a, std::size_t buffer_size)+ : next_layer_(a),+ storage_(buffer_size)+ {+ }++ /// Get a reference to the next layer.+ next_layer_type& next_layer()+ {+ return next_layer_;+ }++ /// Get a reference to the lowest layer.+ lowest_layer_type& lowest_layer()+ {+ return next_layer_.lowest_layer();+ }++ /// Get a const reference to the lowest layer.+ const lowest_layer_type& lowest_layer() const+ {+ return next_layer_.lowest_layer();+ }++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_NOEXCEPT+ {+ return next_layer_.lowest_layer().get_executor();+ }++ /// Close the stream.+ void close()+ {+ next_layer_.close();+ }++ /// Close the stream.+ ASIO_SYNC_OP_VOID close(asio::error_code& ec)+ {+ next_layer_.close(ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Write the given data to the stream. Returns the number of bytes written.+ /// Throws an exception on failure.+ template <typename ConstBufferSequence>+ std::size_t write_some(const ConstBufferSequence& buffers)+ {+ return next_layer_.write_some(buffers);+ }++ /// Write the given data to the stream. Returns the number of bytes written,+ /// or 0 if an error occurred.+ template <typename ConstBufferSequence>+ std::size_t write_some(const ConstBufferSequence& buffers,+ asio::error_code& ec)+ {+ return next_layer_.write_some(buffers, ec);+ }++ /// Start an asynchronous write. The data being written must be valid for the+ /// lifetime of the asynchronous operation.+ template <typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_write_some(const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return next_layer_.async_write_some(buffers,+ ASIO_MOVE_CAST(WriteHandler)(handler));+ }++ /// Fill the buffer with some data. Returns the number of bytes placed in the+ /// buffer as a result of the operation. Throws an exception on failure.+ std::size_t fill();++ /// Fill the buffer with some data. Returns the number of bytes placed in the+ /// buffer as a result of the operation, or 0 if an error occurred.+ std::size_t fill(asio::error_code& ec);++ /// Start an asynchronous fill.+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_fill(+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));++ /// Read some data from the stream. Returns the number of bytes read. Throws+ /// an exception on failure.+ template <typename MutableBufferSequence>+ std::size_t read_some(const MutableBufferSequence& buffers);++ /// Read some data from the stream. Returns the number of bytes read or 0 if+ /// an error occurred.+ template <typename MutableBufferSequence>+ std::size_t read_some(const MutableBufferSequence& buffers,+ asio::error_code& ec);++ /// Start an asynchronous read. The buffer into which the data will be read+ /// must be valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_read_some(const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));++ /// Peek at the incoming data on the stream. Returns the number of bytes read.+ /// Throws an exception on failure.+ template <typename MutableBufferSequence>+ std::size_t peek(const MutableBufferSequence& buffers);++ /// Peek at the incoming data on the stream. Returns the number of bytes read,+ /// or 0 if an error occurred.+ template <typename MutableBufferSequence>+ std::size_t peek(const MutableBufferSequence& buffers,+ asio::error_code& ec);++ /// Determine the amount of data that may be read without blocking.+ std::size_t in_avail()+ {+ return storage_.size();+ }++ /// Determine the amount of data that may be read without blocking.+ std::size_t in_avail(asio::error_code& ec)+ {+ ec = asio::error_code();+ return storage_.size();+ }++private:+ /// Copy data out of the internal buffer to the specified target buffer.+ /// Returns the number of bytes copied.+ template <typename MutableBufferSequence>+ std::size_t copy(const MutableBufferSequence& buffers)+ {+ std::size_t bytes_copied = asio::buffer_copy(+ buffers, storage_.data(), storage_.size());+ storage_.consume(bytes_copied);+ return bytes_copied;+ }++ /// Copy data from the internal buffer to the specified target buffer, without+ /// removing the data from the internal buffer. Returns the number of bytes+ /// copied.+ template <typename MutableBufferSequence>+ std::size_t peek_copy(const MutableBufferSequence& buffers)+ {+ return asio::buffer_copy(buffers, storage_.data(), storage_.size());+ }++ /// The next layer.+ Stream next_layer_;++ // The data in the buffer.+ detail::buffered_stream_storage storage_;+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/buffered_read_stream.hpp"++#endif // ASIO_BUFFERED_READ_STREAM_HPP
+ link/modules/asio-standalone/asio/include/asio/buffered_read_stream_fwd.hpp view
@@ -0,0 +1,25 @@+//+// buffered_read_stream_fwd.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BUFFERED_READ_STREAM_FWD_HPP+#define ASIO_BUFFERED_READ_STREAM_FWD_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++namespace asio {++template <typename Stream>+class buffered_read_stream;++} // namespace asio++#endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP
+ link/modules/asio-standalone/asio/include/asio/buffered_stream.hpp view
@@ -0,0 +1,279 @@+//+// buffered_stream.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BUFFERED_STREAM_HPP+#define ASIO_BUFFERED_STREAM_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/async_result.hpp"+#include "asio/buffered_read_stream.hpp"+#include "asio/buffered_write_stream.hpp"+#include "asio/buffered_stream_fwd.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Adds buffering to the read- and write-related operations of a stream.+/**+ * The buffered_stream class template can be used to add buffering to the+ * synchronous and asynchronous read and write operations of a stream.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Concepts:+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.+ */+template <typename Stream>+class buffered_stream+ : private noncopyable+{+public:+ /// The type of the next layer.+ typedef typename remove_reference<Stream>::type next_layer_type;++ /// The type of the lowest layer.+ typedef typename next_layer_type::lowest_layer_type lowest_layer_type;++ /// The type of the executor associated with the object.+ typedef typename lowest_layer_type::executor_type executor_type;++ /// Construct, passing the specified argument to initialise the next layer.+ template <typename Arg>+ explicit buffered_stream(Arg& a)+ : inner_stream_impl_(a),+ stream_impl_(inner_stream_impl_)+ {+ }++ /// Construct, passing the specified argument to initialise the next layer.+ template <typename Arg>+ explicit buffered_stream(Arg& a, std::size_t read_buffer_size,+ std::size_t write_buffer_size)+ : inner_stream_impl_(a, write_buffer_size),+ stream_impl_(inner_stream_impl_, read_buffer_size)+ {+ }++ /// Get a reference to the next layer.+ next_layer_type& next_layer()+ {+ return stream_impl_.next_layer().next_layer();+ }++ /// Get a reference to the lowest layer.+ lowest_layer_type& lowest_layer()+ {+ return stream_impl_.lowest_layer();+ }++ /// Get a const reference to the lowest layer.+ const lowest_layer_type& lowest_layer() const+ {+ return stream_impl_.lowest_layer();+ }++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_NOEXCEPT+ {+ return stream_impl_.lowest_layer().get_executor();+ }++ /// Close the stream.+ void close()+ {+ stream_impl_.close();+ }++ /// Close the stream.+ ASIO_SYNC_OP_VOID close(asio::error_code& ec)+ {+ stream_impl_.close(ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Flush all data from the buffer to the next layer. Returns the number of+ /// bytes written to the next layer on the last write operation. Throws an+ /// exception on failure.+ std::size_t flush()+ {+ return stream_impl_.next_layer().flush();+ }++ /// Flush all data from the buffer to the next layer. Returns the number of+ /// bytes written to the next layer on the last write operation, or 0 if an+ /// error occurred.+ std::size_t flush(asio::error_code& ec)+ {+ return stream_impl_.next_layer().flush(ec);+ }++ /// Start an asynchronous flush.+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_flush(+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return stream_impl_.next_layer().async_flush(+ ASIO_MOVE_CAST(WriteHandler)(handler));+ }++ /// Write the given data to the stream. Returns the number of bytes written.+ /// Throws an exception on failure.+ template <typename ConstBufferSequence>+ std::size_t write_some(const ConstBufferSequence& buffers)+ {+ return stream_impl_.write_some(buffers);+ }++ /// Write the given data to the stream. Returns the number of bytes written,+ /// or 0 if an error occurred.+ template <typename ConstBufferSequence>+ std::size_t write_some(const ConstBufferSequence& buffers,+ asio::error_code& ec)+ {+ return stream_impl_.write_some(buffers, ec);+ }++ /// Start an asynchronous write. The data being written must be valid for the+ /// lifetime of the asynchronous operation.+ template <typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_write_some(const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return stream_impl_.async_write_some(buffers,+ ASIO_MOVE_CAST(WriteHandler)(handler));+ }++ /// Fill the buffer with some data. Returns the number of bytes placed in the+ /// buffer as a result of the operation. Throws an exception on failure.+ std::size_t fill()+ {+ return stream_impl_.fill();+ }++ /// Fill the buffer with some data. Returns the number of bytes placed in the+ /// buffer as a result of the operation, or 0 if an error occurred.+ std::size_t fill(asio::error_code& ec)+ {+ return stream_impl_.fill(ec);+ }++ /// Start an asynchronous fill.+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_fill(+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return stream_impl_.async_fill(ASIO_MOVE_CAST(ReadHandler)(handler));+ }++ /// Read some data from the stream. Returns the number of bytes read. Throws+ /// an exception on failure.+ template <typename MutableBufferSequence>+ std::size_t read_some(const MutableBufferSequence& buffers)+ {+ return stream_impl_.read_some(buffers);+ }++ /// Read some data from the stream. Returns the number of bytes read or 0 if+ /// an error occurred.+ template <typename MutableBufferSequence>+ std::size_t read_some(const MutableBufferSequence& buffers,+ asio::error_code& ec)+ {+ return stream_impl_.read_some(buffers, ec);+ }++ /// Start an asynchronous read. The buffer into which the data will be read+ /// must be valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_read_some(const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return stream_impl_.async_read_some(buffers,+ ASIO_MOVE_CAST(ReadHandler)(handler));+ }++ /// Peek at the incoming data on the stream. Returns the number of bytes read.+ /// Throws an exception on failure.+ template <typename MutableBufferSequence>+ std::size_t peek(const MutableBufferSequence& buffers)+ {+ return stream_impl_.peek(buffers);+ }++ /// Peek at the incoming data on the stream. Returns the number of bytes read,+ /// or 0 if an error occurred.+ template <typename MutableBufferSequence>+ std::size_t peek(const MutableBufferSequence& buffers,+ asio::error_code& ec)+ {+ return stream_impl_.peek(buffers, ec);+ }++ /// Determine the amount of data that may be read without blocking.+ std::size_t in_avail()+ {+ return stream_impl_.in_avail();+ }++ /// Determine the amount of data that may be read without blocking.+ std::size_t in_avail(asio::error_code& ec)+ {+ return stream_impl_.in_avail(ec);+ }++private:+ // The buffered write stream.+ typedef buffered_write_stream<Stream> write_stream_type;+ write_stream_type inner_stream_impl_;++ // The buffered read stream.+ typedef buffered_read_stream<write_stream_type&> read_stream_type;+ read_stream_type stream_impl_;+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BUFFERED_STREAM_HPP
+ link/modules/asio-standalone/asio/include/asio/buffered_stream_fwd.hpp view
@@ -0,0 +1,25 @@+//+// buffered_stream_fwd.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BUFFERED_STREAM_FWD_HPP+#define ASIO_BUFFERED_STREAM_FWD_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++namespace asio {++template <typename Stream>+class buffered_stream;++} // namespace asio++#endif // ASIO_BUFFERED_STREAM_FWD_HPP
+ link/modules/asio-standalone/asio/include/asio/buffered_write_stream.hpp view
@@ -0,0 +1,245 @@+//+// buffered_write_stream.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BUFFERED_WRITE_STREAM_HPP+#define ASIO_BUFFERED_WRITE_STREAM_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/buffered_write_stream_fwd.hpp"+#include "asio/buffer.hpp"+#include "asio/completion_condition.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffered_stream_storage.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/error.hpp"+#include "asio/write.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Adds buffering to the write-related operations of a stream.+/**+ * The buffered_write_stream class template can be used to add buffering to the+ * synchronous and asynchronous write operations of a stream.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Concepts:+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.+ */+template <typename Stream>+class buffered_write_stream+ : private noncopyable+{+public:+ /// The type of the next layer.+ typedef typename remove_reference<Stream>::type next_layer_type;++ /// The type of the lowest layer.+ typedef typename next_layer_type::lowest_layer_type lowest_layer_type;++ /// The type of the executor associated with the object.+ typedef typename lowest_layer_type::executor_type executor_type;++#if defined(GENERATING_DOCUMENTATION)+ /// The default buffer size.+ static const std::size_t default_buffer_size = implementation_defined;+#else+ ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);+#endif++ /// Construct, passing the specified argument to initialise the next layer.+ template <typename Arg>+ explicit buffered_write_stream(Arg& a)+ : next_layer_(a),+ storage_(default_buffer_size)+ {+ }++ /// Construct, passing the specified argument to initialise the next layer.+ template <typename Arg>+ buffered_write_stream(Arg& a, std::size_t buffer_size)+ : next_layer_(a),+ storage_(buffer_size)+ {+ }++ /// Get a reference to the next layer.+ next_layer_type& next_layer()+ {+ return next_layer_;+ }++ /// Get a reference to the lowest layer.+ lowest_layer_type& lowest_layer()+ {+ return next_layer_.lowest_layer();+ }++ /// Get a const reference to the lowest layer.+ const lowest_layer_type& lowest_layer() const+ {+ return next_layer_.lowest_layer();+ }++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_NOEXCEPT+ {+ return next_layer_.lowest_layer().get_executor();+ }++ /// Close the stream.+ void close()+ {+ next_layer_.close();+ }++ /// Close the stream.+ ASIO_SYNC_OP_VOID close(asio::error_code& ec)+ {+ next_layer_.close(ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Flush all data from the buffer to the next layer. Returns the number of+ /// bytes written to the next layer on the last write operation. Throws an+ /// exception on failure.+ std::size_t flush();++ /// Flush all data from the buffer to the next layer. Returns the number of+ /// bytes written to the next layer on the last write operation, or 0 if an+ /// error occurred.+ std::size_t flush(asio::error_code& ec);++ /// Start an asynchronous flush.+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_flush(+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));++ /// Write the given data to the stream. Returns the number of bytes written.+ /// Throws an exception on failure.+ template <typename ConstBufferSequence>+ std::size_t write_some(const ConstBufferSequence& buffers);++ /// Write the given data to the stream. Returns the number of bytes written,+ /// or 0 if an error occurred and the error handler did not throw.+ template <typename ConstBufferSequence>+ std::size_t write_some(const ConstBufferSequence& buffers,+ asio::error_code& ec);++ /// Start an asynchronous write. The data being written must be valid for the+ /// lifetime of the asynchronous operation.+ template <typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_write_some(const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));++ /// Read some data from the stream. Returns the number of bytes read. Throws+ /// an exception on failure.+ template <typename MutableBufferSequence>+ std::size_t read_some(const MutableBufferSequence& buffers)+ {+ return next_layer_.read_some(buffers);+ }++ /// Read some data from the stream. Returns the number of bytes read or 0 if+ /// an error occurred.+ template <typename MutableBufferSequence>+ std::size_t read_some(const MutableBufferSequence& buffers,+ asio::error_code& ec)+ {+ return next_layer_.read_some(buffers, ec);+ }++ /// Start an asynchronous read. The buffer into which the data will be read+ /// must be valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_read_some(const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return next_layer_.async_read_some(buffers,+ ASIO_MOVE_CAST(ReadHandler)(handler));+ }++ /// Peek at the incoming data on the stream. Returns the number of bytes read.+ /// Throws an exception on failure.+ template <typename MutableBufferSequence>+ std::size_t peek(const MutableBufferSequence& buffers)+ {+ return next_layer_.peek(buffers);+ }++ /// Peek at the incoming data on the stream. Returns the number of bytes read,+ /// or 0 if an error occurred.+ template <typename MutableBufferSequence>+ std::size_t peek(const MutableBufferSequence& buffers,+ asio::error_code& ec)+ {+ return next_layer_.peek(buffers, ec);+ }++ /// Determine the amount of data that may be read without blocking.+ std::size_t in_avail()+ {+ return next_layer_.in_avail();+ }++ /// Determine the amount of data that may be read without blocking.+ std::size_t in_avail(asio::error_code& ec)+ {+ return next_layer_.in_avail(ec);+ }++private:+ /// Copy data into the internal buffer from the specified source buffer.+ /// Returns the number of bytes copied.+ template <typename ConstBufferSequence>+ std::size_t copy(const ConstBufferSequence& buffers);++ /// The next layer.+ Stream next_layer_;++ // The data in the buffer.+ detail::buffered_stream_storage storage_;+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/buffered_write_stream.hpp"++#endif // ASIO_BUFFERED_WRITE_STREAM_HPP
+ link/modules/asio-standalone/asio/include/asio/buffered_write_stream_fwd.hpp view
@@ -0,0 +1,25 @@+//+// buffered_write_stream_fwd.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BUFFERED_WRITE_STREAM_FWD_HPP+#define ASIO_BUFFERED_WRITE_STREAM_FWD_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++namespace asio {++template <typename Stream>+class buffered_write_stream;++} // namespace asio++#endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
+ link/modules/asio-standalone/asio/include/asio/buffers_iterator.hpp view
@@ -0,0 +1,521 @@+//+// buffers_iterator.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BUFFERS_ITERATOR_HPP+#define ASIO_BUFFERS_ITERATOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include <iterator>+#include "asio/buffer.hpp"+#include "asio/detail/assert.hpp"+#include "asio/detail/type_traits.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++namespace detail+{+ template <bool IsMutable>+ struct buffers_iterator_types_helper;++ template <>+ struct buffers_iterator_types_helper<false>+ {+ typedef const_buffer buffer_type;+ template <typename ByteType>+ struct byte_type+ {+ typedef typename add_const<ByteType>::type type;+ };+ };++ template <>+ struct buffers_iterator_types_helper<true>+ {+ typedef mutable_buffer buffer_type;+ template <typename ByteType>+ struct byte_type+ {+ typedef ByteType type;+ };+ };++ template <typename BufferSequence, typename ByteType>+ struct buffers_iterator_types+ {+ enum+ {+ is_mutable = is_convertible<+ typename BufferSequence::value_type,+ mutable_buffer>::value+ };+ typedef buffers_iterator_types_helper<is_mutable> helper;+ typedef typename helper::buffer_type buffer_type;+ typedef typename helper::template byte_type<ByteType>::type byte_type;+ typedef typename BufferSequence::const_iterator const_iterator;+ };++ template <typename ByteType>+ struct buffers_iterator_types<mutable_buffer, ByteType>+ {+ typedef mutable_buffer buffer_type;+ typedef ByteType byte_type;+ typedef const mutable_buffer* const_iterator;+ };++ template <typename ByteType>+ struct buffers_iterator_types<const_buffer, ByteType>+ {+ typedef const_buffer buffer_type;+ typedef typename add_const<ByteType>::type byte_type;+ typedef const const_buffer* const_iterator;+ };++#if !defined(ASIO_NO_DEPRECATED)++ template <typename ByteType>+ struct buffers_iterator_types<mutable_buffers_1, ByteType>+ {+ typedef mutable_buffer buffer_type;+ typedef ByteType byte_type;+ typedef const mutable_buffer* const_iterator;+ };++ template <typename ByteType>+ struct buffers_iterator_types<const_buffers_1, ByteType>+ {+ typedef const_buffer buffer_type;+ typedef typename add_const<ByteType>::type byte_type;+ typedef const const_buffer* const_iterator;+ };++#endif // !defined(ASIO_NO_DEPRECATED)+}++/// A random access iterator over the bytes in a buffer sequence.+template <typename BufferSequence, typename ByteType = char>+class buffers_iterator+{+private:+ typedef typename detail::buffers_iterator_types<+ BufferSequence, ByteType>::buffer_type buffer_type;++ typedef typename detail::buffers_iterator_types<BufferSequence,+ ByteType>::const_iterator buffer_sequence_iterator_type;++public:+ /// The type used for the distance between two iterators.+ typedef std::ptrdiff_t difference_type;++ /// The type of the value pointed to by the iterator.+ typedef ByteType value_type;++#if defined(GENERATING_DOCUMENTATION)+ /// The type of the result of applying operator->() to the iterator.+ /**+ * If the buffer sequence stores buffer objects that are convertible to+ * mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a+ * pointer to a const ByteType.+ */+ typedef const_or_non_const_ByteType* pointer;+#else // defined(GENERATING_DOCUMENTATION)+ typedef typename detail::buffers_iterator_types<+ BufferSequence, ByteType>::byte_type* pointer;+#endif // defined(GENERATING_DOCUMENTATION)++#if defined(GENERATING_DOCUMENTATION)+ /// The type of the result of applying operator*() to the iterator.+ /**+ * If the buffer sequence stores buffer objects that are convertible to+ * mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a+ * reference to a const ByteType.+ */+ typedef const_or_non_const_ByteType& reference;+#else // defined(GENERATING_DOCUMENTATION)+ typedef typename detail::buffers_iterator_types<+ BufferSequence, ByteType>::byte_type& reference;+#endif // defined(GENERATING_DOCUMENTATION)++ /// The iterator category.+ typedef std::random_access_iterator_tag iterator_category;++ /// Default constructor. Creates an iterator in an undefined state.+ buffers_iterator()+ : current_buffer_(),+ current_buffer_position_(0),+ begin_(),+ current_(),+ end_(),+ position_(0)+ {+ }++ /// Construct an iterator representing the beginning of the buffers' data.+ static buffers_iterator begin(const BufferSequence& buffers)+#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)+ __attribute__ ((__noinline__))+#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)+ {+ buffers_iterator new_iter;+ new_iter.begin_ = asio::buffer_sequence_begin(buffers);+ new_iter.current_ = asio::buffer_sequence_begin(buffers);+ new_iter.end_ = asio::buffer_sequence_end(buffers);+ while (new_iter.current_ != new_iter.end_)+ {+ new_iter.current_buffer_ = *new_iter.current_;+ if (new_iter.current_buffer_.size() > 0)+ break;+ ++new_iter.current_;+ }+ return new_iter;+ }++ /// Construct an iterator representing the end of the buffers' data.+ static buffers_iterator end(const BufferSequence& buffers)+#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)+ __attribute__ ((__noinline__))+#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)+ {+ buffers_iterator new_iter;+ new_iter.begin_ = asio::buffer_sequence_begin(buffers);+ new_iter.current_ = asio::buffer_sequence_begin(buffers);+ new_iter.end_ = asio::buffer_sequence_end(buffers);+ while (new_iter.current_ != new_iter.end_)+ {+ buffer_type buffer = *new_iter.current_;+ new_iter.position_ += buffer.size();+ ++new_iter.current_;+ }+ return new_iter;+ }++ /// Dereference an iterator.+ reference operator*() const+ {+ return dereference();+ }++ /// Dereference an iterator.+ pointer operator->() const+ {+ return &dereference();+ }++ /// Access an individual element.+ reference operator[](std::ptrdiff_t difference) const+ {+ buffers_iterator tmp(*this);+ tmp.advance(difference);+ return *tmp;+ }++ /// Increment operator (prefix).+ buffers_iterator& operator++()+ {+ increment();+ return *this;+ }++ /// Increment operator (postfix).+ buffers_iterator operator++(int)+ {+ buffers_iterator tmp(*this);+ ++*this;+ return tmp;+ }++ /// Decrement operator (prefix).+ buffers_iterator& operator--()+ {+ decrement();+ return *this;+ }++ /// Decrement operator (postfix).+ buffers_iterator operator--(int)+ {+ buffers_iterator tmp(*this);+ --*this;+ return tmp;+ }++ /// Addition operator.+ buffers_iterator& operator+=(std::ptrdiff_t difference)+ {+ advance(difference);+ return *this;+ }++ /// Subtraction operator.+ buffers_iterator& operator-=(std::ptrdiff_t difference)+ {+ advance(-difference);+ return *this;+ }++ /// Addition operator.+ friend buffers_iterator operator+(const buffers_iterator& iter,+ std::ptrdiff_t difference)+ {+ buffers_iterator tmp(iter);+ tmp.advance(difference);+ return tmp;+ }++ /// Addition operator.+ friend buffers_iterator operator+(std::ptrdiff_t difference,+ const buffers_iterator& iter)+ {+ buffers_iterator tmp(iter);+ tmp.advance(difference);+ return tmp;+ }++ /// Subtraction operator.+ friend buffers_iterator operator-(const buffers_iterator& iter,+ std::ptrdiff_t difference)+ {+ buffers_iterator tmp(iter);+ tmp.advance(-difference);+ return tmp;+ }++ /// Subtraction operator.+ friend std::ptrdiff_t operator-(const buffers_iterator& a,+ const buffers_iterator& b)+ {+ return b.distance_to(a);+ }++ /// Test two iterators for equality.+ friend bool operator==(const buffers_iterator& a, const buffers_iterator& b)+ {+ return a.equal(b);+ }++ /// Test two iterators for inequality.+ friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b)+ {+ return !a.equal(b);+ }++ /// Compare two iterators.+ friend bool operator<(const buffers_iterator& a, const buffers_iterator& b)+ {+ return a.distance_to(b) > 0;+ }++ /// Compare two iterators.+ friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b)+ {+ return !(b < a);+ }++ /// Compare two iterators.+ friend bool operator>(const buffers_iterator& a, const buffers_iterator& b)+ {+ return b < a;+ }++ /// Compare two iterators.+ friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b)+ {+ return !(a < b);+ }++private:+ // Dereference the iterator.+ reference dereference() const+ {+ return static_cast<pointer>(+ current_buffer_.data())[current_buffer_position_];+ }++ // Compare two iterators for equality.+ bool equal(const buffers_iterator& other) const+ {+ return position_ == other.position_;+ }++ // Increment the iterator.+ void increment()+ {+ ASIO_ASSERT(current_ != end_ && "iterator out of bounds");+ ++position_;++ // Check if the increment can be satisfied by the current buffer.+ ++current_buffer_position_;+ if (current_buffer_position_ != current_buffer_.size())+ return;++ // Find the next non-empty buffer.+ ++current_;+ current_buffer_position_ = 0;+ while (current_ != end_)+ {+ current_buffer_ = *current_;+ if (current_buffer_.size() > 0)+ return;+ ++current_;+ }+ }++ // Decrement the iterator.+ void decrement()+ {+ ASIO_ASSERT(position_ > 0 && "iterator out of bounds");+ --position_;++ // Check if the decrement can be satisfied by the current buffer.+ if (current_buffer_position_ != 0)+ {+ --current_buffer_position_;+ return;+ }++ // Find the previous non-empty buffer.+ buffer_sequence_iterator_type iter = current_;+ while (iter != begin_)+ {+ --iter;+ buffer_type buffer = *iter;+ std::size_t buffer_size = buffer.size();+ if (buffer_size > 0)+ {+ current_ = iter;+ current_buffer_ = buffer;+ current_buffer_position_ = buffer_size - 1;+ return;+ }+ }+ }++ // Advance the iterator by the specified distance.+ void advance(std::ptrdiff_t n)+ {+ if (n > 0)+ {+ ASIO_ASSERT(current_ != end_ && "iterator out of bounds");+ for (;;)+ {+ std::ptrdiff_t current_buffer_balance+ = current_buffer_.size() - current_buffer_position_;++ // Check if the advance can be satisfied by the current buffer.+ if (current_buffer_balance > n)+ {+ position_ += n;+ current_buffer_position_ += n;+ return;+ }++ // Update position.+ n -= current_buffer_balance;+ position_ += current_buffer_balance;++ // Move to next buffer. If it is empty then it will be skipped on the+ // next iteration of this loop.+ if (++current_ == end_)+ {+ ASIO_ASSERT(n == 0 && "iterator out of bounds");+ current_buffer_ = buffer_type();+ current_buffer_position_ = 0;+ return;+ }+ current_buffer_ = *current_;+ current_buffer_position_ = 0;+ }+ }+ else if (n < 0)+ {+ std::size_t abs_n = -n;+ ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds");+ for (;;)+ {+ // Check if the advance can be satisfied by the current buffer.+ if (current_buffer_position_ >= abs_n)+ {+ position_ -= abs_n;+ current_buffer_position_ -= abs_n;+ return;+ }++ // Update position.+ abs_n -= current_buffer_position_;+ position_ -= current_buffer_position_;++ // Check if we've reached the beginning of the buffers.+ if (current_ == begin_)+ {+ ASIO_ASSERT(abs_n == 0 && "iterator out of bounds");+ current_buffer_position_ = 0;+ return;+ }++ // Find the previous non-empty buffer.+ buffer_sequence_iterator_type iter = current_;+ while (iter != begin_)+ {+ --iter;+ buffer_type buffer = *iter;+ std::size_t buffer_size = buffer.size();+ if (buffer_size > 0)+ {+ current_ = iter;+ current_buffer_ = buffer;+ current_buffer_position_ = buffer_size;+ break;+ }+ }+ }+ }+ }++ // Determine the distance between two iterators.+ std::ptrdiff_t distance_to(const buffers_iterator& other) const+ {+ return other.position_ - position_;+ }++ buffer_type current_buffer_;+ std::size_t current_buffer_position_;+ buffer_sequence_iterator_type begin_;+ buffer_sequence_iterator_type current_;+ buffer_sequence_iterator_type end_;+ std::size_t position_;+};++/// Construct an iterator representing the beginning of the buffers' data.+template <typename BufferSequence>+inline buffers_iterator<BufferSequence> buffers_begin(+ const BufferSequence& buffers)+{+ return buffers_iterator<BufferSequence>::begin(buffers);+}++/// Construct an iterator representing the end of the buffers' data.+template <typename BufferSequence>+inline buffers_iterator<BufferSequence> buffers_end(+ const BufferSequence& buffers)+{+ return buffers_iterator<BufferSequence>::end(buffers);+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_BUFFERS_ITERATOR_HPP
+ link/modules/asio-standalone/asio/include/asio/co_spawn.hpp view
@@ -0,0 +1,471 @@+//+// co_spawn.hpp+// ~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 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 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+ */+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),+ typename enable_if<+ (is_executor<Executor>::value || execution::is_executor<Executor>::value)+ && is_convertible<Executor, AwaitableExecutor>::value+ >::type* = 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 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 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+ */+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),+ typename enable_if<+ (is_executor<Executor>::value || execution::is_executor<Executor>::value)+ && is_convertible<Executor, AwaitableExecutor>::value+ >::type* = 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 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 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+ */+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),+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ && is_convertible<typename ExecutionContext::executor_type,+ AwaitableExecutor>::value+ >::type* = 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 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 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+ */+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),+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ && is_convertible<typename ExecutionContext::executor_type,+ AwaitableExecutor>::value+ >::type* = 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 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 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+ */+template <typename Executor, typename F,+ ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<+ typename result_of<F()>::type>::type) CompletionToken+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,+ typename detail::awaitable_signature<typename result_of<F()>::type>::type)+co_spawn(const Executor& ex, F&& f,+ CompletionToken&& token+ ASIO_DEFAULT_COMPLETION_TOKEN(Executor),+ typename enable_if<+ is_executor<Executor>::value || execution::is_executor<Executor>::value+ >::type* = 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 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 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+ */+template <typename ExecutionContext, typename F,+ ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<+ typename result_of<F()>::type>::type) CompletionToken+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename ExecutionContext::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,+ typename detail::awaitable_signature<typename result_of<F()>::type>::type)+co_spawn(ExecutionContext& ctx, F&& f,+ CompletionToken&& token+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename ExecutionContext::executor_type),+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 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
+ link/modules/asio-standalone/asio/include/asio/completion_condition.hpp view
@@ -0,0 +1,218 @@+//+// completion_condition.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_COMPLETION_CONDITION_HPP+#define ASIO_COMPLETION_CONDITION_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>++#include "asio/detail/push_options.hpp"++namespace asio {++namespace detail {++// The default maximum number of bytes to transfer in a single operation.+enum default_max_transfer_size_t { default_max_transfer_size = 65536 };++// Adapt result of old-style completion conditions (which had a bool result+// where true indicated that the operation was complete).+inline std::size_t adapt_completion_condition_result(bool result)+{+ return result ? 0 : default_max_transfer_size;+}++// Adapt result of current completion conditions (which have a size_t result+// where 0 means the operation is complete, and otherwise the result is the+// maximum number of bytes to transfer on the next underlying operation).+inline std::size_t adapt_completion_condition_result(std::size_t result)+{+ return result;+}++class transfer_all_t+{+public:+ typedef std::size_t result_type;++ template <typename Error>+ std::size_t operator()(const Error& err, std::size_t)+ {+ return !!err ? 0 : default_max_transfer_size;+ }+};++class transfer_at_least_t+{+public:+ typedef std::size_t result_type;++ explicit transfer_at_least_t(std::size_t minimum)+ : minimum_(minimum)+ {+ }++ template <typename Error>+ std::size_t operator()(const Error& err, std::size_t bytes_transferred)+ {+ return (!!err || bytes_transferred >= minimum_)+ ? 0 : default_max_transfer_size;+ }++private:+ std::size_t minimum_;+};++class transfer_exactly_t+{+public:+ typedef std::size_t result_type;++ explicit transfer_exactly_t(std::size_t size)+ : size_(size)+ {+ }++ template <typename Error>+ std::size_t operator()(const Error& err, std::size_t bytes_transferred)+ {+ return (!!err || bytes_transferred >= size_) ? 0 :+ (size_ - bytes_transferred < default_max_transfer_size+ ? size_ - bytes_transferred : std::size_t(default_max_transfer_size));+ }++private:+ std::size_t size_;+};++} // namespace detail++/**+ * @defgroup completion_condition Completion Condition Function Objects+ *+ * Function objects used for determining when a read or write operation should+ * complete.+ */+/*@{*/++/// Return a completion condition function object that indicates that a read or+/// write operation should continue until all of the data has been transferred,+/// or until an error occurs.+/**+ * This function is used to create an object, of unspecified type, that meets+ * CompletionCondition requirements.+ *+ * @par Example+ * Reading until a buffer is full:+ * @code+ * boost::array<char, 128> buf;+ * asio::error_code ec;+ * std::size_t n = asio::read(+ * sock, asio::buffer(buf),+ * asio::transfer_all(), ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * else+ * {+ * // n == 128+ * }+ * @endcode+ */+#if defined(GENERATING_DOCUMENTATION)+unspecified transfer_all();+#else+inline detail::transfer_all_t transfer_all()+{+ return detail::transfer_all_t();+}+#endif++/// Return a completion condition function object that indicates that a read or+/// write operation should continue until a minimum number of bytes has been+/// transferred, or until an error occurs.+/**+ * This function is used to create an object, of unspecified type, that meets+ * CompletionCondition requirements.+ *+ * @par Example+ * Reading until a buffer is full or contains at least 64 bytes:+ * @code+ * boost::array<char, 128> buf;+ * asio::error_code ec;+ * std::size_t n = asio::read(+ * sock, asio::buffer(buf),+ * asio::transfer_at_least(64), ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * else+ * {+ * // n >= 64 && n <= 128+ * }+ * @endcode+ */+#if defined(GENERATING_DOCUMENTATION)+unspecified transfer_at_least(std::size_t minimum);+#else+inline detail::transfer_at_least_t transfer_at_least(std::size_t minimum)+{+ return detail::transfer_at_least_t(minimum);+}+#endif++/// Return a completion condition function object that indicates that a read or+/// write operation should continue until an exact number of bytes has been+/// transferred, or until an error occurs.+/**+ * This function is used to create an object, of unspecified type, that meets+ * CompletionCondition requirements.+ *+ * @par Example+ * Reading until a buffer is full or contains exactly 64 bytes:+ * @code+ * boost::array<char, 128> buf;+ * asio::error_code ec;+ * std::size_t n = asio::read(+ * sock, asio::buffer(buf),+ * asio::transfer_exactly(64), ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * else+ * {+ * // n == 64+ * }+ * @endcode+ */+#if defined(GENERATING_DOCUMENTATION)+unspecified transfer_exactly(std::size_t size);+#else+inline detail::transfer_exactly_t transfer_exactly(std::size_t size)+{+ return detail::transfer_exactly_t(size);+}+#endif++/*@}*/++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_COMPLETION_CONDITION_HPP
+ link/modules/asio-standalone/asio/include/asio/compose.hpp view
@@ -0,0 +1,136 @@+//+// compose.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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/async_result.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \+ || 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 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) ->+ * typename asio::async_result<+ * typename std::decay<CompletionToken>::type,+ * void(asio::error_code, std::size_t)>::return_type+ * {+ * 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>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature)+async_compose(ASIO_MOVE_ARG(Implementation) implementation,+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,+ ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors);++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)++template <typename CompletionToken, typename Signature, typename Implementation>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature)+async_compose(ASIO_MOVE_ARG(Implementation) implementation,+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token);++#define ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \+ template <typename CompletionToken, typename Signature, \+ typename Implementation, ASIO_VARIADIC_TPARAMS(n)> \+ ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) \+ async_compose(ASIO_MOVE_ARG(Implementation) implementation, \+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \+ ASIO_VARIADIC_MOVE_PARAMS(n));+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_COMPOSE_DEF)+#undef ASIO_PRIVATE_ASYNC_COMPOSE_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/compose.hpp"++#endif // ASIO_COMPOSE_HPP
+ link/modules/asio-standalone/asio/include/asio/connect.hpp view
@@ -0,0 +1,1076 @@+//+// connect.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HPP+#define ASIO_CONNECT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/async_result.hpp"+#include "asio/basic_socket.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++namespace detail+{+ char (&has_iterator_helper(...))[2];++ template <typename T>+ char has_iterator_helper(T*, typename T::iterator* = 0);++ template <typename T>+ struct has_iterator_typedef+ {+ enum { value = (sizeof((has_iterator_helper)((T*)(0))) == 1) };+ };+} // namespace detail++/// Type trait used to determine whether a type is an endpoint sequence that can+/// be used with with @c connect and @c async_connect.+template <typename T>+struct is_endpoint_sequence+{+#if defined(GENERATING_DOCUMENTATION)+ /// The value member is true if the type may be used as an endpoint sequence.+ static const bool value;+#else+ enum+ {+ value = detail::has_iterator_typedef<T>::value+ };+#endif+};++/**+ * @defgroup connect asio::connect+ *+ * @brief The @c connect function is a composed operation that establishes a+ * socket connection by trying each endpoint in a sequence.+ */+/*@{*/++/// Establishes a socket connection by trying each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param endpoints A sequence of endpoints.+ *+ * @returns The successfully connected endpoint.+ *+ * @throws asio::system_error Thrown on failure. If the sequence is+ * empty, the associated @c error_code is asio::error::not_found.+ * Otherwise, contains the error from the last connection attempt.+ *+ * @par Example+ * @code tcp::resolver r(my_context);+ * tcp::resolver::query q("host", "service");+ * tcp::socket s(my_context);+ * asio::connect(s, r.resolve(q)); @endcode+ */+template <typename Protocol, typename Executor, typename EndpointSequence>+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints,+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type* = 0);++/// Establishes a socket connection by trying each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param endpoints A sequence of endpoints.+ *+ * @param ec Set to indicate what error occurred, if any. If the sequence is+ * empty, set to asio::error::not_found. Otherwise, contains the error+ * from the last connection attempt.+ *+ * @returns On success, the successfully connected endpoint. Otherwise, a+ * default-constructed endpoint.+ *+ * @par Example+ * @code tcp::resolver r(my_context);+ * tcp::resolver::query q("host", "service");+ * tcp::socket s(my_context);+ * asio::error_code ec;+ * asio::connect(s, r.resolve(q), ec);+ * if (ec)+ * {+ * // An error occurred.+ * } @endcode+ */+template <typename Protocol, typename Executor, typename EndpointSequence>+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints, asio::error_code& ec,+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type* = 0);++#if !defined(ASIO_NO_DEPRECATED)+/// (Deprecated: Use range overload.) Establishes a socket connection by trying+/// each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start of a sequence of endpoints.+ *+ * @returns On success, an iterator denoting the successfully connected+ * endpoint. Otherwise, the end iterator.+ *+ * @throws asio::system_error Thrown on failure. If the sequence is+ * empty, the associated @c error_code is asio::error::not_found.+ * Otherwise, contains the error from the last connection attempt.+ *+ * @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 types such as @c asio::ip::tcp::resolver::iterator.+ */+template <typename Protocol, typename Executor, typename Iterator>+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);++/// (Deprecated: Use range overload.) Establishes a socket connection by trying+/// each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start of a sequence of endpoints.+ *+ * @param ec Set to indicate what error occurred, if any. If the sequence is+ * empty, set to asio::error::not_found. Otherwise, contains the error+ * from the last connection attempt.+ *+ * @returns On success, an iterator denoting the successfully connected+ * endpoint. Otherwise, the end iterator.+ *+ * @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 types such as @c asio::ip::tcp::resolver::iterator.+ */+template <typename Protocol, typename Executor, typename Iterator>+Iterator connect(basic_socket<Protocol, Executor>& s,+ Iterator begin, asio::error_code& ec,+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);+#endif // !defined(ASIO_NO_DEPRECATED)++/// Establishes a socket connection by trying each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start of a sequence of endpoints.+ *+ * @param end An iterator pointing to the end of a sequence of endpoints.+ *+ * @returns An iterator denoting the successfully connected endpoint.+ *+ * @throws asio::system_error Thrown on failure. If the sequence is+ * empty, the associated @c error_code is asio::error::not_found.+ * Otherwise, contains the error from the last connection attempt.+ *+ * @par Example+ * @code tcp::resolver r(my_context);+ * tcp::resolver::query q("host", "service");+ * tcp::resolver::results_type e = r.resolve(q);+ * tcp::socket s(my_context);+ * asio::connect(s, e.begin(), e.end()); @endcode+ */+template <typename Protocol, typename Executor, typename Iterator>+Iterator connect(basic_socket<Protocol, Executor>& s,+ Iterator begin, Iterator end);++/// Establishes a socket connection by trying each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start of a sequence of endpoints.+ *+ * @param end An iterator pointing to the end of a sequence of endpoints.+ *+ * @param ec Set to indicate what error occurred, if any. If the sequence is+ * empty, set to asio::error::not_found. Otherwise, contains the error+ * from the last connection attempt.+ *+ * @returns On success, an iterator denoting the successfully connected+ * endpoint. Otherwise, the end iterator.+ *+ * @par Example+ * @code tcp::resolver r(my_context);+ * tcp::resolver::query q("host", "service");+ * tcp::resolver::results_type e = r.resolve(q);+ * tcp::socket s(my_context);+ * asio::error_code ec;+ * asio::connect(s, e.begin(), e.end(), ec);+ * if (ec)+ * {+ * // An error occurred.+ * } @endcode+ */+template <typename Protocol, typename Executor, typename Iterator>+Iterator connect(basic_socket<Protocol, Executor>& s,+ Iterator begin, Iterator end, asio::error_code& ec);++/// Establishes a socket connection by trying each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param endpoints A sequence of endpoints.+ *+ * @param connect_condition A function object that is called prior to each+ * connection attempt. The signature of the function object must be:+ * @code bool connect_condition(+ * const asio::error_code& ec,+ * const typename Protocol::endpoint& next); @endcode+ * The @c ec parameter contains the result from the most recent connect+ * operation. Before the first connection attempt, @c ec is always set to+ * indicate success. The @c next parameter is the next endpoint to be tried.+ * The function object should return true if the next endpoint should be tried,+ * and false if it should be skipped.+ *+ * @returns The successfully connected endpoint.+ *+ * @throws asio::system_error Thrown on failure. If the sequence is+ * empty, the associated @c error_code is asio::error::not_found.+ * Otherwise, contains the error from the last connection attempt.+ *+ * @par Example+ * The following connect condition function object can be used to output+ * information about the individual connection attempts:+ * @code struct my_connect_condition+ * {+ * bool operator()(+ * const asio::error_code& ec,+ * const::tcp::endpoint& next)+ * {+ * if (ec) std::cout << "Error: " << ec.message() << std::endl;+ * std::cout << "Trying: " << next << std::endl;+ * return true;+ * }+ * }; @endcode+ * It would be used with the asio::connect function as follows:+ * @code tcp::resolver r(my_context);+ * tcp::resolver::query q("host", "service");+ * tcp::socket s(my_context);+ * tcp::endpoint e = asio::connect(s,+ * r.resolve(q), my_connect_condition());+ * std::cout << "Connected to: " << e << std::endl; @endcode+ */+template <typename Protocol, typename Executor,+ typename EndpointSequence, typename ConnectCondition>+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints, ConnectCondition connect_condition,+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type* = 0);++/// Establishes a socket connection by trying each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param endpoints A sequence of endpoints.+ *+ * @param connect_condition A function object that is called prior to each+ * connection attempt. The signature of the function object must be:+ * @code bool connect_condition(+ * const asio::error_code& ec,+ * const typename Protocol::endpoint& next); @endcode+ * The @c ec parameter contains the result from the most recent connect+ * operation. Before the first connection attempt, @c ec is always set to+ * indicate success. The @c next parameter is the next endpoint to be tried.+ * The function object should return true if the next endpoint should be tried,+ * and false if it should be skipped.+ *+ * @param ec Set to indicate what error occurred, if any. If the sequence is+ * empty, set to asio::error::not_found. Otherwise, contains the error+ * from the last connection attempt.+ *+ * @returns On success, the successfully connected endpoint. Otherwise, a+ * default-constructed endpoint.+ *+ * @par Example+ * The following connect condition function object can be used to output+ * information about the individual connection attempts:+ * @code struct my_connect_condition+ * {+ * bool operator()(+ * const asio::error_code& ec,+ * const::tcp::endpoint& next)+ * {+ * if (ec) std::cout << "Error: " << ec.message() << std::endl;+ * std::cout << "Trying: " << next << std::endl;+ * return true;+ * }+ * }; @endcode+ * It would be used with the asio::connect function as follows:+ * @code tcp::resolver r(my_context);+ * tcp::resolver::query q("host", "service");+ * tcp::socket s(my_context);+ * asio::error_code ec;+ * tcp::endpoint e = asio::connect(s,+ * r.resolve(q), my_connect_condition(), ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * else+ * {+ * std::cout << "Connected to: " << e << std::endl;+ * } @endcode+ */+template <typename Protocol, typename Executor,+ typename EndpointSequence, typename ConnectCondition>+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints, ConnectCondition connect_condition,+ asio::error_code& ec,+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type* = 0);++#if !defined(ASIO_NO_DEPRECATED)+/// (Deprecated: Use range overload.) Establishes a socket connection by trying+/// each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start of a sequence of endpoints.+ *+ * @param connect_condition A function object that is called prior to each+ * connection attempt. The signature of the function object must be:+ * @code bool connect_condition(+ * const asio::error_code& ec,+ * const typename Protocol::endpoint& next); @endcode+ * The @c ec parameter contains the result from the most recent connect+ * operation. Before the first connection attempt, @c ec is always set to+ * indicate success. The @c next parameter is the next endpoint to be tried.+ * The function object should return true if the next endpoint should be tried,+ * and false if it should be skipped.+ *+ * @returns On success, an iterator denoting the successfully connected+ * endpoint. Otherwise, the end iterator.+ *+ * @throws asio::system_error Thrown on failure. If the sequence is+ * empty, the associated @c error_code is asio::error::not_found.+ * Otherwise, contains the error from the last connection attempt.+ *+ * @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 types such as @c asio::ip::tcp::resolver::iterator.+ */+template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition>+Iterator connect(basic_socket<Protocol, Executor>& s,+ Iterator begin, ConnectCondition connect_condition,+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);++/// (Deprecated: Use range overload.) Establishes a socket connection by trying+/// each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start of a sequence of endpoints.+ *+ * @param connect_condition A function object that is called prior to each+ * connection attempt. The signature of the function object must be:+ * @code bool connect_condition(+ * const asio::error_code& ec,+ * const typename Protocol::endpoint& next); @endcode+ * The @c ec parameter contains the result from the most recent connect+ * operation. Before the first connection attempt, @c ec is always set to+ * indicate success. The @c next parameter is the next endpoint to be tried.+ * The function object should return true if the next endpoint should be tried,+ * and false if it should be skipped.+ *+ * @param ec Set to indicate what error occurred, if any. If the sequence is+ * empty, set to asio::error::not_found. Otherwise, contains the error+ * from the last connection attempt.+ *+ * @returns On success, an iterator denoting the successfully connected+ * endpoint. Otherwise, the end iterator.+ *+ * @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 types such as @c asio::ip::tcp::resolver::iterator.+ */+template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition>+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ ConnectCondition connect_condition, asio::error_code& ec,+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);+#endif // !defined(ASIO_NO_DEPRECATED)++/// Establishes a socket connection by trying each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start of a sequence of endpoints.+ *+ * @param end An iterator pointing to the end of a sequence of endpoints.+ *+ * @param connect_condition A function object that is called prior to each+ * connection attempt. The signature of the function object must be:+ * @code bool connect_condition(+ * const asio::error_code& ec,+ * const typename Protocol::endpoint& next); @endcode+ * The @c ec parameter contains the result from the most recent connect+ * operation. Before the first connection attempt, @c ec is always set to+ * indicate success. The @c next parameter is the next endpoint to be tried.+ * The function object should return true if the next endpoint should be tried,+ * and false if it should be skipped.+ *+ * @returns An iterator denoting the successfully connected endpoint.+ *+ * @throws asio::system_error Thrown on failure. If the sequence is+ * empty, the associated @c error_code is asio::error::not_found.+ * Otherwise, contains the error from the last connection attempt.+ *+ * @par Example+ * The following connect condition function object can be used to output+ * information about the individual connection attempts:+ * @code struct my_connect_condition+ * {+ * bool operator()(+ * const asio::error_code& ec,+ * const::tcp::endpoint& next)+ * {+ * if (ec) std::cout << "Error: " << ec.message() << std::endl;+ * std::cout << "Trying: " << next << std::endl;+ * return true;+ * }+ * }; @endcode+ * It would be used with the asio::connect function as follows:+ * @code tcp::resolver r(my_context);+ * tcp::resolver::query q("host", "service");+ * tcp::resolver::results_type e = r.resolve(q);+ * tcp::socket s(my_context);+ * tcp::resolver::results_type::iterator i = asio::connect(+ * s, e.begin(), e.end(), my_connect_condition());+ * std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode+ */+template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition>+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ Iterator end, ConnectCondition connect_condition);++/// Establishes a socket connection by trying each endpoint in a sequence.+/**+ * 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 connect member+ * function, once for each endpoint in the sequence, until a connection is+ * successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start of a sequence of endpoints.+ *+ * @param end An iterator pointing to the end of a sequence of endpoints.+ *+ * @param connect_condition A function object that is called prior to each+ * connection attempt. The signature of the function object must be:+ * @code bool connect_condition(+ * const asio::error_code& ec,+ * const typename Protocol::endpoint& next); @endcode+ * The @c ec parameter contains the result from the most recent connect+ * operation. Before the first connection attempt, @c ec is always set to+ * indicate success. The @c next parameter is the next endpoint to be tried.+ * The function object should return true if the next endpoint should be tried,+ * and false if it should be skipped.+ *+ * @param ec Set to indicate what error occurred, if any. If the sequence is+ * empty, set to asio::error::not_found. Otherwise, contains the error+ * from the last connection attempt.+ *+ * @returns On success, an iterator denoting the successfully connected+ * endpoint. Otherwise, the end iterator.+ *+ * @par Example+ * The following connect condition function object can be used to output+ * information about the individual connection attempts:+ * @code struct my_connect_condition+ * {+ * bool operator()(+ * const asio::error_code& ec,+ * const::tcp::endpoint& next)+ * {+ * if (ec) std::cout << "Error: " << ec.message() << std::endl;+ * std::cout << "Trying: " << next << std::endl;+ * return true;+ * }+ * }; @endcode+ * It would be used with the asio::connect function as follows:+ * @code tcp::resolver r(my_context);+ * tcp::resolver::query q("host", "service");+ * tcp::resolver::results_type e = r.resolve(q);+ * tcp::socket s(my_context);+ * asio::error_code ec;+ * tcp::resolver::results_type::iterator i = asio::connect(+ * s, e.begin(), e.end(), my_connect_condition());+ * if (ec)+ * {+ * // An error occurred.+ * }+ * else+ * {+ * std::cout << "Connected to: " << i->endpoint() << std::endl;+ * } @endcode+ */+template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition>+Iterator connect(basic_socket<Protocol, Executor>& s,+ Iterator begin, Iterator end, ConnectCondition connect_condition,+ asio::error_code& ec);++/*@}*/++/**+ * @defgroup async_connect asio::async_connect+ *+ * @brief The @c async_connect function is a composed asynchronous operation+ * that establishes a socket connection by trying each endpoint in a sequence.+ */+/*@{*/++/// Asynchronously establishes a socket connection by trying each endpoint in a+/// sequence.+/**+ * 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+ * member function, once for each endpoint in the sequence, until a connection+ * is successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param endpoints A sequence of endpoints.+ *+ * @param handler The handler to be called when the connect operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * // Result of operation. if the sequence is empty, set to+ * // asio::error::not_found. Otherwise, contains the+ * // error from the last connection attempt.+ * const asio::error_code& error,+ *+ * // On success, the successfully connected endpoint.+ * // Otherwise, a default-constructed endpoint.+ * const typename Protocol::endpoint& endpoint+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code tcp::resolver r(my_context);+ * tcp::resolver::query q("host", "service");+ * tcp::socket s(my_context);+ *+ * // ...+ *+ * r.async_resolve(q, resolve_handler);+ *+ * // ...+ *+ * void resolve_handler(+ * const asio::error_code& ec,+ * tcp::resolver::results_type results)+ * {+ * if (!ec)+ * {+ * asio::async_connect(s, results, connect_handler);+ * }+ * }+ *+ * // ...+ *+ * void connect_handler(+ * const asio::error_code& ec,+ * const tcp::endpoint& endpoint)+ * {+ * // ...+ * } @endcode+ */+template <typename Protocol, typename Executor, typename EndpointSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ typename Protocol::endpoint)) RangeConnectHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>+ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,+ void (asio::error_code, typename Protocol::endpoint))+async_connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints,+ ASIO_MOVE_ARG(RangeConnectHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(Executor),+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type* = 0);++#if !defined(ASIO_NO_DEPRECATED)+/// (Deprecated: Use range overload.) Asynchronously establishes a socket+/// connection by trying each endpoint in a sequence.+/**+ * 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+ * member function, once for each endpoint in the sequence, until a connection+ * is successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start of a sequence of endpoints.+ *+ * @param handler The handler to be called when the connect operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * // Result of operation. if the sequence is empty, set to+ * // asio::error::not_found. Otherwise, contains the+ * // error from the last connection attempt.+ * const asio::error_code& error,+ *+ * // On success, an iterator denoting the successfully+ * // connected endpoint. Otherwise, the end iterator.+ * Iterator iterator+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @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 types such as @c asio::ip::tcp::resolver::iterator.+ */+template <typename Protocol, typename Executor, typename Iterator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ Iterator)) IteratorConnectHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>+ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,+ void (asio::error_code, Iterator))+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ ASIO_MOVE_ARG(IteratorConnectHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(Executor),+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);+#endif // !defined(ASIO_NO_DEPRECATED)++/// Asynchronously establishes a socket connection by trying each endpoint in a+/// sequence.+/**+ * 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+ * member function, once for each endpoint in the sequence, until a connection+ * is successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start 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+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * // Result of operation. if the sequence is empty, set to+ * // asio::error::not_found. Otherwise, contains the+ * // error from the last connection attempt.+ * const asio::error_code& error,+ *+ * // On success, an iterator denoting the successfully+ * // connected endpoint. Otherwise, the end iterator.+ * Iterator iterator+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code std::vector<tcp::endpoint> endpoints = ...;+ * tcp::socket s(my_context);+ * asio::async_connect(s,+ * endpoints.begin(), endpoints.end(),+ * connect_handler);+ *+ * // ...+ *+ * void connect_handler(+ * const asio::error_code& ec,+ * std::vector<tcp::endpoint>::iterator i)+ * {+ * // ...+ * } @endcode+ */+template <typename Protocol, typename Executor, typename Iterator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ Iterator)) IteratorConnectHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>+ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,+ void (asio::error_code, Iterator))+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end,+ ASIO_MOVE_ARG(IteratorConnectHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(Executor));++/// Asynchronously establishes a socket connection by trying each endpoint in a+/// sequence.+/**+ * 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+ * member function, once for each endpoint in the sequence, until a connection+ * is successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param endpoints A sequence of endpoints.+ *+ * @param connect_condition A function object that is called prior to each+ * connection attempt. The signature of the function object must be:+ * @code bool connect_condition(+ * const asio::error_code& ec,+ * const typename Protocol::endpoint& next); @endcode+ * The @c ec parameter contains the result from the most recent connect+ * operation. Before the first connection attempt, @c ec is always set to+ * indicate success. The @c next parameter is the next endpoint to be tried.+ * The function object should return true if the next endpoint should be tried,+ * and false if it should be skipped.+ *+ * @param handler The handler to be called when the connect operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * // Result of operation. if the sequence is empty, set to+ * // asio::error::not_found. Otherwise, contains the+ * // error from the last connection attempt.+ * const asio::error_code& error,+ *+ * // On success, an iterator denoting the successfully+ * // connected endpoint. Otherwise, the end iterator.+ * Iterator iterator+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * The following connect condition function object can be used to output+ * information about the individual connection attempts:+ * @code struct my_connect_condition+ * {+ * bool operator()(+ * const asio::error_code& ec,+ * const::tcp::endpoint& next)+ * {+ * if (ec) std::cout << "Error: " << ec.message() << std::endl;+ * std::cout << "Trying: " << next << std::endl;+ * return true;+ * }+ * }; @endcode+ * It would be used with the asio::connect function as follows:+ * @code tcp::resolver r(my_context);+ * tcp::resolver::query q("host", "service");+ * tcp::socket s(my_context);+ *+ * // ...+ *+ * r.async_resolve(q, resolve_handler);+ *+ * // ...+ *+ * void resolve_handler(+ * const asio::error_code& ec,+ * tcp::resolver::results_type results)+ * {+ * if (!ec)+ * {+ * asio::async_connect(s, results,+ * my_connect_condition(),+ * connect_handler);+ * }+ * }+ *+ * // ...+ *+ * void connect_handler(+ * const asio::error_code& ec,+ * const tcp::endpoint& endpoint)+ * {+ * if (ec)+ * {+ * // An error occurred.+ * }+ * else+ * {+ * std::cout << "Connected to: " << endpoint << std::endl;+ * }+ * } @endcode+ */+template <typename Protocol, typename Executor,+ typename EndpointSequence, typename ConnectCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ typename Protocol::endpoint)) RangeConnectHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>+ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,+ void (asio::error_code, typename Protocol::endpoint))+async_connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints, ConnectCondition connect_condition,+ ASIO_MOVE_ARG(RangeConnectHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(Executor),+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type* = 0);++#if !defined(ASIO_NO_DEPRECATED)+/// (Deprecated: Use range overload.) Asynchronously establishes a socket+/// connection by trying each endpoint in a sequence.+/**+ * 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+ * member function, once for each endpoint in the sequence, until a connection+ * is successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start of a sequence of endpoints.+ *+ * @param connect_condition A function object that is called prior to each+ * connection attempt. The signature of the function object must be:+ * @code bool connect_condition(+ * const asio::error_code& ec,+ * const typename Protocol::endpoint& next); @endcode+ * The @c ec parameter contains the result from the most recent connect+ * operation. Before the first connection attempt, @c ec is always set to+ * indicate success. The @c next parameter is the next endpoint to be tried.+ * The function object should return true if the next endpoint should be tried,+ * and false if it should be skipped.+ *+ * @param handler The handler to be called when the connect operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * // Result of operation. if the sequence is empty, set to+ * // asio::error::not_found. Otherwise, contains the+ * // error from the last connection attempt.+ * const asio::error_code& error,+ *+ * // On success, an iterator denoting the successfully+ * // connected endpoint. Otherwise, the end iterator.+ * Iterator iterator+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @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 types such as @c asio::ip::tcp::resolver::iterator.+ */+template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ Iterator)) IteratorConnectHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>+ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,+ void (asio::error_code, Iterator))+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ ConnectCondition connect_condition,+ ASIO_MOVE_ARG(IteratorConnectHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(Executor),+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);+#endif // !defined(ASIO_NO_DEPRECATED)++/// Asynchronously establishes a socket connection by trying each endpoint in a+/// sequence.+/**+ * 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+ * member function, once for each endpoint in the sequence, until a connection+ * is successfully established.+ *+ * @param s The socket to be connected. If the socket is already open, it will+ * be closed.+ *+ * @param begin An iterator pointing to the start of a sequence of endpoints.+ *+ * @param end An iterator pointing to the end of a sequence of endpoints.+ *+ * @param connect_condition A function object that is called prior to each+ * connection attempt. The signature of the function object must be:+ * @code bool connect_condition(+ * const asio::error_code& ec,+ * const typename Protocol::endpoint& next); @endcode+ * The @c ec parameter contains the result from the most recent connect+ * operation. Before the first connection attempt, @c ec is always set to+ * indicate success. The @c next parameter is the next endpoint to be tried.+ * The function object should return true if the next endpoint should be tried,+ * and false if it should be skipped.+ *+ * @param handler The handler to be called when the connect operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * // Result of operation. if the sequence is empty, set to+ * // asio::error::not_found. Otherwise, contains the+ * // error from the last connection attempt.+ * const asio::error_code& error,+ *+ * // On success, an iterator denoting the successfully+ * // connected endpoint. Otherwise, the end iterator.+ * Iterator iterator+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * The following connect condition function object can be used to output+ * information about the individual connection attempts:+ * @code struct my_connect_condition+ * {+ * bool operator()(+ * const asio::error_code& ec,+ * const::tcp::endpoint& next)+ * {+ * if (ec) std::cout << "Error: " << ec.message() << std::endl;+ * std::cout << "Trying: " << next << std::endl;+ * return true;+ * }+ * }; @endcode+ * It would be used with the asio::connect function as follows:+ * @code tcp::resolver r(my_context);+ * tcp::resolver::query q("host", "service");+ * tcp::socket s(my_context);+ *+ * // ...+ *+ * r.async_resolve(q, resolve_handler);+ *+ * // ...+ *+ * void resolve_handler(+ * const asio::error_code& ec,+ * tcp::resolver::iterator i)+ * {+ * if (!ec)+ * {+ * tcp::resolver::iterator end;+ * asio::async_connect(s, i, end,+ * my_connect_condition(),+ * connect_handler);+ * }+ * }+ *+ * // ...+ *+ * void connect_handler(+ * const asio::error_code& ec,+ * tcp::resolver::iterator i)+ * {+ * if (ec)+ * {+ * // An error occurred.+ * }+ * else+ * {+ * std::cout << "Connected to: " << i->endpoint() << std::endl;+ * }+ * } @endcode+ */+template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ Iterator)) IteratorConnectHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>+ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,+ void (asio::error_code, Iterator))+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ Iterator end, ConnectCondition connect_condition,+ ASIO_MOVE_ARG(IteratorConnectHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(Executor));++/*@}*/++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/connect.hpp"++#endif
+ link/modules/asio-standalone/asio/include/asio/coroutine.hpp view
@@ -0,0 +1,328 @@+//+// coroutine.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_COROUTINE_HPP+#define ASIO_COROUTINE_HPP++namespace asio {+namespace detail {++class coroutine_ref;++} // namespace detail++/// Provides support for implementing stackless coroutines.+/**+ * The @c coroutine class may be used to implement stackless coroutines. The+ * class itself is used to store the current state of the coroutine.+ *+ * Coroutines are copy-constructible and assignable, and the space overhead is+ * a single int. They can be used as a base class:+ *+ * @code class session : coroutine+ * {+ * ...+ * }; @endcode+ *+ * or as a data member:+ *+ * @code class session+ * {+ * ...+ * coroutine coro_;+ * }; @endcode+ *+ * or even bound in as a function argument using lambdas or @c bind(). The+ * important thing is that as the application maintains a copy of the object+ * for as long as the coroutine must be kept alive.+ *+ * @par Pseudo-keywords+ *+ * A coroutine is used in conjunction with certain "pseudo-keywords", which+ * are implemented as macros. These macros are defined by a header file:+ *+ * @code #include <asio/yield.hpp>@endcode+ *+ * and may conversely be undefined as follows:+ *+ * @code #include <asio/unyield.hpp>@endcode+ *+ * <b>reenter</b>+ *+ * The @c reenter macro is used to define the body of a coroutine. It takes a+ * single argument: a pointer or reference to a coroutine object. For example,+ * if the base class is a coroutine object you may write:+ *+ * @code reenter (this)+ * {+ * ... coroutine body ...+ * } @endcode+ *+ * and if a data member or other variable you can write:+ *+ * @code reenter (coro_)+ * {+ * ... coroutine body ...+ * } @endcode+ *+ * When @c reenter is executed at runtime, control jumps to the location of the+ * last @c yield or @c fork.+ *+ * The coroutine body may also be a single statement, such as:+ *+ * @code reenter (this) for (;;)+ * {+ * ...+ * } @endcode+ *+ * @b Limitation: The @c reenter macro is implemented using a switch. This+ * means that you must take care when using local variables within the+ * coroutine body. The local variable is not allowed in a position where+ * reentering the coroutine could bypass the variable definition.+ *+ * <b>yield <em>statement</em></b>+ *+ * This form of the @c yield keyword is often used with asynchronous operations:+ *+ * @code yield socket_->async_read_some(buffer(*buffer_), *this); @endcode+ *+ * This divides into four logical steps:+ *+ * @li @c yield saves the current state of the coroutine.+ * @li The statement initiates the asynchronous operation.+ * @li The resume point is defined immediately following the statement.+ * @li Control is transferred to the end of the coroutine body.+ *+ * When the asynchronous operation completes, the function object is invoked+ * and @c reenter causes control to transfer to the resume point. It is+ * important to remember to carry the coroutine state forward with the+ * asynchronous operation. In the above snippet, the current class is a+ * function object object with a coroutine object as base class or data member.+ *+ * The statement may also be a compound statement, and this permits us to+ * define local variables with limited scope:+ *+ * @code yield+ * {+ * mutable_buffers_1 b = buffer(*buffer_);+ * socket_->async_read_some(b, *this);+ * } @endcode+ *+ * <b>yield return <em>expression</em> ;</b>+ *+ * This form of @c yield is often used in generators or coroutine-based parsers.+ * For example, the function object:+ *+ * @code struct interleave : coroutine+ * {+ * istream& is1;+ * istream& is2;+ * char operator()(char c)+ * {+ * reenter (this) for (;;)+ * {+ * yield return is1.get();+ * yield return is2.get();+ * }+ * }+ * }; @endcode+ *+ * defines a trivial coroutine that interleaves the characters from two input+ * streams.+ *+ * This type of @c yield divides into three logical steps:+ *+ * @li @c yield saves the current state of the coroutine.+ * @li The resume point is defined immediately following the semicolon.+ * @li The value of the expression is returned from the function.+ *+ * <b>yield ;</b>+ *+ * This form of @c yield is equivalent to the following steps:+ *+ * @li @c yield saves the current state of the coroutine.+ * @li The resume point is defined immediately following the semicolon.+ * @li Control is transferred to the end of the coroutine body.+ *+ * This form might be applied when coroutines are used for cooperative+ * threading and scheduling is explicitly managed. For example:+ *+ * @code struct task : coroutine+ * {+ * ...+ * void operator()()+ * {+ * reenter (this)+ * {+ * while (... not finished ...)+ * {+ * ... do something ...+ * yield;+ * ... do some more ...+ * yield;+ * }+ * }+ * }+ * ...+ * };+ * ...+ * task t1, t2;+ * for (;;)+ * {+ * t1();+ * t2();+ * } @endcode+ *+ * <b>yield break ;</b>+ *+ * The final form of @c yield is used to explicitly terminate the coroutine.+ * This form is comprised of two steps:+ *+ * @li @c yield sets the coroutine state to indicate termination.+ * @li Control is transferred to the end of the coroutine body.+ *+ * Once terminated, calls to is_complete() return true and the coroutine cannot+ * be reentered.+ *+ * Note that a coroutine may also be implicitly terminated if the coroutine+ * body is exited without a yield, e.g. by return, throw or by running to the+ * end of the body.+ *+ * <b>fork <em>statement</em></b>+ *+ * The @c fork pseudo-keyword is used when "forking" a coroutine, i.e. splitting+ * it into two (or more) copies. One use of @c fork is in a server, where a new+ * coroutine is created to handle each client connection:+ * + * @code reenter (this)+ * {+ * do+ * {+ * socket_.reset(new tcp::socket(my_context_));+ * yield acceptor->async_accept(*socket_, *this);+ * fork server(*this)();+ * } while (is_parent());+ * ... client-specific handling follows ...+ * } @endcode+ * + * The logical steps involved in a @c fork are:+ * + * @li @c fork saves the current state of the coroutine.+ * @li The statement creates a copy of the coroutine and either executes it+ * immediately or schedules it for later execution.+ * @li The resume point is defined immediately following the semicolon.+ * @li For the "parent", control immediately continues from the next line.+ *+ * The functions is_parent() and is_child() can be used to differentiate+ * between parent and child. You would use these functions to alter subsequent+ * control flow.+ *+ * 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.+ * The clone can be called immediately, as above, or scheduled for delayed+ * execution using something like asio::post().+ *+ * @par Alternate macro names+ *+ * If preferred, an application can use macro names that follow a more typical+ * naming convention, rather than the pseudo-keywords. These are:+ *+ * @li @c ASIO_CORO_REENTER instead of @c reenter+ * @li @c ASIO_CORO_YIELD instead of @c yield+ * @li @c ASIO_CORO_FORK instead of @c fork+ */+class coroutine+{+public:+ /// Constructs a coroutine in its initial state.+ coroutine() : value_(0) {}++ /// Returns true if the coroutine is the child of a fork.+ bool is_child() const { return value_ < 0; }++ /// Returns true if the coroutine is the parent of a fork.+ bool is_parent() const { return !is_child(); }++ /// Returns true if the coroutine has reached its terminal state.+ bool is_complete() const { return value_ == -1; }++private:+ friend class detail::coroutine_ref;+ int value_;+};+++namespace detail {++class coroutine_ref+{+public:+ coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}+ coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}+ ~coroutine_ref() { if (!modified_) value_ = -1; }+ operator int() const { return value_; }+ int& operator=(int v) { modified_ = true; return value_ = v; }+private:+ void operator=(const coroutine_ref&);+ int& value_;+ bool modified_;+};++} // namespace detail+} // namespace asio++#define ASIO_CORO_REENTER(c) \+ switch (::asio::detail::coroutine_ref _coro_value = c) \+ case -1: if (_coro_value) \+ { \+ goto terminate_coroutine; \+ terminate_coroutine: \+ _coro_value = -1; \+ goto bail_out_of_coroutine; \+ bail_out_of_coroutine: \+ break; \+ } \+ else /* fall-through */ case 0:++#define ASIO_CORO_YIELD_IMPL(n) \+ for (_coro_value = (n);;) \+ if (_coro_value == 0) \+ { \+ case (n): ; \+ break; \+ } \+ else \+ switch (_coro_value ? 0 : 1) \+ for (;;) \+ /* fall-through */ case -1: if (_coro_value) \+ goto terminate_coroutine; \+ else for (;;) \+ /* fall-through */ case 1: if (_coro_value) \+ goto bail_out_of_coroutine; \+ else /* fall-through */ case 0:++#define ASIO_CORO_FORK_IMPL(n) \+ for (_coro_value = -(n);; _coro_value = (n)) \+ if (_coro_value == (n)) \+ { \+ case -(n): ; \+ break; \+ } \+ else++#if defined(_MSC_VER)+# define ASIO_CORO_YIELD ASIO_CORO_YIELD_IMPL(__COUNTER__ + 1)+# define ASIO_CORO_FORK ASIO_CORO_FORK_IMPL(__COUNTER__ + 1)+#else // defined(_MSC_VER)+# define ASIO_CORO_YIELD ASIO_CORO_YIELD_IMPL(__LINE__)+# define ASIO_CORO_FORK ASIO_CORO_FORK_IMPL(__LINE__)+#endif // defined(_MSC_VER)++#endif // ASIO_COROUTINE_HPP
+ link/modules/asio-standalone/asio/include/asio/deadline_timer.hpp view
@@ -0,0 +1,38 @@+//+// deadline_timer.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DEADLINE_TIMER_HPP+#define ASIO_DEADLINE_TIMER_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_BOOST_DATE_TIME) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/detail/socket_types.hpp" // Must come before posix_time.+#include "asio/basic_deadline_timer.hpp"++#include <boost/date_time/posix_time/posix_time_types.hpp>++namespace asio {++/// Typedef for the typical usage of timer. Uses a UTC clock.+typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer;++} // namespace asio++#endif // defined(ASIO_HAS_BOOST_DATE_TIME)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_DEADLINE_TIMER_HPP
+ link/modules/asio-standalone/asio/include/asio/defer.hpp view
@@ -0,0 +1,130 @@+//+// defer.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DEFER_HPP+#define ASIO_DEFER_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/async_result.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution_context.hpp"+#include "asio/execution/executor.hpp"+#include "asio/is_executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Submits a completion token or function object for execution.+/**+ * This function submits an object for execution using the object's associated+ * executor. The function object is queued for execution, and is never called+ * from the current thread prior to returning from <tt>defer()</tt>.+ *+ * 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.+ *+ * This function has the following effects:+ *+ * @li Constructs a function object handler of type @c Handler, initialized+ * with <tt>handler(forward<CompletionToken>(token))</tt>.+ *+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,+ * initializing the object as <tt>result(handler)</tt>.+ *+ * @li Obtains the handler's associated executor object @c ex by performing+ * <tt>get_associated_executor(handler)</tt>.+ *+ * @li Obtains the handler's associated allocator object @c alloc by performing+ * <tt>get_associated_allocator(handler)</tt>.+ *+ * @li Performs <tt>ex.defer(std::move(handler), alloc)</tt>.+ *+ * @li Returns <tt>result.get()</tt>.+ */+template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(+ ASIO_MOVE_ARG(CompletionToken) token);++/// Submits a completion token or function object for execution.+/**+ * This function submits an object for execution using the specified executor.+ * The function object is queued for execution, and is never called from the+ * current thread prior to returning from <tt>defer()</tt>.+ *+ * 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.+ *+ * This function has the following effects:+ *+ * @li Constructs a function object handler of type @c Handler, initialized+ * with <tt>handler(forward<CompletionToken>(token))</tt>.+ *+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,+ * initializing the object as <tt>result(handler)</tt>.+ *+ * @li Obtains the handler's associated executor object @c ex1 by performing+ * <tt>get_associated_executor(handler)</tt>.+ *+ * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>.+ *+ * @li Obtains the handler's associated allocator object @c alloc by performing+ * <tt>get_associated_allocator(handler)</tt>.+ *+ * @li Constructs a function object @c f with a function call operator that+ * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by+ * <tt>w.reset()</tt>.+ *+ * @li Performs <tt>Executor(ex).defer(std::move(f), alloc)</tt>.+ *+ * @li Returns <tt>result.get()</tt>.+ */+template <typename Executor,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(+ const Executor& ex,+ ASIO_MOVE_ARG(CompletionToken) token+ ASIO_DEFAULT_COMPLETION_TOKEN(Executor),+ typename enable_if<+ execution::is_executor<Executor>::value || is_executor<Executor>::value+ >::type* = 0);++/// Submits a completion token or function object for execution.+/**+ * @returns <tt>defer(ctx.get_executor(), forward<CompletionToken>(token))</tt>.+ */+template <typename ExecutionContext,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename ExecutionContext::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(+ ExecutionContext& ctx,+ ASIO_MOVE_ARG(CompletionToken) token+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename ExecutionContext::executor_type),+ typename enable_if<is_convertible<+ ExecutionContext&, execution_context&>::value>::type* = 0);++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/defer.hpp"++#endif // ASIO_DEFER_HPP
+ link/modules/asio-standalone/asio/include/asio/detached.hpp view
@@ -0,0 +1,112 @@+//+// detached.hpp+// ~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 {++/// Class 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. + ASIO_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) ASIO_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,+ typename enable_if<+ is_convertible<OtherExecutor, InnerExecutor>::value+ >::type* = 0) ASIO_NOEXCEPT+ : InnerExecutor(ex)+ {+ }+ };++ /// Type alias to adapt an I/O object to use @c detached_t as its+ /// default completion token type.+#if defined(ASIO_HAS_ALIAS_TEMPLATES) \+ || defined(GENERATING_DOCUMENTATION)+ template <typename T>+ using as_default_on_t = typename T::template rebind_executor<+ executor_with_default<typename T::executor_type> >::other;+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)++ /// 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>::type::template rebind_executor<+ executor_with_default<typename decay<T>::type::executor_type>+ >::other+ as_default_on(ASIO_MOVE_ARG(T) object)+ {+ return typename decay<T>::type::template rebind_executor<+ executor_with_default<typename decay<T>::type::executor_type>+ >::other(ASIO_MOVE_CAST(T)(object));+ }+};++/// A special value, similar to std::nothrow.+/**+ * See the documentation for asio::detached_t for a usage example.+ */+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr detached_t detached;+#elif defined(ASIO_MSVC)+__declspec(selectany) detached_t detached;+#endif++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/detached.hpp"++#endif // ASIO_DETACHED_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/array.hpp view
@@ -0,0 +1,38 @@+//+// detail/array.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_ARRAY_HPP+#define ASIO_DETAIL_ARRAY_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_STD_ARRAY)+# include <array>+#else // defined(ASIO_HAS_STD_ARRAY)+# include <boost/array.hpp>+#endif // defined(ASIO_HAS_STD_ARRAY)++namespace asio {+namespace detail {++#if defined(ASIO_HAS_STD_ARRAY)+using std::array;+#else // defined(ASIO_HAS_STD_ARRAY)+using boost::array;+#endif // defined(ASIO_HAS_STD_ARRAY)++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_ARRAY_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/array_fwd.hpp view
@@ -0,0 +1,34 @@+//+// detail/array_fwd.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_ARRAY_FWD_HPP+#define ASIO_DETAIL_ARRAY_FWD_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++namespace boost {++template<class T, std::size_t N>+class array;++} // namespace boost++// 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+// add significantly to the compile time.+#if defined(ASIO_HAS_STD_ARRAY)+# include <array>+#endif // defined(ASIO_HAS_STD_ARRAY)++#endif // ASIO_DETAIL_ARRAY_FWD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/assert.hpp view
@@ -0,0 +1,32 @@+//+// detail/assert.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_ASSERT_HPP+#define ASIO_DETAIL_ASSERT_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_BOOST_ASSERT)+# include <boost/assert.hpp>+#else // defined(ASIO_HAS_BOOST_ASSERT)+# include <cassert>+#endif // defined(ASIO_HAS_BOOST_ASSERT)++#if defined(ASIO_HAS_BOOST_ASSERT)+# define ASIO_ASSERT(expr) BOOST_ASSERT(expr)+#else // defined(ASIO_HAS_BOOST_ASSERT)+# define ASIO_ASSERT(expr) assert(expr)+#endif // defined(ASIO_HAS_BOOST_ASSERT)++#endif // ASIO_DETAIL_ASSERT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/atomic_count.hpp view
@@ -0,0 +1,64 @@+//+// detail/atomic_count.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_ATOMIC_COUNT_HPP+#define ASIO_DETAIL_ATOMIC_COUNT_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_THREADS)+// Nothing to include.+#elif defined(ASIO_HAS_STD_ATOMIC)+# include <atomic>+#else // defined(ASIO_HAS_STD_ATOMIC)+# include <boost/detail/atomic_count.hpp>+#endif // defined(ASIO_HAS_STD_ATOMIC)++namespace asio {+namespace detail {++#if !defined(ASIO_HAS_THREADS)+typedef long atomic_count;+inline void increment(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; }+#elif defined(ASIO_HAS_STD_ATOMIC)+typedef std::atomic<long> atomic_count;+inline void increment(atomic_count& a, long b) { a += b; }++inline void ref_count_up(atomic_count& a)+{+ 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;+}+#else // defined(ASIO_HAS_STD_ATOMIC)+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) { ++a; }+inline bool ref_count_down(atomic_count& a) { return --a == 0; }+#endif // defined(ASIO_HAS_STD_ATOMIC)++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_ATOMIC_COUNT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/base_from_completion_cond.hpp view
@@ -0,0 +1,69 @@+//+// detail/base_from_completion_cond.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_COMPLETION_COND_HPP+#define ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/completion_condition.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename CompletionCondition>+class base_from_completion_cond+{+protected:+ explicit base_from_completion_cond(CompletionCondition& completion_condition)+ : completion_condition_(+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition))+ {+ }++ std::size_t check_for_completion(+ const asio::error_code& ec,+ std::size_t total_transferred)+ {+ return detail::adapt_completion_condition_result(+ completion_condition_(ec, total_transferred));+ }++private:+ CompletionCondition completion_condition_;+};++template <>+class base_from_completion_cond<transfer_all_t>+{+protected:+ explicit base_from_completion_cond(transfer_all_t)+ {+ }++ static std::size_t check_for_completion(+ const asio::error_code& ec,+ std::size_t total_transferred)+ {+ return transfer_all_t()(ec, total_transferred);+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/bind_handler.hpp view
@@ -0,0 +1,934 @@+//+// detail/bind_handler.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BIND_HANDLER_HPP+#define ASIO_DETAIL_BIND_HANDLER_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_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/detail/handler_alloc_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/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename Arg1>+class binder1+{+public:+ template <typename T>+ binder1(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1)+ : handler_(ASIO_MOVE_CAST(T)(handler)),+ arg1_(arg1)+ {+ }++ binder1(Handler& handler, const Arg1& arg1)+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),+ arg1_(arg1)+ {+ }++#if defined(ASIO_HAS_MOVE)+ binder1(const binder1& other)+ : handler_(other.handler_),+ arg1_(other.arg1_)+ {+ }++ binder1(binder1&& other)+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()()+ {+ handler_(static_cast<const Arg1&>(arg1_));+ }++ void operator()() const+ {+ handler_(arg1_);+ }++//private:+ Handler handler_;+ Arg1 arg1_;+};++template <typename Handler, typename Arg1>+inline asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size,+ binder1<Handler, Arg1>* this_handler)+{+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1>+inline asio_handler_deallocate_is_deprecated+asio_handler_deallocate(void* pointer, std::size_t size,+ binder1<Handler, Arg1>* this_handler)+{+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1>+inline bool asio_handler_is_continuation(+ binder1<Handler, Arg1>* this_handler)+{+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+}++template <typename Function, typename Handler, typename Arg1>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(Function& function,+ binder1<Handler, Arg1>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Function, typename Handler, typename Arg1>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(const Function& function,+ binder1<Handler, Arg1>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1>+inline binder1<typename decay<Handler>::type, Arg1> bind_handler(+ ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1)+{+ return binder1<typename decay<Handler>::type, Arg1>(0,+ ASIO_MOVE_CAST(Handler)(handler), arg1);+}++template <typename Handler, typename Arg1, typename Arg2>+class binder2+{+public:+ template <typename T>+ binder2(int, ASIO_MOVE_ARG(T) handler,+ const Arg1& arg1, const Arg2& arg2)+ : handler_(ASIO_MOVE_CAST(T)(handler)),+ arg1_(arg1),+ arg2_(arg2)+ {+ }++ binder2(Handler& handler, const Arg1& arg1, const Arg2& arg2)+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),+ arg1_(arg1),+ arg2_(arg2)+ {+ }++#if defined(ASIO_HAS_MOVE)+ binder2(const binder2& other)+ : handler_(other.handler_),+ arg1_(other.arg1_),+ arg2_(other.arg2_)+ {+ }++ binder2(binder2&& other)+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),+ arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()()+ {+ handler_(static_cast<const Arg1&>(arg1_),+ static_cast<const Arg2&>(arg2_));+ }++ void operator()() const+ {+ handler_(arg1_, arg2_);+ }++//private:+ Handler handler_;+ Arg1 arg1_;+ Arg2 arg2_;+};++template <typename Handler, typename Arg1, typename Arg2>+inline asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size,+ binder2<Handler, Arg1, Arg2>* this_handler)+{+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2>+inline asio_handler_deallocate_is_deprecated+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_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2>+inline bool asio_handler_is_continuation(+ binder2<Handler, Arg1, Arg2>* this_handler)+{+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+}++template <typename Function, typename Handler, typename Arg1, typename Arg2>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(Function& function,+ binder2<Handler, Arg1, Arg2>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Function, typename Handler, typename Arg1, typename Arg2>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(const Function& function,+ binder2<Handler, Arg1, Arg2>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2>+inline binder2<typename decay<Handler>::type, Arg1, Arg2> bind_handler(+ ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2)+{+ return binder2<typename decay<Handler>::type, Arg1, Arg2>(0,+ ASIO_MOVE_CAST(Handler)(handler), arg1, arg2);+}++template <typename Handler, typename Arg1, typename Arg2, typename Arg3>+class binder3+{+public:+ template <typename T>+ binder3(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,+ const Arg2& arg2, const Arg3& arg3)+ : handler_(ASIO_MOVE_CAST(T)(handler)),+ arg1_(arg1),+ arg2_(arg2),+ arg3_(arg3)+ {+ }++ binder3(Handler& handler, const Arg1& arg1,+ const Arg2& arg2, const Arg3& arg3)+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),+ arg1_(arg1),+ arg2_(arg2),+ arg3_(arg3)+ {+ }++#if defined(ASIO_HAS_MOVE)+ binder3(const binder3& other)+ : handler_(other.handler_),+ arg1_(other.arg1_),+ arg2_(other.arg2_),+ arg3_(other.arg3_)+ {+ }++ binder3(binder3&& other)+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),+ arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),+ arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()()+ {+ handler_(static_cast<const Arg1&>(arg1_),+ static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_));+ }++ void operator()() const+ {+ handler_(arg1_, arg2_, arg3_);+ }++//private:+ Handler handler_;+ Arg1 arg1_;+ Arg2 arg2_;+ Arg3 arg3_;+};++template <typename Handler, typename Arg1, typename Arg2, typename Arg3>+inline asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size,+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)+{+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2, typename Arg3>+inline asio_handler_deallocate_is_deprecated+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_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2, typename Arg3>+inline bool asio_handler_is_continuation(+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)+{+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+}++template <typename Function, typename Handler,+ typename Arg1, typename Arg2, typename Arg3>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(Function& function,+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Function, typename Handler,+ typename Arg1, typename Arg2, typename Arg3>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(const Function& function,+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2, typename Arg3>+inline binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3> bind_handler(+ ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2,+ const Arg3& arg3)+{+ return binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3>(0,+ ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3);+}++template <typename Handler, typename Arg1,+ typename Arg2, typename Arg3, typename Arg4>+class binder4+{+public:+ template <typename T>+ binder4(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)+ : handler_(ASIO_MOVE_CAST(T)(handler)),+ arg1_(arg1),+ arg2_(arg2),+ arg3_(arg3),+ arg4_(arg4)+ {+ }++ binder4(Handler& handler, const Arg1& arg1,+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),+ arg1_(arg1),+ arg2_(arg2),+ arg3_(arg3),+ arg4_(arg4)+ {+ }++#if defined(ASIO_HAS_MOVE)+ binder4(const binder4& other)+ : handler_(other.handler_),+ arg1_(other.arg1_),+ arg2_(other.arg2_),+ arg3_(other.arg3_),+ arg4_(other.arg4_)+ {+ }++ binder4(binder4&& other)+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),+ arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),+ arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)),+ arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()()+ {+ handler_(static_cast<const Arg1&>(arg1_),+ static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_),+ static_cast<const Arg4&>(arg4_));+ }++ void operator()() const+ {+ handler_(arg1_, arg2_, arg3_, arg4_);+ }++//private:+ Handler handler_;+ Arg1 arg1_;+ Arg2 arg2_;+ Arg3 arg3_;+ Arg4 arg4_;+};++template <typename Handler, typename Arg1,+ typename Arg2, typename Arg3, typename Arg4>+inline asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size,+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)+{+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1,+ typename Arg2, typename Arg3, typename Arg4>+inline asio_handler_deallocate_is_deprecated+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_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1,+ typename Arg2, typename Arg3, typename Arg4>+inline bool asio_handler_is_continuation(+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)+{+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+}++template <typename Function, typename Handler, typename Arg1,+ typename Arg2, typename Arg3, typename Arg4>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(Function& function,+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Function, typename Handler, typename Arg1,+ typename Arg2, typename Arg3, typename Arg4>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(const Function& function,+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1,+ typename Arg2, typename Arg3, typename Arg4>+inline binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>+bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1,+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)+{+ return binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>(0,+ ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4);+}++template <typename Handler, typename Arg1, typename Arg2,+ typename Arg3, typename Arg4, typename Arg5>+class binder5+{+public:+ template <typename T>+ binder5(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)+ : handler_(ASIO_MOVE_CAST(T)(handler)),+ arg1_(arg1),+ arg2_(arg2),+ arg3_(arg3),+ arg4_(arg4),+ arg5_(arg5)+ {+ }++ binder5(Handler& handler, const Arg1& arg1, const Arg2& arg2,+ const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),+ arg1_(arg1),+ arg2_(arg2),+ arg3_(arg3),+ arg4_(arg4),+ arg5_(arg5)+ {+ }++#if defined(ASIO_HAS_MOVE)+ binder5(const binder5& other)+ : handler_(other.handler_),+ arg1_(other.arg1_),+ arg2_(other.arg2_),+ arg3_(other.arg3_),+ arg4_(other.arg4_),+ arg5_(other.arg5_)+ {+ }++ binder5(binder5&& other)+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),+ arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),+ arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)),+ arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_)),+ arg5_(ASIO_MOVE_CAST(Arg5)(other.arg5_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()()+ {+ handler_(static_cast<const Arg1&>(arg1_),+ static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_),+ static_cast<const Arg4&>(arg4_), static_cast<const Arg5&>(arg5_));+ }++ void operator()() const+ {+ handler_(arg1_, arg2_, arg3_, arg4_, arg5_);+ }++//private:+ Handler handler_;+ Arg1 arg1_;+ Arg2 arg2_;+ Arg3 arg3_;+ Arg4 arg4_;+ Arg5 arg5_;+};++template <typename Handler, typename Arg1, typename Arg2,+ typename Arg3, typename Arg4, typename Arg5>+inline asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size,+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)+{+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2,+ typename Arg3, typename Arg4, typename Arg5>+inline asio_handler_deallocate_is_deprecated+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_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2,+ typename Arg3, typename Arg4, typename Arg5>+inline bool asio_handler_is_continuation(+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)+{+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+}++template <typename Function, typename Handler, typename Arg1,+ typename Arg2, typename Arg3, typename Arg4, typename Arg5>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(Function& function,+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Function, typename Handler, typename Arg1,+ typename Arg2, typename Arg3, typename Arg4, typename Arg5>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(const Function& function,+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2,+ typename Arg3, typename Arg4, typename Arg5>+inline binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5>+bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1,+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)+{+ return binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5>(0,+ ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4, arg5);+}++#if defined(ASIO_HAS_MOVE)++template <typename Handler, typename Arg1>+class move_binder1+{+public:+ move_binder1(int, ASIO_MOVE_ARG(Handler) handler,+ ASIO_MOVE_ARG(Arg1) arg1)+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),+ arg1_(ASIO_MOVE_CAST(Arg1)(arg1))+ {+ }++ move_binder1(move_binder1&& other)+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_))+ {+ }++ void operator()()+ {+ handler_(ASIO_MOVE_CAST(Arg1)(arg1_));+ }++//private:+ Handler handler_;+ Arg1 arg1_;+};++template <typename Handler, typename Arg1>+inline asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size,+ move_binder1<Handler, Arg1>* this_handler)+{+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1>+inline asio_handler_deallocate_is_deprecated+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_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1>+inline bool asio_handler_is_continuation(+ move_binder1<Handler, Arg1>* this_handler)+{+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+}++template <typename Function, typename Handler, typename Arg1>+inline asio_handler_invoke_is_deprecated+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_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2>+class move_binder2+{+public:+ move_binder2(int, ASIO_MOVE_ARG(Handler) handler,+ const Arg1& arg1, ASIO_MOVE_ARG(Arg2) arg2)+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),+ arg1_(arg1),+ arg2_(ASIO_MOVE_CAST(Arg2)(arg2))+ {+ }++ move_binder2(move_binder2&& other)+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),+ arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_))+ {+ }++ void operator()()+ {+ handler_(static_cast<const Arg1&>(arg1_),+ ASIO_MOVE_CAST(Arg2)(arg2_));+ }++//private:+ Handler handler_;+ Arg1 arg1_;+ Arg2 arg2_;+};++template <typename Handler, typename Arg1, typename Arg2>+inline asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size,+ move_binder2<Handler, Arg1, Arg2>* this_handler)+{+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2>+inline asio_handler_deallocate_is_deprecated+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_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Arg1, typename Arg2>+inline bool asio_handler_is_continuation(+ move_binder2<Handler, Arg1, Arg2>* this_handler)+{+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+}++template <typename Function, typename Handler, typename Arg1, typename Arg2>+inline asio_handler_invoke_is_deprecated+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_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++#endif // defined(ASIO_HAS_MOVE)++} // namespace detail++template <typename Handler, typename Arg1, typename Allocator>+struct associated_allocator<detail::binder1<Handler, Arg1>, Allocator>+{+ typedef typename associated_allocator<Handler, Allocator>::type type;++ static type get(const detail::binder1<Handler, Arg1>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<Handler, Allocator>::get(h.handler_, a);+ }+};++template <typename Handler, typename Arg1, typename Arg2, typename Allocator>+struct associated_allocator<detail::binder2<Handler, Arg1, Arg2>, Allocator>+{+ typedef typename associated_allocator<Handler, Allocator>::type type;++ static type get(const detail::binder2<Handler, Arg1, Arg2>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<Handler, Allocator>::get(h.handler_, a);+ }+};++template <typename Handler, typename Arg1, typename Executor>+struct associated_executor<detail::binder1<Handler, Arg1>, Executor>+{+ typedef typename associated_executor<Handler, Executor>::type type;++ static type get(const detail::binder1<Handler, Arg1>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<Handler, Executor>::get(h.handler_, ex);+ }+};++template <typename Handler, typename Arg1, typename Arg2, typename Executor>+struct associated_executor<detail::binder2<Handler, Arg1, Arg2>, Executor>+{+ typedef typename associated_executor<Handler, Executor>::type type;++ static type get(const detail::binder2<Handler, Arg1, Arg2>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<Handler, Executor>::get(h.handler_, ex);+ }+};++#if defined(ASIO_HAS_MOVE)++template <typename Handler, typename Arg1, typename Allocator>+struct associated_allocator<detail::move_binder1<Handler, Arg1>, Allocator>+{+ typedef typename associated_allocator<Handler, Allocator>::type type;++ 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);+ }+};++template <typename Handler, typename Arg1, typename Arg2, typename Allocator>+struct associated_allocator<+ detail::move_binder2<Handler, Arg1, Arg2>, Allocator>+{+ typedef typename associated_allocator<Handler, Allocator>::type type;++ static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<Handler, Allocator>::get(h.handler_, a);+ }+};++template <typename Handler, typename Arg1, typename Executor>+struct associated_executor<detail::move_binder1<Handler, Arg1>, Executor>+{+ typedef typename associated_executor<Handler, Executor>::type type;++ static type get(const detail::move_binder1<Handler, Arg1>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<Handler, Executor>::get(h.handler_, ex);+ }+};++template <typename Handler, typename Arg1, typename Arg2, typename Executor>+struct associated_executor<detail::move_binder2<Handler, Arg1, Arg2>, Executor>+{+ typedef typename associated_executor<Handler, Executor>::type type;++ static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<Handler, Executor>::get(h.handler_, ex);+ }+};++#endif // defined(ASIO_HAS_MOVE)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_BIND_HANDLER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/blocking_executor_op.hpp view
@@ -0,0 +1,107 @@+//+// detail/blocking_executor_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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/handler_invoke_helpers.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*/)+ {+ 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(());+ asio_handler_invoke_helpers::invoke(o->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
+ link/modules/asio-standalone/asio/include/asio/detail/buffer_resize_guard.hpp view
@@ -0,0 +1,66 @@+//+// detail/buffer_resize_guard.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BUFFER_RESIZE_GUARD_HPP+#define ASIO_DETAIL_BUFFER_RESIZE_GUARD_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/limits.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Helper class to manage buffer resizing in an exception safe way.+template <typename Buffer>+class buffer_resize_guard+{+public:+ // Constructor.+ buffer_resize_guard(Buffer& buffer)+ : buffer_(buffer),+ old_size_(buffer.size())+ {+ }++ // Destructor rolls back the buffer resize unless commit was called.+ ~buffer_resize_guard()+ {+ if (old_size_ != (std::numeric_limits<size_t>::max)())+ {+ buffer_.resize(old_size_);+ }+ }++ // Commit the resize transaction.+ void commit()+ {+ old_size_ = (std::numeric_limits<size_t>::max)();+ }++private:+ // The buffer being managed.+ Buffer& buffer_;++ // The size of the buffer at the time the guard was constructed.+ size_t old_size_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/buffer_sequence_adapter.hpp view
@@ -0,0 +1,650 @@+//+// detail/buffer_sequence_adapter.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BUFFER_SEQUENCE_ADAPTER_HPP+#define ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/buffer.hpp"+#include "asio/detail/array_fwd.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class buffer_sequence_adapter_base+{+#if defined(ASIO_WINDOWS_RUNTIME)+public:+ // The maximum number of buffers to support in a single operation.+ enum { max_buffers = 1 };++protected:+ typedef Windows::Storage::Streams::IBuffer^ native_buffer_type;++ ASIO_DECL static void init_native_buffer(+ native_buffer_type& buf,+ const asio::mutable_buffer& buffer);++ ASIO_DECL static void init_native_buffer(+ native_buffer_type& buf,+ const asio::const_buffer& buffer);+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+public:+ // The maximum number of buffers to support in a single operation.+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };++protected:+ typedef WSABUF native_buffer_type;++ static void init_native_buffer(WSABUF& buf,+ const asio::mutable_buffer& buffer)+ {+ buf.buf = static_cast<char*>(buffer.data());+ buf.len = static_cast<ULONG>(buffer.size());+ }++ static void init_native_buffer(WSABUF& buf,+ const asio::const_buffer& buffer)+ {+ buf.buf = const_cast<char*>(static_cast<const char*>(buffer.data()));+ buf.len = static_cast<ULONG>(buffer.size());+ }+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+public:+ // The maximum number of buffers to support in a single operation.+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };++protected:+ typedef iovec native_buffer_type;++ static void init_iov_base(void*& base, void* addr)+ {+ base = addr;+ }++ template <typename T>+ static void init_iov_base(T& base, void* addr)+ {+ base = static_cast<T>(addr);+ }++ static void init_native_buffer(iovec& iov,+ const asio::mutable_buffer& buffer)+ {+ init_iov_base(iov.iov_base, buffer.data());+ iov.iov_len = buffer.size();+ }++ static void init_native_buffer(iovec& iov,+ const asio::const_buffer& buffer)+ {+ init_iov_base(iov.iov_base, const_cast<void*>(buffer.data()));+ iov.iov_len = buffer.size();+ }+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+};++// Helper class to translate buffers into the native buffer representation.+template <typename Buffer, typename Buffers>+class buffer_sequence_adapter+ : buffer_sequence_adapter_base+{+public:+ enum { is_single_buffer = false };++ explicit buffer_sequence_adapter(const Buffers& buffer_sequence)+ : count_(0), total_buffer_size_(0)+ {+ buffer_sequence_adapter::init(+ asio::buffer_sequence_begin(buffer_sequence),+ asio::buffer_sequence_end(buffer_sequence));+ }++ native_buffer_type* buffers()+ {+ return buffers_;+ }++ std::size_t count() const+ {+ return count_;+ }++ std::size_t total_size() const+ {+ return total_buffer_size_;+ }++ bool all_empty() const+ {+ return total_buffer_size_ == 0;+ }++ static bool all_empty(const Buffers& buffer_sequence)+ {+ return buffer_sequence_adapter::all_empty(+ asio::buffer_sequence_begin(buffer_sequence),+ asio::buffer_sequence_end(buffer_sequence));+ }++ static void validate(const Buffers& buffer_sequence)+ {+ buffer_sequence_adapter::validate(+ asio::buffer_sequence_begin(buffer_sequence),+ asio::buffer_sequence_end(buffer_sequence));+ }++ static Buffer first(const Buffers& buffer_sequence)+ {+ return buffer_sequence_adapter::first(+ asio::buffer_sequence_begin(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:+ template <typename Iterator>+ void init(Iterator begin, Iterator end)+ {+ Iterator iter = begin;+ for (; iter != end && count_ < max_buffers; ++iter, ++count_)+ {+ Buffer buffer(*iter);+ init_native_buffer(buffers_[count_], buffer);+ total_buffer_size_ += buffer.size();+ }+ }++ template <typename Iterator>+ static bool all_empty(Iterator begin, Iterator end)+ {+ Iterator iter = begin;+ std::size_t i = 0;+ for (; iter != end && i < max_buffers; ++iter, ++i)+ if (Buffer(*iter).size() > 0)+ return false;+ return true;+ }++ template <typename Iterator>+ static void validate(Iterator begin, Iterator end)+ {+ Iterator iter = begin;+ for (; iter != end; ++iter)+ {+ Buffer buffer(*iter);+ buffer.data();+ }+ }++ template <typename Iterator>+ static Buffer first(Iterator begin, Iterator end)+ {+ Iterator iter = begin;+ for (; iter != end; ++iter)+ {+ Buffer buffer(*iter);+ if (buffer.size() != 0)+ 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];+ std::size_t count_;+ std::size_t total_buffer_size_;+};++template <typename Buffer>+class buffer_sequence_adapter<Buffer, asio::mutable_buffer>+ : buffer_sequence_adapter_base+{+public:+ enum { is_single_buffer = true };++ explicit buffer_sequence_adapter(+ const asio::mutable_buffer& buffer_sequence)+ {+ init_native_buffer(buffer_, Buffer(buffer_sequence));+ total_buffer_size_ = buffer_sequence.size();+ }++ native_buffer_type* buffers()+ {+ return &buffer_;+ }++ std::size_t count() const+ {+ return 1;+ }++ std::size_t total_size() const+ {+ return total_buffer_size_;+ }++ bool all_empty() const+ {+ return total_buffer_size_ == 0;+ }++ static bool all_empty(const asio::mutable_buffer& buffer_sequence)+ {+ return buffer_sequence.size() == 0;+ }++ static void validate(const asio::mutable_buffer& buffer_sequence)+ {+ buffer_sequence.data();+ }++ static Buffer first(const asio::mutable_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:+ native_buffer_type buffer_;+ std::size_t total_buffer_size_;+};++template <typename Buffer>+class buffer_sequence_adapter<Buffer, asio::const_buffer>+ : buffer_sequence_adapter_base+{+public:+ enum { is_single_buffer = true };++ explicit buffer_sequence_adapter(+ const asio::const_buffer& buffer_sequence)+ {+ init_native_buffer(buffer_, Buffer(buffer_sequence));+ total_buffer_size_ = buffer_sequence.size();+ }++ native_buffer_type* buffers()+ {+ return &buffer_;+ }++ std::size_t count() const+ {+ return 1;+ }++ std::size_t total_size() const+ {+ return total_buffer_size_;+ }++ bool all_empty() const+ {+ return total_buffer_size_ == 0;+ }++ static bool all_empty(const asio::const_buffer& buffer_sequence)+ {+ return buffer_sequence.size() == 0;+ }++ static void validate(const asio::const_buffer& buffer_sequence)+ {+ buffer_sequence.data();+ }++ static Buffer first(const asio::const_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:+ native_buffer_type buffer_;+ std::size_t total_buffer_size_;+};++#if !defined(ASIO_NO_DEPRECATED)++template <typename Buffer>+class buffer_sequence_adapter<Buffer, asio::mutable_buffers_1>+ : buffer_sequence_adapter_base+{+public:+ enum { is_single_buffer = true };++ explicit buffer_sequence_adapter(+ const asio::mutable_buffers_1& buffer_sequence)+ {+ init_native_buffer(buffer_, Buffer(buffer_sequence));+ total_buffer_size_ = buffer_sequence.size();+ }++ native_buffer_type* buffers()+ {+ return &buffer_;+ }++ std::size_t count() const+ {+ return 1;+ }++ std::size_t total_size() const+ {+ return total_buffer_size_;+ }++ bool all_empty() const+ {+ return total_buffer_size_ == 0;+ }++ static bool all_empty(const asio::mutable_buffers_1& buffer_sequence)+ {+ return buffer_sequence.size() == 0;+ }++ static void validate(const asio::mutable_buffers_1& buffer_sequence)+ {+ buffer_sequence.data();+ }++ static Buffer first(const asio::mutable_buffers_1& 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:+ native_buffer_type buffer_;+ std::size_t total_buffer_size_;+};++template <typename Buffer>+class buffer_sequence_adapter<Buffer, asio::const_buffers_1>+ : buffer_sequence_adapter_base+{+public:+ enum { is_single_buffer = true };++ explicit buffer_sequence_adapter(+ const asio::const_buffers_1& buffer_sequence)+ {+ init_native_buffer(buffer_, Buffer(buffer_sequence));+ total_buffer_size_ = buffer_sequence.size();+ }++ native_buffer_type* buffers()+ {+ return &buffer_;+ }++ std::size_t count() const+ {+ return 1;+ }++ std::size_t total_size() const+ {+ return total_buffer_size_;+ }++ bool all_empty() const+ {+ return total_buffer_size_ == 0;+ }++ static bool all_empty(const asio::const_buffers_1& buffer_sequence)+ {+ return buffer_sequence.size() == 0;+ }++ static void validate(const asio::const_buffers_1& buffer_sequence)+ {+ buffer_sequence.data();+ }++ static Buffer first(const asio::const_buffers_1& 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:+ native_buffer_type buffer_;+ std::size_t total_buffer_size_;+};++#endif // !defined(ASIO_NO_DEPRECATED)++template <typename Buffer, typename Elem>+class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> >+ : buffer_sequence_adapter_base+{+public:+ enum { is_single_buffer = false };++ explicit buffer_sequence_adapter(+ const boost::array<Elem, 2>& buffer_sequence)+ {+ init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));+ init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));+ total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();+ }++ native_buffer_type* buffers()+ {+ return buffers_;+ }++ std::size_t count() const+ {+ return 2;+ }++ std::size_t total_size() const+ {+ return total_buffer_size_;+ }++ bool all_empty() const+ {+ return total_buffer_size_ == 0;+ }++ static bool all_empty(const boost::array<Elem, 2>& buffer_sequence)+ {+ return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;+ }++ static void validate(const boost::array<Elem, 2>& buffer_sequence)+ {+ buffer_sequence[0].data();+ buffer_sequence[1].data();+ }++ static Buffer first(const boost::array<Elem, 2>& buffer_sequence)+ {+ return Buffer(buffer_sequence[0].size() != 0+ ? 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:+ native_buffer_type buffers_[2];+ std::size_t total_buffer_size_;+};++#if defined(ASIO_HAS_STD_ARRAY)++template <typename Buffer, typename Elem>+class buffer_sequence_adapter<Buffer, std::array<Elem, 2> >+ : buffer_sequence_adapter_base+{+public:+ enum { is_single_buffer = false };++ explicit buffer_sequence_adapter(+ const std::array<Elem, 2>& buffer_sequence)+ {+ init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));+ init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));+ total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();+ }++ native_buffer_type* buffers()+ {+ return buffers_;+ }++ std::size_t count() const+ {+ return 2;+ }++ std::size_t total_size() const+ {+ return total_buffer_size_;+ }++ bool all_empty() const+ {+ return total_buffer_size_ == 0;+ }++ static bool all_empty(const std::array<Elem, 2>& buffer_sequence)+ {+ return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;+ }++ static void validate(const std::array<Elem, 2>& buffer_sequence)+ {+ buffer_sequence[0].data();+ buffer_sequence[1].data();+ }++ static Buffer first(const std::array<Elem, 2>& buffer_sequence)+ {+ return Buffer(buffer_sequence[0].size() != 0+ ? 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:+ native_buffer_type buffers_[2];+ std::size_t total_buffer_size_;+};++#endif // defined(ASIO_HAS_STD_ARRAY)++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/buffer_sequence_adapter.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/buffered_stream_storage.hpp view
@@ -0,0 +1,126 @@+//+// detail/buffered_stream_storage.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BUFFERED_STREAM_STORAGE_HPP+#define ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/buffer.hpp"+#include "asio/detail/assert.hpp"+#include <cstddef>+#include <cstring>+#include <vector>++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class buffered_stream_storage+{+public:+ // The type of the bytes stored in the buffer.+ typedef unsigned char byte_type;++ // The type used for offsets into the buffer.+ typedef std::size_t size_type;++ // Constructor.+ explicit buffered_stream_storage(std::size_t buffer_capacity)+ : begin_offset_(0),+ end_offset_(0),+ buffer_(buffer_capacity)+ {+ }++ /// Clear the buffer.+ void clear()+ {+ begin_offset_ = 0;+ end_offset_ = 0;+ }++ // Return a pointer to the beginning of the unread data.+ mutable_buffer data()+ {+ return asio::buffer(buffer_) + begin_offset_;+ }++ // Return a pointer to the beginning of the unread data.+ const_buffer data() const+ {+ return asio::buffer(buffer_) + begin_offset_;+ }++ // Is there no unread data in the buffer.+ bool empty() const+ {+ return begin_offset_ == end_offset_;+ }++ // Return the amount of unread data the is in the buffer.+ size_type size() const+ {+ return end_offset_ - begin_offset_;+ }++ // Resize the buffer to the specified length.+ void resize(size_type length)+ {+ ASIO_ASSERT(length <= capacity());+ if (begin_offset_ + length <= capacity())+ {+ end_offset_ = begin_offset_ + length;+ }+ else+ {+ using namespace std; // For memmove.+ memmove(&buffer_[0], &buffer_[0] + begin_offset_, size());+ end_offset_ = length;+ begin_offset_ = 0;+ }+ }++ // Return the maximum size for data in the buffer.+ size_type capacity() const+ {+ return buffer_.size();+ }++ // Consume multiple bytes from the beginning of the buffer.+ void consume(size_type count)+ {+ ASIO_ASSERT(begin_offset_ + count <= end_offset_);+ begin_offset_ += count;+ if (empty())+ clear();+ }++private:+ // The offset to the beginning of the unread data.+ size_type begin_offset_;++ // The offset to the end of the unread data.+ size_type end_offset_;+ + // The data in the buffer.+ std::vector<byte_type> buffer_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/bulk_executor_op.hpp view
@@ -0,0 +1,88 @@+//+// detail/bulk_executor_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_BULK_EXECUTOR_OP_HPP+#define ASIO_DETAIL_BULK_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/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/scheduler_operation.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename Alloc,+ typename Operation = scheduler_operation>+class bulk_executor_op : public Operation+{+public:+ ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(bulk_executor_op);++ template <typename H>+ bulk_executor_op(ASIO_MOVE_ARG(H) h,+ const Alloc& allocator, std::size_t i)+ : Operation(&bulk_executor_op::do_complete),+ handler_(ASIO_MOVE_CAST(H)(h)),+ allocator_(allocator),+ index_(i)+ {+ }++ static void do_complete(void* owner, Operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ bulk_executor_op* o(static_cast<bulk_executor_op*>(base));+ Alloc allocator(o->allocator_);+ ptr p = { detail::addressof(allocator), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // 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::binder1<Handler, std::size_t> handler(o->handler_, o->index_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN(());+ asio_handler_invoke_helpers::invoke(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ Alloc allocator_;+ std::size_t index_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_BULK_EXECUTOR_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/call_stack.hpp view
@@ -0,0 +1,125 @@+//+// detail/call_stack.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_CALL_STACK_HPP+#define ASIO_DETAIL_CALL_STACK_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/noncopyable.hpp"+#include "asio/detail/tss_ptr.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Helper class to determine whether or not the current thread is inside an+// invocation of io_context::run() for a specified io_context object.+template <typename Key, typename Value = unsigned char>+class call_stack+{+public:+ // Context class automatically pushes the key/value pair on to the stack.+ class context+ : private noncopyable+ {+ public:+ // Push the key on to the stack.+ explicit context(Key* k)+ : key_(k),+ next_(call_stack<Key, Value>::top_)+ {+ value_ = reinterpret_cast<unsigned char*>(this);+ call_stack<Key, Value>::top_ = this;+ }++ // Push the key/value pair on to the stack.+ context(Key* k, Value& v)+ : key_(k),+ value_(&v),+ next_(call_stack<Key, Value>::top_)+ {+ call_stack<Key, Value>::top_ = this;+ }++ // Pop the key/value pair from the stack.+ ~context()+ {+ call_stack<Key, Value>::top_ = next_;+ }++ // Find the next context with the same key.+ Value* next_by_key() const+ {+ context* elem = next_;+ while (elem)+ {+ if (elem->key_ == key_)+ return elem->value_;+ elem = elem->next_;+ }+ return 0;+ }++ private:+ friend class call_stack<Key, Value>;++ // The key associated with the context.+ Key* key_;++ // The value associated with the context.+ Value* value_;++ // The next element in the stack.+ context* next_;+ };++ friend class context;++ // Determine whether the specified owner is on the stack. Returns address of+ // key if present, 0 otherwise.+ static Value* contains(Key* k)+ {+ context* elem = top_;+ while (elem)+ {+ if (elem->key_ == k)+ return elem->value_;+ elem = elem->next_;+ }+ return 0;+ }++ // Obtain the value at the top of the stack.+ static Value* top()+ {+ context* elem = top_;+ return elem ? elem->value_ : 0;+ }++private:+ // The top of the stack of calls for the current thread.+ static tss_ptr<context> top_;+};++template <typename Key, typename Value>+tss_ptr<typename call_stack<Key, Value>::context>+call_stack<Key, Value>::top_;++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_CALL_STACK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/chrono.hpp view
@@ -0,0 +1,66 @@+//+// detail/chrono.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_CHRONO_HPP+#define ASIO_DETAIL_CHRONO_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_STD_CHRONO)+# include <chrono>+#elif defined(ASIO_HAS_BOOST_CHRONO)+# include <boost/chrono/system_clocks.hpp>+#endif // defined(ASIO_HAS_BOOST_CHRONO)++namespace asio {+namespace chrono {++#if defined(ASIO_HAS_STD_CHRONO)+using std::chrono::duration;+using std::chrono::time_point;+using std::chrono::duration_cast;+using std::chrono::nanoseconds;+using std::chrono::microseconds;+using std::chrono::milliseconds;+using std::chrono::seconds;+using std::chrono::minutes;+using std::chrono::hours;+using std::chrono::time_point_cast;+#if defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)+typedef std::chrono::monotonic_clock steady_clock;+#else // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)+using std::chrono::steady_clock;+#endif // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)+using std::chrono::system_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 asio++#endif // ASIO_DETAIL_CHRONO_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/chrono_time_traits.hpp view
@@ -0,0 +1,190 @@+//+// detail/chrono_time_traits.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_CHRONO_TIME_TRAITS_HPP+#define ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/cstdint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Helper template to compute the greatest common divisor.+template <int64_t v1, int64_t v2>+struct gcd { enum { value = gcd<v2, v1 % v2>::value }; };++template <int64_t v1>+struct gcd<v1, 0> { enum { value = v1 }; };++// Adapts std::chrono clocks for use with a deadline timer.+template <typename Clock, typename WaitTraits>+struct chrono_time_traits+{+ // The clock type.+ typedef Clock clock_type;++ // The duration type of the clock.+ typedef typename clock_type::duration duration_type;++ // The time point type of the clock.+ typedef typename clock_type::time_point time_type;++ // The period of the clock.+ typedef typename duration_type::period period_type;++ // Get the current time.+ static time_type now()+ {+ return clock_type::now();+ }++ // Add a duration to a time.+ static time_type add(const time_type& t, const duration_type& d)+ {+ const time_type epoch;+ if (t >= epoch)+ {+ if ((time_type::max)() - t < d)+ return (time_type::max)();+ }+ else // t < epoch+ {+ if (-(t - (time_type::min)()) > d)+ return (time_type::min)();+ }++ return t + d;+ }++ // Subtract one time from another.+ static duration_type subtract(const time_type& t1, const time_type& t2)+ {+ const time_type epoch;+ if (t1 >= epoch)+ {+ if (t2 >= epoch)+ {+ return t1 - t2;+ }+ else if (t2 == (time_type::min)())+ {+ return (duration_type::max)();+ }+ else if ((time_type::max)() - t1 < epoch - t2)+ {+ return (duration_type::max)();+ }+ else+ {+ return t1 - t2;+ }+ }+ else // t1 < epoch+ {+ if (t2 < epoch)+ {+ return t1 - t2;+ }+ else if (t1 == (time_type::min)())+ {+ return (duration_type::min)();+ }+ else if ((time_type::max)() - t2 < epoch - t1)+ {+ return (duration_type::min)();+ }+ else+ {+ return -(t2 - t1);+ }+ }+ }++ // Test whether one time is less than another.+ static bool less_than(const time_type& t1, const time_type& t2)+ {+ return t1 < t2;+ }++ // Implement just enough of the posix_time::time_duration interface to supply+ // what the timer_queue requires.+ class posix_time_duration+ {+ public:+ explicit posix_time_duration(const duration_type& d)+ : d_(d)+ {+ }++ int64_t ticks() const+ {+ return d_.count();+ }++ int64_t total_seconds() const+ {+ return duration_cast<1, 1>();+ }++ int64_t total_milliseconds() const+ {+ return duration_cast<1, 1000>();+ }++ int64_t total_microseconds() const+ {+ return duration_cast<1, 1000000>();+ }++ private:+ template <int64_t Num, int64_t Den>+ int64_t duration_cast() const+ {+ const int64_t num1 = period_type::num / gcd<period_type::num, Num>::value;+ const int64_t num2 = Num / gcd<period_type::num, Num>::value;++ const int64_t den1 = period_type::den / gcd<period_type::den, Den>::value;+ const int64_t den2 = Den / gcd<period_type::den, Den>::value;++ const int64_t num = num1 * den2;+ const int64_t den = num2 * den1;++ if (num == 1 && den == 1)+ return ticks();+ else if (num != 1 && den == 1)+ return ticks() * num;+ else if (num == 1 && period_type::den != 1)+ return ticks() / den;+ else+ return ticks() * num / den;+ }++ duration_type d_;+ };++ // Convert to POSIX duration type.+ static posix_time_duration to_posix_duration(const duration_type& d)+ {+ return posix_time_duration(WaitTraits::to_wait_duration(d));+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/completion_handler.hpp view
@@ -0,0 +1,88 @@+//+// detail/completion_handler.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_COMPLETION_HANDLER_HPP+#define ASIO_DETAIL_COMPLETION_HANDLER_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/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/operation.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename IoExecutor>+class completion_handler : public operation+{+public:+ ASIO_DEFINE_HANDLER_PTR(completion_handler);++ completion_handler(Handler& h, const IoExecutor& io_ex)+ : operation(&completion_handler::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(h)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ completion_handler* h(static_cast<completion_handler*>(base));+ ptr p = { asio::detail::addressof(h->handler_), h, h };++ ASIO_HANDLER_COMPLETION((*h));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ h->work_));++ // 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.+ Handler handler(ASIO_MOVE_CAST(Handler)(h->handler_));+ p.h = asio::detail::addressof(handler);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN(());+ w.complete(handler, handler);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_COMPLETION_HANDLER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/concurrency_hint.hpp view
@@ -0,0 +1,94 @@+//+// detail/concurrency_hint.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_CONCURRENCY_HINT_HPP+#define ASIO_DETAIL_CONCURRENCY_HINT_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/noncopyable.hpp"++// The concurrency hint ID and mask are used to identify when a "well-known"+// concurrency hint value has been passed to the io_context.+#define ASIO_CONCURRENCY_HINT_ID 0xA5100000u+#define ASIO_CONCURRENCY_HINT_ID_MASK 0xFFFF0000u++// If set, this bit indicates that the scheduler should perform locking.+#define ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER 0x1u++// If set, this bit indicates that the reactor should perform locking when+// managing descriptor registrations.+#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION 0x2u++// If set, this bit indicates that the reactor should perform locking for I/O.+#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO 0x4u++// Helper macro to determine if we have a special concurrency hint.+#define ASIO_CONCURRENCY_HINT_IS_SPECIAL(hint) \+ ((static_cast<unsigned>(hint) \+ & ASIO_CONCURRENCY_HINT_ID_MASK) \+ == ASIO_CONCURRENCY_HINT_ID)++// Helper macro to determine if locking is enabled for a given facility.+#define ASIO_CONCURRENCY_HINT_IS_LOCKING(facility, hint) \+ (((static_cast<unsigned>(hint) \+ & (ASIO_CONCURRENCY_HINT_ID_MASK \+ | ASIO_CONCURRENCY_HINT_LOCKING_ ## facility)) \+ ^ ASIO_CONCURRENCY_HINT_ID) != 0)++// This special concurrency hint disables locking in both the scheduler and+// reactor I/O. This hint has the following restrictions:+//+// - Care must be taken to ensure that all operations on the io_context and any+// of its associated I/O objects (such as sockets and timers) occur in only+// one thread at a time.+//+// - Asynchronous resolve operations fail with operation_not_supported.+//+// - If a signal_set is used with the io_context, signal_set objects cannot be+// used with any other io_context in the program.+#define ASIO_CONCURRENCY_HINT_UNSAFE \+ static_cast<int>(ASIO_CONCURRENCY_HINT_ID)++// This special concurrency hint disables locking in the reactor I/O. This hint+// has the following restrictions:+//+// - Care must be taken to ensure that run functions on the io_context, and all+// operations on the io_context's associated I/O objects (such as sockets and+// timers), occur in only one thread at a time.+#define ASIO_CONCURRENCY_HINT_UNSAFE_IO \+ static_cast<int>(ASIO_CONCURRENCY_HINT_ID \+ | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \+ | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION)++// The special concurrency hint provides full thread safety.+#define ASIO_CONCURRENCY_HINT_SAFE \+ static_cast<int>(ASIO_CONCURRENCY_HINT_ID \+ | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \+ | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION \+ | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO)++// This #define may be overridden at compile time to specify a program-wide+// default concurrency hint, used by the zero-argument io_context constructor.+#if !defined(ASIO_CONCURRENCY_HINT_DEFAULT)+# define ASIO_CONCURRENCY_HINT_DEFAULT -1+#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT)++// This #define may be overridden at compile time to specify a program-wide+// concurrency hint, used by the one-argument io_context constructor when+// passed a value of 1.+#if !defined(ASIO_CONCURRENCY_HINT_1)+# define ASIO_CONCURRENCY_HINT_1 1+#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT)++#endif // ASIO_DETAIL_CONCURRENCY_HINT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/conditionally_enabled_event.hpp view
@@ -0,0 +1,120 @@+//+// detail/conditionally_enabled_event.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_CONDITIONALLY_ENABLED_EVENT_HPP+#define ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_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/conditionally_enabled_mutex.hpp"+#include "asio/detail/event.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/null_event.hpp"+#include "asio/detail/scoped_lock.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Mutex adapter used to conditionally enable or disable locking.+class conditionally_enabled_event+ : private noncopyable+{+public:+ // Constructor.+ conditionally_enabled_event()+ {+ }++ // Destructor.+ ~conditionally_enabled_event()+ {+ }++ // Signal the event. (Retained for backward compatibility.)+ void signal(conditionally_enabled_mutex::scoped_lock& lock)+ {+ if (lock.mutex_.enabled_)+ event_.signal(lock);+ }++ // Signal all waiters.+ void signal_all(conditionally_enabled_mutex::scoped_lock& lock)+ {+ if (lock.mutex_.enabled_)+ event_.signal_all(lock);+ }++ // Unlock the mutex and signal one waiter.+ void unlock_and_signal_one(+ conditionally_enabled_mutex::scoped_lock& lock)+ {+ if (lock.mutex_.enabled_)+ 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.+ bool maybe_unlock_and_signal_one(+ conditionally_enabled_mutex::scoped_lock& lock)+ {+ if (lock.mutex_.enabled_)+ return event_.maybe_unlock_and_signal_one(lock);+ else+ return false;+ }++ // Reset the event.+ void clear(conditionally_enabled_mutex::scoped_lock& lock)+ {+ if (lock.mutex_.enabled_)+ event_.clear(lock);+ }++ // Wait for the event to become signalled.+ void wait(conditionally_enabled_mutex::scoped_lock& lock)+ {+ if (lock.mutex_.enabled_)+ event_.wait(lock);+ else+ null_event().wait(lock);+ }++ // Timed wait for the event to become signalled.+ bool wait_for_usec(+ conditionally_enabled_mutex::scoped_lock& lock, long usec)+ {+ if (lock.mutex_.enabled_)+ return event_.wait_for_usec(lock, usec);+ else+ return null_event().wait_for_usec(lock, usec);+ }++private:+ asio::detail::event event_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/conditionally_enabled_mutex.hpp view
@@ -0,0 +1,149 @@+//+// detail/conditionally_enabled_mutex.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_CONDITIONALLY_ENABLED_MUTEX_HPP+#define ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_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/mutex.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/scoped_lock.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Mutex adapter used to conditionally enable or disable locking.+class conditionally_enabled_mutex+ : private noncopyable+{+public:+ // Helper class to lock and unlock a mutex automatically.+ class scoped_lock+ : private noncopyable+ {+ public:+ // Tag type used to distinguish constructors.+ enum adopt_lock_t { adopt_lock };++ // Constructor adopts a lock that is already held.+ scoped_lock(conditionally_enabled_mutex& m, adopt_lock_t)+ : mutex_(m),+ locked_(m.enabled_)+ {+ }++ // Constructor acquires the lock.+ explicit scoped_lock(conditionally_enabled_mutex& m)+ : mutex_(m)+ {+ if (m.enabled_)+ {+ mutex_.mutex_.lock();+ locked_ = true;+ }+ else+ locked_ = false;+ }++ // Destructor releases the lock.+ ~scoped_lock()+ {+ if (locked_)+ mutex_.mutex_.unlock();+ }++ // Explicitly acquire the lock.+ void lock()+ {+ if (mutex_.enabled_ && !locked_)+ {+ mutex_.mutex_.lock();+ locked_ = true;+ }+ }++ // Explicitly release the lock.+ void unlock()+ {+ if (locked_)+ {+ mutex_.unlock();+ locked_ = false;+ }+ }++ // Test whether the lock is held.+ bool locked() const+ {+ return locked_;+ }++ // Get the underlying mutex.+ asio::detail::mutex& mutex()+ {+ return mutex_.mutex_;+ }++ private:+ friend class conditionally_enabled_event;+ conditionally_enabled_mutex& mutex_;+ bool locked_;+ };++ // Constructor.+ explicit conditionally_enabled_mutex(bool enabled)+ : enabled_(enabled)+ {+ }++ // Destructor.+ ~conditionally_enabled_mutex()+ {+ }++ // Determine whether locking is enabled.+ bool enabled() const+ {+ return enabled_;+ }++ // Lock the mutex.+ void lock()+ {+ if (enabled_)+ mutex_.lock();+ }++ // Unlock the mutex.+ void unlock()+ {+ if (enabled_)+ mutex_.unlock();+ }++private:+ friend class scoped_lock;+ friend class conditionally_enabled_event;+ asio::detail::mutex mutex_;+ const bool enabled_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/config.hpp view
@@ -0,0 +1,1822 @@+//+// detail/config.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_CONFIG_HPP+#define ASIO_DETAIL_CONFIG_HPP++// boostify: non-boost code starts here+#if !defined(ASIO_STANDALONE)+# if !defined(ASIO_ENABLE_BOOST)+# if (__cplusplus >= 201103)+# define ASIO_STANDALONE 1+# elif defined(_MSC_VER) && defined(_MSVC_LANG)+# if (_MSC_VER >= 1900) && (_MSVC_LANG >= 201103)+# define ASIO_STANDALONE 1+# endif // (_MSC_VER >= 1900) && (_MSVC_LANG >= 201103)+# endif // defined(_MSC_VER) && defined(_MSVC_LANG)+# endif // !defined(ASIO_ENABLE_BOOST)+#endif // !defined(ASIO_STANDALONE)++// boostify: non-boost code ends here+#if defined(ASIO_STANDALONE)+# define ASIO_DISABLE_BOOST_ARRAY 1+# define ASIO_DISABLE_BOOST_ASSERT 1+# define ASIO_DISABLE_BOOST_BIND 1+# define ASIO_DISABLE_BOOST_CHRONO 1+# define ASIO_DISABLE_BOOST_DATE_TIME 1+# define ASIO_DISABLE_BOOST_LIMITS 1+# define ASIO_DISABLE_BOOST_REGEX 1+# define ASIO_DISABLE_BOOST_STATIC_CONSTANT 1+# define ASIO_DISABLE_BOOST_THROW_EXCEPTION 1+# define ASIO_DISABLE_BOOST_WORKAROUND 1+#else // defined(ASIO_STANDALONE)+# include <boost/config.hpp>+# include <boost/version.hpp>+# define ASIO_HAS_BOOST_CONFIG 1+#endif // defined(ASIO_STANDALONE)++// Default to a header-only implementation. The user must specifically request+// separate compilation by defining either ASIO_SEPARATE_COMPILATION or+// ASIO_DYN_LINK (as a DLL/shared library implies separate compilation).+#if !defined(ASIO_HEADER_ONLY)+# if !defined(ASIO_SEPARATE_COMPILATION)+# if !defined(ASIO_DYN_LINK)+# define ASIO_HEADER_ONLY 1+# endif // !defined(ASIO_DYN_LINK)+# endif // !defined(ASIO_SEPARATE_COMPILATION)+#endif // !defined(ASIO_HEADER_ONLY)++#if defined(ASIO_HEADER_ONLY)+# define ASIO_DECL inline+#else // defined(ASIO_HEADER_ONLY)+# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__)+// We need to import/export our code only if the user has specifically asked+// for it by defining ASIO_DYN_LINK.+# if defined(ASIO_DYN_LINK)+// Export if this is our own source, otherwise import.+# if defined(ASIO_SOURCE)+# define ASIO_DECL __declspec(dllexport)+# else // defined(ASIO_SOURCE)+# define ASIO_DECL __declspec(dllimport)+# endif // defined(ASIO_SOURCE)+# endif // defined(ASIO_DYN_LINK)+# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__)+#endif // defined(ASIO_HEADER_ONLY)++// If ASIO_DECL isn't defined yet define it now.+#if !defined(ASIO_DECL)+# define ASIO_DECL+#endif // !defined(ASIO_DECL)++// Helper macro for documentation.+#define ASIO_UNSPECIFIED(e) e++// Microsoft Visual C++ detection.+#if !defined(ASIO_MSVC)+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC)+# define ASIO_MSVC BOOST_MSVC+# elif defined(_MSC_VER) && (defined(__INTELLISENSE__) \+ || (!defined(__MWERKS__) && !defined(__EDG_VERSION__)))+# define ASIO_MSVC _MSC_VER+# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC)+#endif // !defined(ASIO_MSVC)++// Clang / libc++ detection.+#if defined(__clang__)+# if (__cplusplus >= 201103)+# if __has_include(<__config>)+# include <__config>+# if defined(_LIBCPP_VERSION)+# define ASIO_HAS_CLANG_LIBCXX 1+# endif // defined(_LIBCPP_VERSION)+# endif // __has_include(<__config>)+# endif // (__cplusplus >= 201103)+#endif // defined(__clang__)++// Android platform detection.+#if defined(__ANDROID__)+# include <android/api-level.h>+#endif // defined(__ANDROID__)++// Support move construction and assignment on compilers known to allow it.+#if !defined(ASIO_HAS_MOVE)+# if !defined(ASIO_DISABLE_MOVE)+# if defined(__clang__)+# if __has_feature(__cxx_rvalue_references__)+# define ASIO_HAS_MOVE 1+# endif // __has_feature(__cxx_rvalue_references__)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_MOVE 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_MOVE 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# if defined(__INTEL_CXX11_MODE__)+# if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500)+# define ASIO_HAS_MOVE 1+# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500)+# if defined(__ICL) && (__ICL >= 1500)+# define ASIO_HAS_MOVE 1+# endif // defined(__ICL) && (__ICL >= 1500)+# endif // defined(__INTEL_CXX11_MODE__)+# endif // !defined(ASIO_DISABLE_MOVE)+#endif // !defined(ASIO_HAS_MOVE)++// If ASIO_MOVE_CAST isn't defined, and move support is available, define+// * ASIO_MOVE_ARG,+// * ASIO_NONDEDUCED_MOVE_ARG, and+// * ASIO_MOVE_CAST+// to take advantage of rvalue references and perfect forwarding.+#if defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST)+# define ASIO_MOVE_ARG(type) type&&+# define ASIO_MOVE_ARG2(type1, type2) type1, type2&&+# define ASIO_NONDEDUCED_MOVE_ARG(type) type&+# define ASIO_MOVE_CAST(type) static_cast<type&&>+# define ASIO_MOVE_CAST2(type1, type2) static_cast<type1, type2&&>+# define ASIO_MOVE_OR_LVALUE(type) static_cast<type&&>+# define ASIO_MOVE_OR_LVALUE_TYPE(type) type+#endif // defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST)++// If ASIO_MOVE_CAST still isn't defined, default to a C++03-compatible+// implementation. Note that older g++ and MSVC versions don't like it when you+// pass a non-member function through a const reference, so for most compilers+// we'll play it safe and stick with the old approach of passing the handler by+// value.+#if !defined(ASIO_MOVE_CAST)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4)+# define ASIO_MOVE_ARG(type) const type&+# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4)+# define ASIO_MOVE_ARG(type) type+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4)+# elif defined(ASIO_MSVC)+# if (_MSC_VER >= 1400)+# define ASIO_MOVE_ARG(type) const type&+# else // (_MSC_VER >= 1400)+# define ASIO_MOVE_ARG(type) type+# endif // (_MSC_VER >= 1400)+# else+# define ASIO_MOVE_ARG(type) type+# endif+# define ASIO_NONDEDUCED_MOVE_ARG(type) const type&+# define ASIO_MOVE_CAST(type) static_cast<const type&>+# define ASIO_MOVE_CAST2(type1, type2) static_cast<const type1, type2&>+# define ASIO_MOVE_OR_LVALUE(type)+# define ASIO_MOVE_OR_LVALUE_TYPE(type) type&+#endif // !defined(ASIO_MOVE_CAST)++// Support variadic templates on compilers known to allow it.+#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)+# if !defined(ASIO_DISABLE_VARIADIC_TEMPLATES)+# if defined(__clang__)+# if __has_feature(__cxx_variadic_templates__)+# define ASIO_HAS_VARIADIC_TEMPLATES 1+# endif // __has_feature(__cxx_variadic_templates__)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_VARIADIC_TEMPLATES 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1900)+# define ASIO_HAS_VARIADIC_TEMPLATES 1+# endif // (_MSC_VER >= 1900)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_VARIADIC_TEMPLATES)+#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)+#if !defined(ASIO_ELLIPSIS)+# if defined(ASIO_HAS_VARIADIC_TEMPLATES)+# define ASIO_ELLIPSIS ...+# else // defined(ASIO_HAS_VARIADIC_TEMPLATES)+# define ASIO_ELLIPSIS+# endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+#endif // !defined(ASIO_ELLIPSIS)++// Support deleted functions on compilers known to allow it.+#if !defined(ASIO_DELETED)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_DELETED = delete+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(__clang__)+# if __has_feature(__cxx_deleted_functions__)+# define ASIO_DELETED = delete+# endif // __has_feature(__cxx_deleted_functions__)+# endif // defined(__clang__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1900)+# define ASIO_DELETED = delete+# endif // (_MSC_VER >= 1900)+# endif // defined(ASIO_MSVC)+# if !defined(ASIO_DELETED)+# define ASIO_DELETED+# endif // !defined(ASIO_DELETED)+#endif // !defined(ASIO_DELETED)++// Support constexpr on compilers known to allow it.+#if !defined(ASIO_HAS_CONSTEXPR)+# if !defined(ASIO_DISABLE_CONSTEXPR)+# if defined(__clang__)+# if __has_feature(__cxx_constexpr__)+# define ASIO_HAS_CONSTEXPR 1+# endif // __has_feature(__cxx_constexpr__)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_CONSTEXPR 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1900)+# define ASIO_HAS_CONSTEXPR 1+# endif // (_MSC_VER >= 1900)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_CONSTEXPR)+#endif // !defined(ASIO_HAS_CONSTEXPR)+#if !defined(ASIO_CONSTEXPR)+# if defined(ASIO_HAS_CONSTEXPR)+# define ASIO_CONSTEXPR constexpr+# else // defined(ASIO_HAS_CONSTEXPR)+# define ASIO_CONSTEXPR+# endif // defined(ASIO_HAS_CONSTEXPR)+#endif // !defined(ASIO_CONSTEXPR)+#if !defined(ASIO_STATIC_CONSTEXPR)+# if defined(ASIO_HAS_CONSTEXPR)+# define ASIO_STATIC_CONSTEXPR(type, assignment) \+ static constexpr type assignment+# else // defined(ASIO_HAS_CONSTEXPR)+# define ASIO_STATIC_CONSTEXPR(type, assignment) \+ static const type assignment+# endif // defined(ASIO_HAS_CONSTEXPR)+#endif // !defined(ASIO_STATIC_CONSTEXPR)+#if !defined(ASIO_STATIC_CONSTEXPR_DEFAULT_INIT)+# if defined(ASIO_HAS_CONSTEXPR)+# if defined(__GNUC__)+# if (__GNUC__ >= 8)+# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \+ static constexpr const type name{}+# else // (__GNUC__ >= 8)+# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \+ static const type name+# endif // (__GNUC__ >= 8)+# elif defined(ASIO_MSVC)+# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \+ static const type name+# else // defined(ASIO_MSVC)+# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \+ static constexpr const type name{}+# endif // defined(ASIO_MSVC)+# else // defined(ASIO_HAS_CONSTEXPR)+# define ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \+ static const type name+# endif // defined(ASIO_HAS_CONSTEXPR)+#endif // !defined(ASIO_STATIC_CONSTEXPR_DEFAULT_INIT)++// Support noexcept on compilers known to allow it.+#if !defined(ASIO_HAS_NOEXCEPT)+# if !defined(ASIO_DISABLE_NOEXCEPT)+# if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300)+# if !defined(BOOST_NO_NOEXCEPT)+# define ASIO_HAS_NOEXCEPT 1+# endif // !defined(BOOST_NO_NOEXCEPT)+# define ASIO_NOEXCEPT BOOST_NOEXCEPT+# define ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW+# define ASIO_NOEXCEPT_IF(c) BOOST_NOEXCEPT_IF(c)+# elif defined(__clang__)+# if __has_feature(__cxx_noexcept__)+# define ASIO_HAS_NOEXCEPT 1+# endif // __has_feature(__cxx_noexcept__)+# elif defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_NOEXCEPT 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# elif defined(ASIO_MSVC)+# if (_MSC_VER >= 1900)+# define ASIO_HAS_NOEXCEPT 1+# endif // (_MSC_VER >= 1900)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_NOEXCEPT)+# if !defined(ASIO_NOEXCEPT)+# endif // !defined(ASIO_NOEXCEPT)+# if !defined(ASIO_NOEXCEPT_OR_NOTHROW)+# endif // !defined(ASIO_NOEXCEPT_OR_NOTHROW)+#endif // !defined(ASIO_HAS_NOEXCEPT)+#if !defined(ASIO_NOEXCEPT)+# if defined(ASIO_HAS_NOEXCEPT)+# define ASIO_NOEXCEPT noexcept(true)+# else // defined(ASIO_HAS_NOEXCEPT)+# define ASIO_NOEXCEPT+# endif // defined(ASIO_HAS_NOEXCEPT)+#endif // !defined(ASIO_NOEXCEPT)+#if !defined(ASIO_NOEXCEPT_OR_NOTHROW)+# if defined(ASIO_HAS_NOEXCEPT)+# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)+# else // defined(ASIO_HAS_NOEXCEPT)+# define ASIO_NOEXCEPT_OR_NOTHROW throw()+# endif // defined(ASIO_HAS_NOEXCEPT)+#endif // !defined(ASIO_NOEXCEPT_OR_NOTHROW)+#if !defined(ASIO_NOEXCEPT_IF)+# if defined(ASIO_HAS_NOEXCEPT)+# define ASIO_NOEXCEPT_IF(c) noexcept(c)+# else // defined(ASIO_HAS_NOEXCEPT)+# define ASIO_NOEXCEPT_IF(c)+# endif // defined(ASIO_HAS_NOEXCEPT)+#endif // !defined(ASIO_NOEXCEPT_IF)++// Support automatic type deduction on compilers known to support it.+#if !defined(ASIO_HAS_DECLTYPE)+# if !defined(ASIO_DISABLE_DECLTYPE)+# if defined(__clang__)+# if __has_feature(__cxx_decltype__)+# define ASIO_HAS_DECLTYPE 1+# endif // __has_feature(__cxx_decltype__)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_DECLTYPE 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1800)+# define ASIO_HAS_DECLTYPE 1+# endif // (_MSC_VER >= 1800)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_DECLTYPE)+#endif // !defined(ASIO_HAS_DECLTYPE)++// Support alias templates on compilers known to allow it.+#if !defined(ASIO_HAS_ALIAS_TEMPLATES)+# if !defined(ASIO_DISABLE_ALIAS_TEMPLATES)+# if defined(__clang__)+# if __has_feature(__cxx_alias_templates__)+# define ASIO_HAS_ALIAS_TEMPLATES 1+# endif // __has_feature(__cxx_alias_templates__)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_ALIAS_TEMPLATES 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1900)+# define ASIO_HAS_ALIAS_TEMPLATES 1+# endif // (_MSC_VER >= 1900)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_ALIAS_TEMPLATES)+#endif // !defined(ASIO_HAS_ALIAS_TEMPLATES)++// Support return type deduction on compilers known to allow it.+#if !defined(ASIO_HAS_RETURN_TYPE_DEDUCTION)+# if !defined(ASIO_DISABLE_RETURN_TYPE_DEDUCTION)+# if defined(__clang__)+# if __has_feature(__cxx_return_type_deduction__)+# define ASIO_HAS_RETURN_TYPE_DEDUCTION 1+# endif // __has_feature(__cxx_return_type_deduction__)+# elif (__cplusplus >= 201402)+# define ASIO_HAS_RETURN_TYPE_DEDUCTION 1+# elif defined(__cpp_return_type_deduction)+# if (__cpp_return_type_deduction >= 201304)+# define ASIO_HAS_RETURN_TYPE_DEDUCTION 1+# endif // (__cpp_return_type_deduction >= 201304)+# endif // defined(__cpp_return_type_deduction)+# endif // !defined(ASIO_DISABLE_RETURN_TYPE_DEDUCTION)+#endif // !defined(ASIO_HAS_RETURN_TYPE_DEDUCTION)++// Support default function template arguments on compilers known to allow it.+#if !defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)+# if !defined(ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)+# if (__cplusplus >= 201103)+# define ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1+# endif // (__cplusplus >= 201103)+# endif // !defined(ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)+#endif // !defined(ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS)++// Support concepts on compilers known to allow them.+#if !defined(ASIO_HAS_CONCEPTS)+# if !defined(ASIO_DISABLE_CONCEPTS)+# if defined(__cpp_concepts)+# define ASIO_HAS_CONCEPTS 1+# if (__cpp_concepts >= 201707)+# define ASIO_CONCEPT concept+# else // (__cpp_concepts >= 201707)+# define ASIO_CONCEPT concept bool+# endif // (__cpp_concepts >= 201707)+# endif // defined(__cpp_concepts)+# endif // !defined(ASIO_DISABLE_CONCEPTS)+#endif // !defined(ASIO_HAS_CONCEPTS)++// Support template variables on compilers known to allow it.+#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)+# if !defined(ASIO_DISABLE_VARIABLE_TEMPLATES)+# if defined(__clang__)+# if (__cplusplus >= 201402)+# if __has_feature(__cxx_variable_templates__)+# define ASIO_HAS_VARIABLE_TEMPLATES 1+# endif // __has_feature(__cxx_variable_templates__)+# endif // (__cplusplus >= 201402)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if (__GNUC__ >= 6)+# if (__cplusplus >= 201402)+# define ASIO_HAS_VARIABLE_TEMPLATES 1+# endif // (__cplusplus >= 201402)+# endif // (__GNUC__ >= 6)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1901)+# define ASIO_HAS_VARIABLE_TEMPLATES 1+# endif // (_MSC_VER >= 1901)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_VARIABLE_TEMPLATES)+#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)++// Support SFINAEd template variables on compilers known to allow it.+#if !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+# if !defined(ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES)+# if defined(__clang__)+# if (__cplusplus >= 201703)+# if __has_feature(__cxx_variable_templates__)+# define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1+# endif // __has_feature(__cxx_variable_templates__)+# endif // (__cplusplus >= 201703)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8)+# if (__cplusplus >= 201402)+# define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1+# endif // (__cplusplus >= 201402)+# endif // ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1901)+# define ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1+# endif // (_MSC_VER >= 1901)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES)+#endif // !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++// Support SFINAE use of constant expressions on compilers known to allow it.+#if !defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE)+# if !defined(ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE)+# if defined(__clang__)+# if (__cplusplus >= 201402)+# define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1+# endif // (__cplusplus >= 201402)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if (__GNUC__ >= 7)+# if (__cplusplus >= 201402)+# define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1+# endif // (__cplusplus >= 201402)+# endif // (__GNUC__ >= 7)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1901)+# define ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1+# endif // (_MSC_VER >= 1901)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE)+#endif // !defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE)++// Enable workarounds for lack of working expression SFINAE.+#if !defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# if !defined(ASIO_DISABLE_WORKING_EXPRESSION_SFINAE)+# if !defined(ASIO_MSVC)+# if (__cplusplus >= 201103)+# define ASIO_HAS_WORKING_EXPRESSION_SFINAE 1+# endif // (__cplusplus >= 201103)+# endif // !defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_WORKING_EXPRESSION_SFINAE)+#endif // !defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++// Support ref-qualified functions on compilers known to allow it.+#if !defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS)+# if !defined(ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS)+# if defined(__clang__)+# if __has_feature(__cxx_reference_qualified_functions__)+# define ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1+# endif // __has_feature(__cxx_reference_qualified_functions__)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1900)+# define ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1+# endif // (_MSC_VER >= 1900)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS)+#endif // !defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS)+#if defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS)+# if !defined(ASIO_LVALUE_REF_QUAL)+# define ASIO_LVALUE_REF_QUAL &+# endif // !defined(ASIO_LVALUE_REF_QUAL)+# if !defined(ASIO_RVALUE_REF_QUAL)+# define ASIO_RVALUE_REF_QUAL &&+# endif // !defined(ASIO_RVALUE_REF_QUAL)+#else // defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS)+# if !defined(ASIO_LVALUE_REF_QUAL)+# define ASIO_LVALUE_REF_QUAL+# endif // !defined(ASIO_LVALUE_REF_QUAL)+# if !defined(ASIO_RVALUE_REF_QUAL)+# define ASIO_RVALUE_REF_QUAL+# endif // !defined(ASIO_RVALUE_REF_QUAL)+#endif // defined(ASIO_HAS_REF_QUALIFIED_FUNCTIONS)++// Standard library support for system errors.+#if !defined(ASIO_HAS_STD_SYSTEM_ERROR)+# if !defined(ASIO_DISABLE_STD_SYSTEM_ERROR)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_SYSTEM_ERROR 1+# elif (__cplusplus >= 201103)+# if __has_include(<system_error>)+# define ASIO_HAS_STD_SYSTEM_ERROR 1+# endif // __has_include(<system_error>)+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_SYSTEM_ERROR 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_STD_SYSTEM_ERROR 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_SYSTEM_ERROR)+#endif // !defined(ASIO_HAS_STD_SYSTEM_ERROR)++// Compliant C++11 compilers put noexcept specifiers on error_category members.+#if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)+# if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300)+# define ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT+# elif defined(__clang__)+# if __has_feature(__cxx_noexcept__)+# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)+# endif // __has_feature(__cxx_noexcept__)+# elif defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# elif defined(ASIO_MSVC)+# if (_MSC_VER >= 1900)+# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)+# endif // (_MSC_VER >= 1900)+# endif // defined(ASIO_MSVC)+# if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)+# define ASIO_ERROR_CATEGORY_NOEXCEPT+# endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)+#endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)++// Standard library support for arrays.+#if !defined(ASIO_HAS_STD_ARRAY)+# if !defined(ASIO_DISABLE_STD_ARRAY)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_ARRAY 1+# elif (__cplusplus >= 201103)+# if __has_include(<array>)+# define ASIO_HAS_STD_ARRAY 1+# endif // __has_include(<array>)+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_ARRAY 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1600)+# define ASIO_HAS_STD_ARRAY 1+# endif // (_MSC_VER >= 1600)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_ARRAY)+#endif // !defined(ASIO_HAS_STD_ARRAY)++// Standard library support for shared_ptr and weak_ptr.+#if !defined(ASIO_HAS_STD_SHARED_PTR)+# if !defined(ASIO_DISABLE_STD_SHARED_PTR)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_SHARED_PTR 1+# elif (__cplusplus >= 201103)+# define ASIO_HAS_STD_SHARED_PTR 1+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_SHARED_PTR 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1600)+# define ASIO_HAS_STD_SHARED_PTR 1+# endif // (_MSC_VER >= 1600)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_SHARED_PTR)+#endif // !defined(ASIO_HAS_STD_SHARED_PTR)++// Standard library support for allocator_arg_t.+#if !defined(ASIO_HAS_STD_ALLOCATOR_ARG)+# if !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_ALLOCATOR_ARG 1+# elif (__cplusplus >= 201103)+# define ASIO_HAS_STD_ALLOCATOR_ARG 1+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_ALLOCATOR_ARG 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1600)+# define ASIO_HAS_STD_ALLOCATOR_ARG 1+# endif // (_MSC_VER >= 1600)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG)+#endif // !defined(ASIO_HAS_STD_ALLOCATOR_ARG)++// Standard library support for atomic operations.+#if !defined(ASIO_HAS_STD_ATOMIC)+# if !defined(ASIO_DISABLE_STD_ATOMIC)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_ATOMIC 1+# elif (__cplusplus >= 201103)+# if __has_include(<atomic>)+# define ASIO_HAS_STD_ATOMIC 1+# endif // __has_include(<atomic>)+# elif defined(__apple_build_version__) && defined(_LIBCPP_VERSION)+# if (__clang_major__ >= 10)+# if __has_include(<atomic>)+# define ASIO_HAS_STD_ATOMIC 1+# endif // __has_include(<atomic>)+# endif // (__clang_major__ >= 10)+# endif // defined(__apple_build_version__) && defined(_LIBCPP_VERSION)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_ATOMIC 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_STD_ATOMIC 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_ATOMIC)+#endif // !defined(ASIO_HAS_STD_ATOMIC)++// Standard library support for chrono. Some standard libraries (such as the+// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x+// drafts, rather than the eventually standardised name of steady_clock.+#if !defined(ASIO_HAS_STD_CHRONO)+# if !defined(ASIO_DISABLE_STD_CHRONO)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_CHRONO 1+# elif (__cplusplus >= 201103)+# if __has_include(<chrono>)+# define ASIO_HAS_STD_CHRONO 1+# endif // __has_include(<chrono>)+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_CHRONO 1+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6))+# define ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK 1+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6))+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_STD_CHRONO 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_CHRONO)+#endif // !defined(ASIO_HAS_STD_CHRONO)++// Boost support for chrono.+#if !defined(ASIO_HAS_BOOST_CHRONO)+# if !defined(ASIO_DISABLE_BOOST_CHRONO)+# if defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700)+# define ASIO_HAS_BOOST_CHRONO 1+# endif // defined(ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700)+# endif // !defined(ASIO_DISABLE_BOOST_CHRONO)+#endif // !defined(ASIO_HAS_BOOST_CHRONO)++// Some form of chrono library is available.+#if !defined(ASIO_HAS_CHRONO)+# if defined(ASIO_HAS_STD_CHRONO) \+ || defined(ASIO_HAS_BOOST_CHRONO)+# define ASIO_HAS_CHRONO 1+# endif // defined(ASIO_HAS_STD_CHRONO)+ // || defined(ASIO_HAS_BOOST_CHRONO)+#endif // !defined(ASIO_HAS_CHRONO)++// Boost support for the DateTime library.+#if !defined(ASIO_HAS_BOOST_DATE_TIME)+# if !defined(ASIO_DISABLE_BOOST_DATE_TIME)+# define ASIO_HAS_BOOST_DATE_TIME 1+# endif // !defined(ASIO_DISABLE_BOOST_DATE_TIME)+#endif // !defined(ASIO_HAS_BOOST_DATE_TIME)++// Standard library support for addressof.+#if !defined(ASIO_HAS_STD_ADDRESSOF)+# if !defined(ASIO_DISABLE_STD_ADDRESSOF)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_ADDRESSOF 1+# elif (__cplusplus >= 201103)+# define ASIO_HAS_STD_ADDRESSOF 1+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_ADDRESSOF 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_STD_ADDRESSOF 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_ADDRESSOF)+#endif // !defined(ASIO_HAS_STD_ADDRESSOF)++// Standard library support for the function class.+#if !defined(ASIO_HAS_STD_FUNCTION)+# if !defined(ASIO_DISABLE_STD_FUNCTION)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_FUNCTION 1+# elif (__cplusplus >= 201103)+# define ASIO_HAS_STD_FUNCTION 1+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_FUNCTION 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_STD_FUNCTION 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_FUNCTION)+#endif // !defined(ASIO_HAS_STD_FUNCTION)++// Standard library support for type traits.+#if !defined(ASIO_HAS_STD_TYPE_TRAITS)+# if !defined(ASIO_DISABLE_STD_TYPE_TRAITS)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_TYPE_TRAITS 1+# elif (__cplusplus >= 201103)+# if __has_include(<type_traits>)+# define ASIO_HAS_STD_TYPE_TRAITS 1+# endif // __has_include(<type_traits>)+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_TYPE_TRAITS 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_STD_TYPE_TRAITS 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_TYPE_TRAITS)+#endif // !defined(ASIO_HAS_STD_TYPE_TRAITS)++// Standard library support for the nullptr_t type.+#if !defined(ASIO_HAS_NULLPTR)+# if !defined(ASIO_DISABLE_NULLPTR)+# if defined(__clang__)+# if __has_feature(__cxx_nullptr__)+# define ASIO_HAS_NULLPTR 1+# endif // __has_feature(__cxx_nullptr__)+# elif defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_NULLPTR 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_NULLPTR 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_NULLPTR)+#endif // !defined(ASIO_HAS_NULLPTR)++// Standard library support for the C++11 allocator additions.+#if !defined(ASIO_HAS_CXX11_ALLOCATORS)+# if !defined(ASIO_DISABLE_CXX11_ALLOCATORS)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_CXX11_ALLOCATORS 1+# elif (__cplusplus >= 201103)+# define ASIO_HAS_CXX11_ALLOCATORS 1+# endif // (__cplusplus >= 201103)+# elif defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_CXX11_ALLOCATORS 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1800)+# define ASIO_HAS_CXX11_ALLOCATORS 1+# endif // (_MSC_VER >= 1800)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_CXX11_ALLOCATORS)+#endif // !defined(ASIO_HAS_CXX11_ALLOCATORS)++// Standard library support for the cstdint header.+#if !defined(ASIO_HAS_CSTDINT)+# if !defined(ASIO_DISABLE_CSTDINT)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_CSTDINT 1+# elif (__cplusplus >= 201103)+# define ASIO_HAS_CSTDINT 1+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_CSTDINT 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_CSTDINT 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_CSTDINT)+#endif // !defined(ASIO_HAS_CSTDINT)++// Standard library support for the thread class.+#if !defined(ASIO_HAS_STD_THREAD)+# if !defined(ASIO_DISABLE_STD_THREAD)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_THREAD 1+# elif (__cplusplus >= 201103)+# if __has_include(<thread>)+# define ASIO_HAS_STD_THREAD 1+# endif // __has_include(<thread>)+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_THREAD 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_STD_THREAD 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_THREAD)+#endif // !defined(ASIO_HAS_STD_THREAD)++// Standard library support for the mutex and condition variable classes.+#if !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)+# if !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1+# elif (__cplusplus >= 201103)+# if __has_include(<mutex>)+# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1+# endif // __has_include(<mutex>)+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR)+#endif // !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)++// Standard library support for the call_once function.+#if !defined(ASIO_HAS_STD_CALL_ONCE)+# if !defined(ASIO_DISABLE_STD_CALL_ONCE)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_CALL_ONCE 1+# elif (__cplusplus >= 201103)+# if __has_include(<mutex>)+# define ASIO_HAS_STD_CALL_ONCE 1+# endif // __has_include(<mutex>)+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_CALL_ONCE 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_STD_CALL_ONCE 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_CALL_ONCE)+#endif // !defined(ASIO_HAS_STD_CALL_ONCE)++// Standard library support for futures.+#if !defined(ASIO_HAS_STD_FUTURE)+# if !defined(ASIO_DISABLE_STD_FUTURE)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_FUTURE 1+# elif (__cplusplus >= 201103)+# if __has_include(<future>)+# define ASIO_HAS_STD_FUTURE 1+# endif // __has_include(<future>)+# endif // (__cplusplus >= 201103)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_FUTURE 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_STD_FUTURE 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_FUTURE)+#endif // !defined(ASIO_HAS_STD_FUTURE)++// Standard library support for std::string_view.+#if !defined(ASIO_HAS_STD_STRING_VIEW)+# if !defined(ASIO_DISABLE_STD_STRING_VIEW)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# if (__cplusplus >= 201402)+# if __has_include(<string_view>)+# define ASIO_HAS_STD_STRING_VIEW 1+# endif // __has_include(<string_view>)+# endif // (__cplusplus >= 201402)+# else // defined(ASIO_HAS_CLANG_LIBCXX)+# if (__cplusplus >= 201703)+# if __has_include(<string_view>)+# define ASIO_HAS_STD_STRING_VIEW 1+# endif // __has_include(<string_view>)+# endif // (__cplusplus >= 201703)+# endif // defined(ASIO_HAS_CLANG_LIBCXX)+# elif defined(__GNUC__)+# if (__GNUC__ >= 7)+# if (__cplusplus >= 201703)+# define ASIO_HAS_STD_STRING_VIEW 1+# endif // (__cplusplus >= 201703)+# endif // (__GNUC__ >= 7)+# elif defined(ASIO_MSVC)+# if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703)+# define ASIO_HAS_STD_STRING_VIEW 1+# endif // (_MSC_VER >= 1910 && _MSVC_LANG >= 201703)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_STRING_VIEW)+#endif // !defined(ASIO_HAS_STD_STRING_VIEW)++// Standard library support for std::experimental::string_view.+#if !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)+# if !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# if (_LIBCPP_VERSION < 7000)+# if (__cplusplus >= 201402)+# if __has_include(<experimental/string_view>)+# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1+# endif // __has_include(<experimental/string_view>)+# endif // (__cplusplus >= 201402)+# endif // (_LIBCPP_VERSION < 7000)+# else // defined(ASIO_HAS_CLANG_LIBCXX)+# if (__cplusplus >= 201402)+# if __has_include(<experimental/string_view>)+# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1+# endif // __has_include(<experimental/string_view>)+# endif // (__cplusplus >= 201402)+# endif // // defined(ASIO_HAS_CLANG_LIBCXX)+# endif // defined(__clang__)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)+# if (__cplusplus >= 201402)+# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1+# endif // (__cplusplus >= 201402)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# endif // !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW)+#endif // !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)++// Standard library has a string_view that we can use.+#if !defined(ASIO_HAS_STRING_VIEW)+# if !defined(ASIO_DISABLE_STRING_VIEW)+# if defined(ASIO_HAS_STD_STRING_VIEW)+# define ASIO_HAS_STRING_VIEW 1+# elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)+# define ASIO_HAS_STRING_VIEW 1+# endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)+# endif // !defined(ASIO_DISABLE_STRING_VIEW)+#endif // !defined(ASIO_HAS_STRING_VIEW)++// Standard library support for iostream move construction and assignment.+#if !defined(ASIO_HAS_STD_IOSTREAM_MOVE)+# if !defined(ASIO_DISABLE_STD_IOSTREAM_MOVE)+# if defined(__GNUC__)+# if (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_IOSTREAM_MOVE 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_STD_IOSTREAM_MOVE 1+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_IOSTREAM_MOVE)+#endif // !defined(ASIO_HAS_STD_IOSTREAM_MOVE)++// Standard library has invoke_result (which supersedes result_of).+#if !defined(ASIO_HAS_STD_INVOKE_RESULT)+# if !defined(ASIO_DISABLE_STD_INVOKE_RESULT)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1911 && _MSVC_LANG >= 201703)+# define ASIO_HAS_STD_INVOKE_RESULT 1+# endif // (_MSC_VER >= 1911 && _MSVC_LANG >= 201703)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_INVOKE_RESULT)+#endif // !defined(ASIO_HAS_STD_INVOKE_RESULT)++// Standard library support for std::exception_ptr and std::current_exception.+#if !defined(ASIO_HAS_STD_EXCEPTION_PTR)+# if !defined(ASIO_DISABLE_STD_EXCEPTION_PTR)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_EXCEPTION_PTR 1+# elif (__cplusplus >= 201103)+# define ASIO_HAS_STD_EXCEPTION_PTR 1+# endif // (__cplusplus >= 201103)+# elif defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_EXCEPTION_PTR 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1800)+# define ASIO_HAS_STD_EXCEPTION_PTR 1+# endif // (_MSC_VER >= 1800)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_EXCEPTION_PTR)+#endif // !defined(ASIO_HAS_STD_EXCEPTION_PTR)++// Standard library support for std::nested_exception.+#if !defined(ASIO_HAS_STD_NESTED_EXCEPTION)+# if !defined(ASIO_DISABLE_STD_NESTED_EXCEPTION)+# if defined(__clang__)+# if defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_NESTED_EXCEPTION 1+# elif (__cplusplus >= 201103)+# define ASIO_HAS_STD_NESTED_EXCEPTION 1+# endif // (__cplusplus >= 201103)+# elif defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_HAS_STD_NESTED_EXCEPTION 1+# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1900)+# define ASIO_HAS_STD_NESTED_EXCEPTION 1+# endif // (_MSC_VER >= 1900)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_NESTED_EXCEPTION)+#endif // !defined(ASIO_HAS_STD_NESTED_EXCEPTION)++// Standard library support for std::any.+#if !defined(ASIO_HAS_STD_ANY)+# if !defined(ASIO_DISABLE_STD_ANY)+# if defined(__clang__)+# if (__cplusplus >= 201703)+# if __has_include(<any>)+# define ASIO_HAS_STD_ANY 1+# endif // __has_include(<any>)+# endif // (__cplusplus >= 201703)+# elif defined(__GNUC__)+# if (__GNUC__ >= 7)+# if (__cplusplus >= 201703)+# define ASIO_HAS_STD_ANY 1+# endif // (__cplusplus >= 201703)+# endif // (__GNUC__ >= 7)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703)+# define ASIO_HAS_STD_ANY 1+# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703)+# endif // defined(ASIO_MSVC)+# endif // !defined(ASIO_DISABLE_STD_ANY)+#endif // !defined(ASIO_HAS_STD_ANY)++// Standard library support for std::source_location.+#if !defined(ASIO_HAS_STD_SOURCE_LOCATION)+# if !defined(ASIO_DISABLE_STD_SOURCE_LOCATION)+// ...+# endif // !defined(ASIO_DISABLE_STD_SOURCE_LOCATION)+#endif // !defined(ASIO_HAS_STD_SOURCE_LOCATION)++// Standard library support for std::experimental::source_location.+#if !defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)+# if !defined(ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION)+# if defined(__GNUC__)+# if (__cplusplus >= 201709)+# if __has_include(<experimental/source_location>)+# define ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1+# endif // __has_include(<experimental/source_location>)+# endif // (__cplusplus >= 201709)+# endif // defined(__GNUC__)+# endif // !defined(ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION)+#endif // !defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)++// Standard library has a source_location that we can use.+#if !defined(ASIO_HAS_SOURCE_LOCATION)+# if !defined(ASIO_DISABLE_SOURCE_LOCATION)+# if defined(ASIO_HAS_STD_SOURCE_LOCATION)+# define ASIO_HAS_SOURCE_LOCATION 1+# elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)+# define ASIO_HAS_SOURCE_LOCATION 1+# endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)+# endif // !defined(ASIO_DISABLE_SOURCE_LOCATION)+#endif // !defined(ASIO_HAS_SOURCE_LOCATION)++// Windows App target. Windows but with a limited API.+#if !defined(ASIO_WINDOWS_APP)+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603)+# include <winapifamily.h>+# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \+ || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)) \+ && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)+# define ASIO_WINDOWS_APP 1+# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)+ // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)+# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603)+#endif // !defined(ASIO_WINDOWS_APP)++// Legacy WinRT target. Windows App is preferred.+#if !defined(ASIO_WINDOWS_RUNTIME)+# if !defined(ASIO_WINDOWS_APP)+# if defined(__cplusplus_winrt)+# include <winapifamily.h>+# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \+ && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)+# define ASIO_WINDOWS_RUNTIME 1+# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)+ // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)+# endif // defined(__cplusplus_winrt)+# endif // !defined(ASIO_WINDOWS_APP)+#endif // !defined(ASIO_WINDOWS_RUNTIME)++// Windows target. Excludes WinRT but includes Windows App targets.+#if !defined(ASIO_WINDOWS)+# if !defined(ASIO_WINDOWS_RUNTIME)+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS)+# define ASIO_WINDOWS 1+# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)+# define ASIO_WINDOWS 1+# elif defined(ASIO_WINDOWS_APP)+# define ASIO_WINDOWS 1+# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS)+# endif // !defined(ASIO_WINDOWS_RUNTIME)+#endif // !defined(ASIO_WINDOWS)++// Windows: target OS version.+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)+# if defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__))+# pragma message( \+ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\+ "- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\+ "- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\+ "Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).")+# else // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__))+# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.+# warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line.+# warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).+# endif // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__))+# define _WIN32_WINNT 0x0601+# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)+# if defined(_MSC_VER)+# if defined(_WIN32) && !defined(WIN32)+# if !defined(_WINSOCK2API_)+# define WIN32 // Needed for correct types in winsock2.h+# else // !defined(_WINSOCK2API_)+# error Please define the macro WIN32 in your compiler options+# endif // !defined(_WINSOCK2API_)+# endif // defined(_WIN32) && !defined(WIN32)+# endif // defined(_MSC_VER)+# if defined(__BORLANDC__)+# if defined(__WIN32__) && !defined(WIN32)+# if !defined(_WINSOCK2API_)+# define WIN32 // Needed for correct types in winsock2.h+# else // !defined(_WINSOCK2API_)+# error Please define the macro WIN32 in your compiler options+# endif // !defined(_WINSOCK2API_)+# endif // defined(__WIN32__) && !defined(WIN32)+# endif // defined(__BORLANDC__)+# if defined(__CYGWIN__)+# if !defined(__USE_W32_SOCKETS)+# error You must add -D__USE_W32_SOCKETS to your compiler options.+# endif // !defined(__USE_W32_SOCKETS)+# endif // defined(__CYGWIN__)+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++// Windows: minimise header inclusion.+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)+# if !defined(WIN32_LEAN_AND_MEAN)+# define WIN32_LEAN_AND_MEAN+# endif // !defined(WIN32_LEAN_AND_MEAN)+# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++// Windows: suppress definition of "min" and "max" macros.+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# if !defined(ASIO_NO_NOMINMAX)+# if !defined(NOMINMAX)+# define NOMINMAX 1+# endif // !defined(NOMINMAX)+# endif // !defined(ASIO_NO_NOMINMAX)+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++// Windows: IO Completion Ports.+#if !defined(ASIO_HAS_IOCP)+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)+# if !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)+# if !defined(ASIO_DISABLE_IOCP)+# define ASIO_HAS_IOCP 1+# endif // !defined(ASIO_DISABLE_IOCP)+# endif // !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)+# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+#endif // !defined(ASIO_HAS_IOCP)++// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to+// get access to the various platform feature macros, e.g. to be able to test+// for threads support.+#if !defined(ASIO_HAS_UNISTD_H)+# if !defined(ASIO_HAS_BOOST_CONFIG)+# if defined(unix) \+ || defined(__unix) \+ || defined(_XOPEN_SOURCE) \+ || defined(_POSIX_SOURCE) \+ || (defined(__MACH__) && defined(__APPLE__)) \+ || defined(__FreeBSD__) \+ || defined(__NetBSD__) \+ || defined(__OpenBSD__) \+ || defined(__linux__) \+ || defined(__HAIKU__)+# define ASIO_HAS_UNISTD_H 1+# endif+# endif // !defined(ASIO_HAS_BOOST_CONFIG)+#endif // !defined(ASIO_HAS_UNISTD_H)+#if defined(ASIO_HAS_UNISTD_H)+# include <unistd.h>+#endif // defined(ASIO_HAS_UNISTD_H)++// Linux: epoll, eventfd and timerfd.+#if defined(__linux__)+# include <linux/version.h>+# if !defined(ASIO_HAS_EPOLL)+# if !defined(ASIO_DISABLE_EPOLL)+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)+# define ASIO_HAS_EPOLL 1+# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)+# endif // !defined(ASIO_DISABLE_EPOLL)+# endif // !defined(ASIO_HAS_EPOLL)+# if !defined(ASIO_HAS_EVENTFD)+# if !defined(ASIO_DISABLE_EVENTFD)+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)+# define ASIO_HAS_EVENTFD 1+# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)+# endif // !defined(ASIO_DISABLE_EVENTFD)+# endif // !defined(ASIO_HAS_EVENTFD)+# if !defined(ASIO_HAS_TIMERFD)+# if defined(ASIO_HAS_EPOLL)+# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)+# define ASIO_HAS_TIMERFD 1+# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)+# endif // defined(ASIO_HAS_EPOLL)+# endif // !defined(ASIO_HAS_TIMERFD)+#endif // defined(__linux__)++// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue.+#if (defined(__MACH__) && defined(__APPLE__)) \+ || defined(__FreeBSD__) \+ || defined(__NetBSD__) \+ || defined(__OpenBSD__)+# if !defined(ASIO_HAS_KQUEUE)+# if !defined(ASIO_DISABLE_KQUEUE)+# define ASIO_HAS_KQUEUE 1+# endif // !defined(ASIO_DISABLE_KQUEUE)+# endif // !defined(ASIO_HAS_KQUEUE)+#endif // (defined(__MACH__) && defined(__APPLE__))+ // || defined(__FreeBSD__)+ // || defined(__NetBSD__)+ // || defined(__OpenBSD__)++// Solaris: /dev/poll.+#if defined(__sun)+# if !defined(ASIO_HAS_DEV_POLL)+# if !defined(ASIO_DISABLE_DEV_POLL)+# define ASIO_HAS_DEV_POLL 1+# endif // !defined(ASIO_DISABLE_DEV_POLL)+# endif // !defined(ASIO_HAS_DEV_POLL)+#endif // defined(__sun)++// Serial ports.+#if !defined(ASIO_HAS_SERIAL_PORT)+# if defined(ASIO_HAS_IOCP) \+ || !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+# if !defined(__SYMBIAN32__)+# if !defined(ASIO_DISABLE_SERIAL_PORT)+# define ASIO_HAS_SERIAL_PORT 1+# endif // !defined(ASIO_DISABLE_SERIAL_PORT)+# endif // !defined(__SYMBIAN32__)+# endif // defined(ASIO_HAS_IOCP)+ // || !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)+#endif // !defined(ASIO_HAS_SERIAL_PORT)++// Windows: stream handles.+#if !defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)+# if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)+# if defined(ASIO_HAS_IOCP)+# define ASIO_HAS_WINDOWS_STREAM_HANDLE 1+# endif // defined(ASIO_HAS_IOCP)+# endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)+#endif // !defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)++// Windows: random access handles.+#if !defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)+# if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)+# if defined(ASIO_HAS_IOCP)+# define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1+# endif // defined(ASIO_HAS_IOCP)+# endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)+#endif // !defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)++// Windows: object handles.+#if !defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)+# if !defined(ASIO_DISABLE_WINDOWS_OBJECT_HANDLE)+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# if !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)+# define ASIO_HAS_WINDOWS_OBJECT_HANDLE 1+# endif // !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# endif // !defined(ASIO_DISABLE_WINDOWS_OBJECT_HANDLE)+#endif // !defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)++// Windows: OVERLAPPED wrapper.+#if !defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR)+# if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)+# if defined(ASIO_HAS_IOCP)+# define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1+# endif // defined(ASIO_HAS_IOCP)+# endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)+#endif // !defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR)++// POSIX: stream-oriented file descriptors.+#if !defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)+# if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)+# if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+# define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1+# endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)+# endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)+#endif // !defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)++// UNIX domain sockets.+#if !defined(ASIO_HAS_LOCAL_SOCKETS)+# if !defined(ASIO_DISABLE_LOCAL_SOCKETS)+# if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+# define ASIO_HAS_LOCAL_SOCKETS 1+# endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)+# endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS)+#endif // !defined(ASIO_HAS_LOCAL_SOCKETS)++// Can use sigaction() instead of signal().+#if !defined(ASIO_HAS_SIGACTION)+# if !defined(ASIO_DISABLE_SIGACTION)+# if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+# define ASIO_HAS_SIGACTION 1+# endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)+# endif // !defined(ASIO_DISABLE_SIGACTION)+#endif // !defined(ASIO_HAS_SIGACTION)++// Can use signal().+#if !defined(ASIO_HAS_SIGNAL)+# if !defined(ASIO_DISABLE_SIGNAL)+# if !defined(UNDER_CE)+# define ASIO_HAS_SIGNAL 1+# endif // !defined(UNDER_CE)+# endif // !defined(ASIO_DISABLE_SIGNAL)+#endif // !defined(ASIO_HAS_SIGNAL)++// Can use getaddrinfo() and getnameinfo().+#if !defined(ASIO_HAS_GETADDRINFO)+# if !defined(ASIO_DISABLE_GETADDRINFO)+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)+# define ASIO_HAS_GETADDRINFO 1+# elif defined(UNDER_CE)+# define ASIO_HAS_GETADDRINFO 1+# endif // defined(UNDER_CE)+# elif defined(__MACH__) && defined(__APPLE__)+# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)+# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)+# define ASIO_HAS_GETADDRINFO 1+# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)+# else // defined(__MAC_OS_X_VERSION_MIN_REQUIRED)+# define ASIO_HAS_GETADDRINFO 1+# endif // defined(__MAC_OS_X_VERSION_MIN_REQUIRED)+# else // defined(__MACH__) && defined(__APPLE__)+# define ASIO_HAS_GETADDRINFO 1+# endif // defined(__MACH__) && defined(__APPLE__)+# endif // !defined(ASIO_DISABLE_GETADDRINFO)+#endif // !defined(ASIO_HAS_GETADDRINFO)++// Whether standard iostreams are disabled.+#if !defined(ASIO_NO_IOSTREAM)+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_IOSTREAM)+# define ASIO_NO_IOSTREAM 1+# endif // !defined(BOOST_NO_IOSTREAM)+#endif // !defined(ASIO_NO_IOSTREAM)++// Whether exception handling is disabled.+#if !defined(ASIO_NO_EXCEPTIONS)+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_EXCEPTIONS)+# define ASIO_NO_EXCEPTIONS 1+# endif // !defined(BOOST_NO_EXCEPTIONS)+#endif // !defined(ASIO_NO_EXCEPTIONS)++// Whether the typeid operator is supported.+#if !defined(ASIO_NO_TYPEID)+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_TYPEID)+# define ASIO_NO_TYPEID 1+# endif // !defined(BOOST_NO_TYPEID)+#endif // !defined(ASIO_NO_TYPEID)++// Threads.+#if !defined(ASIO_HAS_THREADS)+# if !defined(ASIO_DISABLE_THREADS)+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS)+# define ASIO_HAS_THREADS 1+# elif defined(__GNUC__) && !defined(__MINGW32__) \+ && !defined(linux) && !defined(__linux) && !defined(__linux__)+# define ASIO_HAS_THREADS 1+# elif defined(_MT) || defined(__MT__)+# define ASIO_HAS_THREADS 1+# elif defined(_REENTRANT)+# define ASIO_HAS_THREADS 1+# elif defined(__APPLE__)+# define ASIO_HAS_THREADS 1+# elif defined(__HAIKU__)+# define ASIO_HAS_THREADS 1+# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0)+# define ASIO_HAS_THREADS 1+# elif defined(_PTHREADS)+# define ASIO_HAS_THREADS 1+# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS)+# endif // !defined(ASIO_DISABLE_THREADS)+#endif // !defined(ASIO_HAS_THREADS)++// POSIX threads.+#if !defined(ASIO_HAS_PTHREADS)+# if defined(ASIO_HAS_THREADS)+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS)+# define ASIO_HAS_PTHREADS 1+# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0)+# define ASIO_HAS_PTHREADS 1+# elif defined(__HAIKU__)+# define ASIO_HAS_PTHREADS 1+# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS)+# endif // defined(ASIO_HAS_THREADS)+#endif // !defined(ASIO_HAS_PTHREADS)++// Helper to prevent macro expansion.+#define ASIO_PREVENT_MACRO_SUBSTITUTION++// Helper to define in-class constants.+#if !defined(ASIO_STATIC_CONSTANT)+# if !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT)+# define ASIO_STATIC_CONSTANT(type, assignment) \+ BOOST_STATIC_CONSTANT(type, assignment)+# else // !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT)+# define ASIO_STATIC_CONSTANT(type, assignment) \+ static const type assignment+# endif // !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT)+#endif // !defined(ASIO_STATIC_CONSTANT)++// Boost array library.+#if !defined(ASIO_HAS_BOOST_ARRAY)+# if !defined(ASIO_DISABLE_BOOST_ARRAY)+# define ASIO_HAS_BOOST_ARRAY 1+# endif // !defined(ASIO_DISABLE_BOOST_ARRAY)+#endif // !defined(ASIO_HAS_BOOST_ARRAY)++// Boost assert macro.+#if !defined(ASIO_HAS_BOOST_ASSERT)+# if !defined(ASIO_DISABLE_BOOST_ASSERT)+# define ASIO_HAS_BOOST_ASSERT 1+# endif // !defined(ASIO_DISABLE_BOOST_ASSERT)+#endif // !defined(ASIO_HAS_BOOST_ASSERT)++// Boost limits header.+#if !defined(ASIO_HAS_BOOST_LIMITS)+# if !defined(ASIO_DISABLE_BOOST_LIMITS)+# define ASIO_HAS_BOOST_LIMITS 1+# endif // !defined(ASIO_DISABLE_BOOST_LIMITS)+#endif // !defined(ASIO_HAS_BOOST_LIMITS)++// Boost throw_exception function.+#if !defined(ASIO_HAS_BOOST_THROW_EXCEPTION)+# if !defined(ASIO_DISABLE_BOOST_THROW_EXCEPTION)+# define ASIO_HAS_BOOST_THROW_EXCEPTION 1+# endif // !defined(ASIO_DISABLE_BOOST_THROW_EXCEPTION)+#endif // !defined(ASIO_HAS_BOOST_THROW_EXCEPTION)++// Boost regex library.+#if !defined(ASIO_HAS_BOOST_REGEX)+# if !defined(ASIO_DISABLE_BOOST_REGEX)+# define ASIO_HAS_BOOST_REGEX 1+# endif // !defined(ASIO_DISABLE_BOOST_REGEX)+#endif // !defined(ASIO_HAS_BOOST_REGEX)++// Boost bind function.+#if !defined(ASIO_HAS_BOOST_BIND)+# if !defined(ASIO_DISABLE_BOOST_BIND)+# define ASIO_HAS_BOOST_BIND 1+# endif // !defined(ASIO_DISABLE_BOOST_BIND)+#endif // !defined(ASIO_HAS_BOOST_BIND)++// Boost's BOOST_WORKAROUND macro.+#if !defined(ASIO_HAS_BOOST_WORKAROUND)+# if !defined(ASIO_DISABLE_BOOST_WORKAROUND)+# define ASIO_HAS_BOOST_WORKAROUND 1+# endif // !defined(ASIO_DISABLE_BOOST_WORKAROUND)+#endif // !defined(ASIO_HAS_BOOST_WORKAROUND)++// Microsoft Visual C++'s secure C runtime library.+#if !defined(ASIO_HAS_SECURE_RTL)+# if !defined(ASIO_DISABLE_SECURE_RTL)+# if defined(ASIO_MSVC) \+ && (ASIO_MSVC >= 1400) \+ && !defined(UNDER_CE)+# define ASIO_HAS_SECURE_RTL 1+# endif // defined(ASIO_MSVC)+ // && (ASIO_MSVC >= 1400)+ // && !defined(UNDER_CE)+# endif // !defined(ASIO_DISABLE_SECURE_RTL)+#endif // !defined(ASIO_HAS_SECURE_RTL)++// Handler hooking. Disabled for ancient Borland C++ and gcc compilers.+#if !defined(ASIO_HAS_HANDLER_HOOKS)+# if !defined(ASIO_DISABLE_HANDLER_HOOKS)+# if defined(__GNUC__)+# if (__GNUC__ >= 3)+# define ASIO_HAS_HANDLER_HOOKS 1+# endif // (__GNUC__ >= 3)+# elif !defined(__BORLANDC__) || defined(__clang__)+# define ASIO_HAS_HANDLER_HOOKS 1+# endif // !defined(__BORLANDC__) || defined(__clang__)+# endif // !defined(ASIO_DISABLE_HANDLER_HOOKS)+#endif // !defined(ASIO_HAS_HANDLER_HOOKS)++// Support for the __thread keyword extension.+#if !defined(ASIO_DISABLE_THREAD_KEYWORD_EXTENSION)+# if defined(__linux__)+# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))+# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)+# if !defined(__INTEL_COMPILER) && !defined(__ICL) \+ && !(defined(__clang__) && defined(__ANDROID__))+# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1+# define ASIO_THREAD_KEYWORD __thread+# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100)+# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1+# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100)+ // && !(defined(__clang__) && defined(__ANDROID__))+# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)+# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))+# endif // defined(__linux__)+# if defined(ASIO_MSVC) && defined(ASIO_WINDOWS_RUNTIME)+# if (_MSC_VER >= 1700)+# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1+# define ASIO_THREAD_KEYWORD __declspec(thread)+# endif // (_MSC_VER >= 1700)+# endif // defined(ASIO_MSVC) && defined(ASIO_WINDOWS_RUNTIME)+#endif // !defined(ASIO_DISABLE_THREAD_KEYWORD_EXTENSION)+#if !defined(ASIO_THREAD_KEYWORD)+# define ASIO_THREAD_KEYWORD __thread+#endif // !defined(ASIO_THREAD_KEYWORD)++// Support for POSIX ssize_t typedef.+#if !defined(ASIO_DISABLE_SSIZE_T)+# if defined(__linux__) \+ || (defined(__MACH__) && defined(__APPLE__))+# define ASIO_HAS_SSIZE_T 1+# endif // defined(__linux__)+ // || (defined(__MACH__) && defined(__APPLE__))+#endif // !defined(ASIO_DISABLE_SSIZE_T)++// Helper macros to manage transition away from error_code return values.+#if defined(ASIO_NO_DEPRECATED)+# define ASIO_SYNC_OP_VOID void+# define ASIO_SYNC_OP_VOID_RETURN(e) return+#else // defined(ASIO_NO_DEPRECATED)+# define ASIO_SYNC_OP_VOID asio::error_code+# define ASIO_SYNC_OP_VOID_RETURN(e) return e+#endif // defined(ASIO_NO_DEPRECATED)++// Newer gcc, clang need special treatment to suppress unused typedef warnings.+#if defined(__clang__)+# if defined(__apple_build_version__)+# if (__clang_major__ >= 7)+# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__))+# endif // (__clang_major__ >= 7)+# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \+ || (__clang_major__ > 3)+# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__))+# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6))+ // || (__clang_major__ > 3)+#elif defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__))+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)+#endif // defined(__GNUC__)+#if !defined(ASIO_UNUSED_TYPEDEF)+# define ASIO_UNUSED_TYPEDEF+#endif // !defined(ASIO_UNUSED_TYPEDEF)++// Some versions of gcc generate spurious warnings about unused variables.+#if defined(__GNUC__)+# if (__GNUC__ >= 4)+# define ASIO_UNUSED_VARIABLE __attribute__((__unused__))+# endif // (__GNUC__ >= 4)+#endif // defined(__GNUC__)+#if !defined(ASIO_UNUSED_VARIABLE)+# define ASIO_UNUSED_VARIABLE+#endif // !defined(ASIO_UNUSED_VARIABLE)++// Support the co_await keyword on compilers known to allow it.+#if !defined(ASIO_HAS_CO_AWAIT)+# if !defined(ASIO_DISABLE_CO_AWAIT)+# if defined(ASIO_MSVC)+# if (_MSC_FULL_VER >= 190023506)+# if defined(_RESUMABLE_FUNCTIONS_SUPPORTED)+# define ASIO_HAS_CO_AWAIT 1+# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED)+# endif // (_MSC_FULL_VER >= 190023506)+# endif // defined(ASIO_MSVC)+# if defined(__clang__)+# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703)+# if __has_include(<experimental/coroutine>)+# define ASIO_HAS_CO_AWAIT 1+# endif // __has_include(<experimental/coroutine>)+# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703)+# elif defined(__GNUC__)+# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)+# if __has_include(<coroutine>)+# define ASIO_HAS_CO_AWAIT 1+# endif // __has_include(<coroutine>)+# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)+# endif // defined(__GNUC__)+# endif // !defined(ASIO_DISABLE_CO_AWAIT)+#endif // !defined(ASIO_HAS_CO_AWAIT)++// Standard library support for coroutines.+#if !defined(ASIO_HAS_STD_COROUTINE)+# if !defined(ASIO_DISABLE_STD_COROUTINE)+# if defined(__GNUC__)+# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)+# if __has_include(<coroutine>)+# define ASIO_HAS_STD_COROUTINE 1+# endif // __has_include(<coroutine>)+# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)+# endif // defined(__GNUC__)+# endif // !defined(ASIO_DISABLE_STD_COROUTINE)+#endif // !defined(ASIO_HAS_STD_COROUTINE)++// Compiler support for the the [[nodiscard]] attribute.+#if !defined(ASIO_NODISCARD)+# if defined(__has_cpp_attribute)+# if __has_cpp_attribute(nodiscard)+# if (__cplusplus >= 201703)+# define ASIO_NODISCARD [[nodiscard]]+# endif // (__cplusplus >= 201703)+# endif // __has_cpp_attribute(nodiscard)+# endif // defined(__has_cpp_attribute)+#endif // !defined(ASIO_NODISCARD)+#if !defined(ASIO_NODISCARD)+# define ASIO_NODISCARD+#endif // !defined(ASIO_NODISCARD)++#endif // ASIO_DETAIL_CONFIG_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/consuming_buffers.hpp view
@@ -0,0 +1,414 @@+//+// detail/consuming_buffers.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_CONSUMING_BUFFERS_HPP+#define ASIO_DETAIL_CONSUMING_BUFFERS_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/buffer.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/limits.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Helper template to determine the maximum number of prepared buffers.+template <typename Buffers>+struct prepared_buffers_max+{+ enum { value = buffer_sequence_adapter_base::max_buffers };+};++template <typename Elem, std::size_t N>+struct prepared_buffers_max<boost::array<Elem, N> >+{+ enum { value = N };+};++#if defined(ASIO_HAS_STD_ARRAY)++template <typename Elem, std::size_t N>+struct prepared_buffers_max<std::array<Elem, N> >+{+ enum { value = N };+};++#endif // defined(ASIO_HAS_STD_ARRAY)++// A buffer sequence used to represent a subsequence of the buffers.+template <typename Buffer, std::size_t MaxBuffers>+struct prepared_buffers+{+ typedef Buffer value_type;+ typedef const Buffer* const_iterator;++ enum { max_buffers = MaxBuffers < 16 ? MaxBuffers : 16 };++ prepared_buffers() : count(0) {}+ const_iterator begin() const { return elems; }+ const_iterator end() const { return elems + count; }++ Buffer elems[max_buffers];+ std::size_t count;+};++// A proxy for a sub-range in a list of buffers.+template <typename Buffer, typename Buffers, typename Buffer_Iterator>+class consuming_buffers+{+public:+ typedef prepared_buffers<Buffer, prepared_buffers_max<Buffers>::value>+ prepared_buffers_type;++ // Construct to represent the entire list of buffers.+ explicit consuming_buffers(const Buffers& buffers)+ : buffers_(buffers),+ total_consumed_(0),+ next_elem_(0),+ next_elem_offset_(0)+ {+ using asio::buffer_size;+ total_size_ = buffer_size(buffers);+ }++ // Determine if we are at the end of the buffers.+ bool empty() const+ {+ return total_consumed_ >= total_size_;+ }++ // Get the buffer for a single transfer, with a size.+ prepared_buffers_type prepare(std::size_t max_size)+ {+ prepared_buffers_type result;++ Buffer_Iterator next = asio::buffer_sequence_begin(buffers_);+ Buffer_Iterator end = asio::buffer_sequence_end(buffers_);++ std::advance(next, next_elem_);+ std::size_t elem_offset = next_elem_offset_;+ while (next != end && max_size > 0 && (result.count) < result.max_buffers)+ {+ Buffer next_buf = Buffer(*next) + elem_offset;+ result.elems[result.count] = asio::buffer(next_buf, max_size);+ max_size -= result.elems[result.count].size();+ elem_offset = 0;+ if (result.elems[result.count].size() > 0)+ ++result.count;+ ++next;+ }++ return result;+ }++ // Consume the specified number of bytes from the buffers.+ void consume(std::size_t size)+ {+ total_consumed_ += size;++ Buffer_Iterator next = asio::buffer_sequence_begin(buffers_);+ Buffer_Iterator end = asio::buffer_sequence_end(buffers_);++ std::advance(next, next_elem_);+ while (next != end && size > 0)+ {+ Buffer next_buf = Buffer(*next) + next_elem_offset_;+ if (size < next_buf.size())+ {+ next_elem_offset_ += size;+ size = 0;+ }+ else+ {+ size -= next_buf.size();+ next_elem_offset_ = 0;+ ++next_elem_;+ ++next;+ }+ }+ }++ // Get the total number of bytes consumed from the buffers.+ std::size_t total_consumed() const+ {+ return total_consumed_;+ }++private:+ Buffers buffers_;+ std::size_t total_size_;+ std::size_t total_consumed_;+ std::size_t next_elem_;+ std::size_t next_elem_offset_;+};++// Base class of all consuming_buffers specialisations for single buffers.+template <typename Buffer>+class consuming_single_buffer+{+public:+ // Construct to represent the entire list of buffers.+ template <typename Buffer1>+ explicit consuming_single_buffer(const Buffer1& buffer)+ : buffer_(buffer),+ total_consumed_(0)+ {+ }++ // Determine if we are at the end of the buffers.+ bool empty() const+ {+ return total_consumed_ >= buffer_.size();+ }++ // Get the buffer for a single transfer, with a size.+ Buffer prepare(std::size_t max_size)+ {+ return asio::buffer(buffer_ + total_consumed_, max_size);+ }++ // Consume the specified number of bytes from the buffers.+ void consume(std::size_t size)+ {+ total_consumed_ += size;+ }++ // Get the total number of bytes consumed from the buffers.+ std::size_t total_consumed() const+ {+ return total_consumed_;+ }++private:+ Buffer buffer_;+ std::size_t total_consumed_;+};++template <>+class consuming_buffers<mutable_buffer, mutable_buffer, const mutable_buffer*>+ : public consuming_single_buffer<ASIO_MUTABLE_BUFFER>+{+public:+ explicit consuming_buffers(const mutable_buffer& buffer)+ : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer)+ {+ }+};++template <>+class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*>+ : public consuming_single_buffer<ASIO_CONST_BUFFER>+{+public:+ explicit consuming_buffers(const mutable_buffer& buffer)+ : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)+ {+ }+};++template <>+class consuming_buffers<const_buffer, const_buffer, const const_buffer*>+ : public consuming_single_buffer<ASIO_CONST_BUFFER>+{+public:+ explicit consuming_buffers(const const_buffer& buffer)+ : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)+ {+ }+};++#if !defined(ASIO_NO_DEPRECATED)++template <>+class consuming_buffers<mutable_buffer,+ mutable_buffers_1, const mutable_buffer*>+ : public consuming_single_buffer<ASIO_MUTABLE_BUFFER>+{+public:+ explicit consuming_buffers(const mutable_buffers_1& buffer)+ : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer)+ {+ }+};++template <>+class consuming_buffers<const_buffer, mutable_buffers_1, const mutable_buffer*>+ : public consuming_single_buffer<ASIO_CONST_BUFFER>+{+public:+ explicit consuming_buffers(const mutable_buffers_1& buffer)+ : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)+ {+ }+};++template <>+class consuming_buffers<const_buffer, const_buffers_1, const const_buffer*>+ : public consuming_single_buffer<ASIO_CONST_BUFFER>+{+public:+ explicit consuming_buffers(const const_buffers_1& buffer)+ : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)+ {+ }+};++#endif // !defined(ASIO_NO_DEPRECATED)++template <typename Buffer, typename Elem>+class consuming_buffers<Buffer, boost::array<Elem, 2>,+ typename boost::array<Elem, 2>::const_iterator>+{+public:+ // Construct to represent the entire list of buffers.+ explicit consuming_buffers(const boost::array<Elem, 2>& buffers)+ : buffers_(buffers),+ total_consumed_(0)+ {+ }++ // Determine if we are at the end of the buffers.+ bool empty() const+ {+ return total_consumed_ >=+ Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();+ }++ // Get the buffer for a single transfer, with a size.+ boost::array<Buffer, 2> prepare(std::size_t max_size)+ {+ boost::array<Buffer, 2> result = {{+ Buffer(buffers_[0]), Buffer(buffers_[1]) }};+ std::size_t buffer0_size = result[0].size();+ result[0] = asio::buffer(result[0] + total_consumed_, max_size);+ result[1] = asio::buffer(+ result[1] + (total_consumed_ < buffer0_size+ ? 0 : total_consumed_ - buffer0_size),+ max_size - result[0].size());+ return result;+ }++ // Consume the specified number of bytes from the buffers.+ void consume(std::size_t size)+ {+ total_consumed_ += size;+ }++ // Get the total number of bytes consumed from the buffers.+ std::size_t total_consumed() const+ {+ return total_consumed_;+ }++private:+ boost::array<Elem, 2> buffers_;+ std::size_t total_consumed_;+};++#if defined(ASIO_HAS_STD_ARRAY)++template <typename Buffer, typename Elem>+class consuming_buffers<Buffer, std::array<Elem, 2>,+ typename std::array<Elem, 2>::const_iterator>+{+public:+ // Construct to represent the entire list of buffers.+ explicit consuming_buffers(const std::array<Elem, 2>& buffers)+ : buffers_(buffers),+ total_consumed_(0)+ {+ }++ // Determine if we are at the end of the buffers.+ bool empty() const+ {+ return total_consumed_ >=+ Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();+ }++ // Get the buffer for a single transfer, with a size.+ std::array<Buffer, 2> prepare(std::size_t max_size)+ {+ std::array<Buffer, 2> result = {{+ Buffer(buffers_[0]), Buffer(buffers_[1]) }};+ std::size_t buffer0_size = result[0].size();+ result[0] = asio::buffer(result[0] + total_consumed_, max_size);+ result[1] = asio::buffer(+ result[1] + (total_consumed_ < buffer0_size+ ? 0 : total_consumed_ - buffer0_size),+ max_size - result[0].size());+ return result;+ }++ // Consume the specified number of bytes from the buffers.+ void consume(std::size_t size)+ {+ total_consumed_ += size;+ }++ // Get the total number of bytes consumed from the buffers.+ std::size_t total_consumed() const+ {+ return total_consumed_;+ }++private:+ std::array<Elem, 2> buffers_;+ std::size_t total_consumed_;+};++#endif // defined(ASIO_HAS_STD_ARRAY)++// Specialisation for null_buffers to ensure that the null_buffers type is+// always passed through to the underlying read or write operation.+template <typename Buffer>+class consuming_buffers<Buffer, null_buffers, const mutable_buffer*>+ : public asio::null_buffers+{+public:+ consuming_buffers(const null_buffers&)+ {+ // No-op.+ }++ bool empty()+ {+ return false;+ }++ null_buffers prepare(std::size_t)+ {+ return null_buffers();+ }++ void consume(std::size_t)+ {+ // No-op.+ }++ std::size_t total_consumed() const+ {+ return 0;+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/cstddef.hpp view
@@ -0,0 +1,31 @@+//+// detail/cstddef.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_CSTDDEF_HPP+#define ASIO_DETAIL_CSTDDEF_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>++namespace asio {++#if defined(ASIO_HAS_NULLPTR)+using std::nullptr_t;+#else // defined(ASIO_HAS_NULLPTR)+struct nullptr_t {};+#endif // defined(ASIO_HAS_NULLPTR)++} // namespace asio++#endif // ASIO_DETAIL_CSTDDEF_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/cstdint.hpp view
@@ -0,0 +1,60 @@+//+// detail/cstdint.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_CSTDINT_HPP+#define ASIO_DETAIL_CSTDINT_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_CSTDINT)+# include <cstdint>+#else // defined(ASIO_HAS_CSTDINT)+# include <boost/cstdint.hpp>+#endif // defined(ASIO_HAS_CSTDINT)++namespace asio {++#if defined(ASIO_HAS_CSTDINT)+using std::int16_t;+using std::int_least16_t;+using std::uint16_t;+using std::uint_least16_t;+using std::int32_t;+using std::int_least32_t;+using std::uint32_t;+using std::uint_least32_t;+using std::int64_t;+using std::int_least64_t;+using std::uint64_t;+using std::uint_least64_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++#endif // ASIO_DETAIL_CSTDINT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/date_time_fwd.hpp view
@@ -0,0 +1,34 @@+//+// detail/date_time_fwd.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DATE_TIME_FWD_HPP+#define ASIO_DETAIL_DATE_TIME_FWD_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++namespace boost {+namespace date_time {++template<class T, class TimeSystem>+class base_time;++} // namespace date_time+namespace posix_time {++class ptime;++} // namespace posix_time+} // namespace boost++#endif // ASIO_DETAIL_DATE_TIME_FWD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/deadline_timer_service.hpp view
@@ -0,0 +1,295 @@+//+// detail/deadline_timer_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DEADLINE_TIMER_SERVICE_HPP+#define ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/timer_queue.hpp"+#include "asio/detail/timer_queue_ptime.hpp"+#include "asio/detail/timer_scheduler.hpp"+#include "asio/detail/wait_handler.hpp"+#include "asio/detail/wait_op.hpp"++#if defined(ASIO_WINDOWS_RUNTIME)+# include <chrono>+# include <thread>+#endif // defined(ASIO_WINDOWS_RUNTIME)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Time_Traits>+class deadline_timer_service+ : public execution_context_service_base<deadline_timer_service<Time_Traits> >+{+public:+ // The time type.+ typedef typename Time_Traits::time_type time_type;++ // The duration type.+ typedef typename Time_Traits::duration_type duration_type;++ // The implementation type of the timer. This type is dependent on the+ // underlying implementation of the timer service.+ struct implementation_type+ : private asio::detail::noncopyable+ {+ time_type expiry;+ bool might_have_pending_waits;+ typename timer_queue<Time_Traits>::per_timer_data timer_data;+ };++ // Constructor.+ deadline_timer_service(execution_context& context)+ : execution_context_service_base<+ deadline_timer_service<Time_Traits> >(context),+ scheduler_(asio::use_service<timer_scheduler>(context))+ {+ scheduler_.init_task();+ scheduler_.add_timer_queue(timer_queue_);+ }++ // Destructor.+ ~deadline_timer_service()+ {+ scheduler_.remove_timer_queue(timer_queue_);+ }++ // Destroy all user-defined handler objects owned by the service.+ void shutdown()+ {+ }++ // Construct a new timer implementation.+ void construct(implementation_type& impl)+ {+ impl.expiry = time_type();+ impl.might_have_pending_waits = false;+ }++ // Destroy a timer implementation.+ void destroy(implementation_type& impl)+ {+ asio::error_code ec;+ cancel(impl, ec);+ }++ // Move-construct a new timer implementation.+ void move_construct(implementation_type& impl,+ implementation_type& other_impl)+ {+ scheduler_.move_timer(timer_queue_, impl.timer_data, other_impl.timer_data);++ impl.expiry = other_impl.expiry;+ other_impl.expiry = time_type();++ impl.might_have_pending_waits = other_impl.might_have_pending_waits;+ other_impl.might_have_pending_waits = false;+ }++ // Move-assign from another timer implementation.+ void move_assign(implementation_type& impl,+ deadline_timer_service& other_service,+ implementation_type& other_impl)+ {+ if (this != &other_service)+ if (impl.might_have_pending_waits)+ scheduler_.cancel_timer(timer_queue_, impl.timer_data);++ other_service.scheduler_.move_timer(other_service.timer_queue_,+ impl.timer_data, other_impl.timer_data);++ impl.expiry = other_impl.expiry;+ other_impl.expiry = time_type();++ impl.might_have_pending_waits = other_impl.might_have_pending_waits;+ 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.+ std::size_t cancel(implementation_type& impl, asio::error_code& ec)+ {+ if (!impl.might_have_pending_waits)+ {+ ec = asio::error_code();+ return 0;+ }++ ASIO_HANDLER_OPERATION((scheduler_.context(),+ "deadline_timer", &impl, 0, "cancel"));++ std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data);+ impl.might_have_pending_waits = false;+ ec = asio::error_code();+ return count;+ }++ // Cancels one asynchronous wait operation associated with the timer.+ std::size_t cancel_one(implementation_type& impl,+ asio::error_code& ec)+ {+ if (!impl.might_have_pending_waits)+ {+ ec = asio::error_code();+ return 0;+ }++ ASIO_HANDLER_OPERATION((scheduler_.context(),+ "deadline_timer", &impl, 0, "cancel_one"));++ std::size_t count = scheduler_.cancel_timer(+ timer_queue_, impl.timer_data, 1);+ if (count == 0)+ impl.might_have_pending_waits = false;+ ec = asio::error_code();+ return count;+ }++ // Get the expiry time for the timer as an absolute time.+ time_type expiry(const implementation_type& impl) const+ {+ return impl.expiry;+ }++ // Get the expiry time for the timer as an absolute time.+ time_type expires_at(const implementation_type& impl) const+ {+ return impl.expiry;+ }++ // Get the expiry time for the timer relative to now.+ duration_type expires_from_now(const implementation_type& impl) const+ {+ return Time_Traits::subtract(this->expiry(impl), Time_Traits::now());+ }++ // Set the expiry time for the timer as an absolute time.+ std::size_t expires_at(implementation_type& impl,+ const time_type& expiry_time, asio::error_code& ec)+ {+ std::size_t count = cancel(impl, ec);+ impl.expiry = expiry_time;+ ec = asio::error_code();+ return count;+ }++ // Set the expiry time for the timer relative to now.+ std::size_t expires_after(implementation_type& impl,+ const duration_type& expiry_time, asio::error_code& ec)+ {+ return expires_at(impl,+ Time_Traits::add(Time_Traits::now(), expiry_time), ec);+ }++ // Set the expiry time for the timer relative to now.+ std::size_t expires_from_now(implementation_type& impl,+ const duration_type& expiry_time, asio::error_code& ec)+ {+ return expires_at(impl,+ Time_Traits::add(Time_Traits::now(), expiry_time), ec);+ }++ // Perform a blocking wait on the timer.+ void wait(implementation_type& impl, asio::error_code& ec)+ {+ time_type now = Time_Traits::now();+ ec = asio::error_code();+ while (Time_Traits::less_than(now, impl.expiry) && !ec)+ {+ this->do_wait(Time_Traits::to_posix_duration(+ Time_Traits::subtract(impl.expiry, now)), ec);+ now = Time_Traits::now();+ }+ }++ // Start an asynchronous wait on the timer.+ template <typename Handler, typename IoExecutor>+ void async_wait(implementation_type& impl,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef wait_handler<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(handler, io_ex);++ impl.might_have_pending_waits = true;++ ASIO_HANDLER_CREATION((scheduler_.context(),+ *p.p, "deadline_timer", &impl, 0, "async_wait"));++ scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p);+ p.v = p.p = 0;+ }++private:+ // Helper function to wait given a duration type. The duration type should+ // either be of type boost::posix_time::time_duration, or implement the+ // required subset of its interface.+ template <typename Duration>+ void do_wait(const Duration& timeout, asio::error_code& ec)+ {+#if defined(ASIO_WINDOWS_RUNTIME)+ std::this_thread::sleep_for(+ std::chrono::seconds(timeout.total_seconds())+ + std::chrono::microseconds(timeout.total_microseconds()));+ ec = asio::error_code();+#else // defined(ASIO_WINDOWS_RUNTIME)+ ::timeval tv;+ tv.tv_sec = timeout.total_seconds();+ tv.tv_usec = timeout.total_microseconds() % 1000000;+ socket_ops::select(0, 0, 0, 0, &tv, ec);+#endif // defined(ASIO_WINDOWS_RUNTIME)+ }++ // The queue of timers.+ timer_queue<Time_Traits> timer_queue_;++ // The object that schedules and executes timers. Usually a reactor.+ timer_scheduler& scheduler_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/dependent_type.hpp view
@@ -0,0 +1,36 @@+//+// detail/dependent_type.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DEPENDENT_TYPE_HPP+#define ASIO_DETAIL_DEPENDENT_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 {+namespace detail {++template <typename DependsOn, typename T>+struct dependent_type+{+ typedef T type;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_DEPENDENT_TYPE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/descriptor_ops.hpp view
@@ -0,0 +1,139 @@+//+// detail/descriptor_ops.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DESCRIPTOR_OPS_HPP+#define ASIO_DETAIL_DESCRIPTOR_OPS_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_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)++#include <cstddef>+#include "asio/error.hpp"+#include "asio/error_code.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {+namespace descriptor_ops {++// Descriptor state bits.+enum+{+ // The user wants a non-blocking descriptor.+ user_set_non_blocking = 1,++ // The descriptor has been set non-blocking.+ internal_non_blocking = 2,++ // Helper "state" used to determine whether the descriptor is non-blocking.+ non_blocking = user_set_non_blocking | internal_non_blocking,++ // The descriptor may have been dup()-ed.+ possible_dup = 4+};++typedef unsigned char state_type;++inline void get_last_error(+ asio::error_code& ec, bool is_error_condition)+{+ if (!is_error_condition)+ {+ ec.assign(0, ec.category());+ }+ else+ {+ ec = asio::error_code(errno,+ asio::error::get_system_category());+ }+}++ASIO_DECL int open(const char* path, int flags,+ asio::error_code& ec);++ASIO_DECL int close(int d, state_type& state,+ asio::error_code& ec);++ASIO_DECL bool set_user_non_blocking(int d,+ state_type& state, bool value, asio::error_code& ec);++ASIO_DECL bool set_internal_non_blocking(int d,+ state_type& state, bool value, asio::error_code& ec);++typedef iovec buf;++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);++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::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,+ const buf* bufs, std::size_t count, bool all_empty,+ 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,+ const buf* bufs, std::size_t count,+ 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);++ASIO_DECL int ioctl(int d, state_type& state, long cmd,+ ioctl_arg_type* arg, asio::error_code& ec);++ASIO_DECL int fcntl(int d, int cmd, asio::error_code& ec);++ASIO_DECL int fcntl(int d, int cmd,+ long arg, asio::error_code& ec);++ASIO_DECL int poll_read(int d,+ state_type state, asio::error_code& ec);++ASIO_DECL int poll_write(int d,+ state_type state, asio::error_code& ec);++ASIO_DECL int poll_error(int d,+ state_type state, asio::error_code& ec);++} // namespace descriptor_ops+} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/descriptor_ops.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)++#endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/descriptor_read_op.hpp view
@@ -0,0 +1,148 @@+//+// detail/descriptor_read_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DESCRIPTOR_READ_OP_HPP+#define ASIO_DETAIL_DESCRIPTOR_READ_OP_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_WINDOWS) && !defined(__CYGWIN__)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/descriptor_ops.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename MutableBufferSequence>+class descriptor_read_op_base : public reactor_op+{+public:+ descriptor_read_op_base(const asio::error_code& success_ec,+ int descriptor, const MutableBufferSequence& buffers,+ func_type complete_func)+ : reactor_op(success_ec,+ &descriptor_read_op_base::do_perform, complete_func),+ descriptor_(descriptor),+ buffers_(buffers)+ {+ }++ static status do_perform(reactor_op* base)+ {+ descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base));++ typedef buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs_type;++ 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_)+ ? done : not_done;+ }++ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read",+ o->ec_, o->bytes_transferred_));++ return result;+ }++private:+ int descriptor_;+ MutableBufferSequence buffers_;+};++template <typename MutableBufferSequence, typename Handler, typename IoExecutor>+class descriptor_read_op+ : public descriptor_read_op_base<MutableBufferSequence>+{+public:+ ASIO_DEFINE_HANDLER_PTR(descriptor_read_op);++ descriptor_read_op(const asio::error_code& success_ec,+ int descriptor, const MutableBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ : descriptor_read_op_base<MutableBufferSequence>(success_ec,+ descriptor, buffers, &descriptor_read_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ 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.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++#endif // ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/descriptor_write_op.hpp view
@@ -0,0 +1,148 @@+//+// detail/descriptor_write_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DESCRIPTOR_WRITE_OP_HPP+#define ASIO_DETAIL_DESCRIPTOR_WRITE_OP_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_WINDOWS) && !defined(__CYGWIN__)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/descriptor_ops.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename ConstBufferSequence>+class descriptor_write_op_base : public reactor_op+{+public:+ descriptor_write_op_base(const asio::error_code& success_ec,+ int descriptor, const ConstBufferSequence& buffers,+ func_type complete_func)+ : reactor_op(success_ec,+ &descriptor_write_op_base::do_perform, complete_func),+ descriptor_(descriptor),+ buffers_(buffers)+ {+ }++ static status do_perform(reactor_op* base)+ {+ descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base));++ typedef buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence> bufs_type;++ 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_)+ ? done : not_done;+ }++ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write",+ o->ec_, o->bytes_transferred_));++ return result;+ }++private:+ int descriptor_;+ ConstBufferSequence buffers_;+};++template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+class descriptor_write_op+ : public descriptor_write_op_base<ConstBufferSequence>+{+public:+ ASIO_DEFINE_HANDLER_PTR(descriptor_write_op);++ descriptor_write_op(const asio::error_code& success_ec,+ int descriptor, const ConstBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ : descriptor_write_op_base<ConstBufferSequence>(success_ec,+ descriptor, buffers, &descriptor_write_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ 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.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++#endif // ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/dev_poll_reactor.hpp view
@@ -0,0 +1,218 @@+//+// detail/dev_poll_reactor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DEV_POLL_REACTOR_HPP+#define ASIO_DETAIL_DEV_POLL_REACTOR_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_DEV_POLL)++#include <cstddef>+#include <vector>+#include <sys/devpoll.h>+#include "asio/detail/hash_map.hpp"+#include "asio/detail/limits.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/reactor_op_queue.hpp"+#include "asio/detail/select_interrupter.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/timer_queue_base.hpp"+#include "asio/detail/timer_queue_set.hpp"+#include "asio/detail/wait_op.hpp"+#include "asio/execution_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class dev_poll_reactor+ : public execution_context_service_base<dev_poll_reactor>+{+public:+ enum op_types { read_op = 0, write_op = 1,+ connect_op = 1, except_op = 2, max_ops = 3 };++ // Per-descriptor data.+ struct per_descriptor_data+ {+ };++ // Constructor.+ ASIO_DECL dev_poll_reactor(asio::execution_context& ctx);++ // Destructor.+ ASIO_DECL ~dev_poll_reactor();++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Recreate internal descriptors following a fork.+ ASIO_DECL void notify_fork(+ asio::execution_context::fork_event fork_ev);++ // Initialise the task.+ ASIO_DECL void init_task();++ // Register a socket with the reactor. Returns 0 on success, system error+ // code on failure.+ ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);++ // Register a descriptor with an associated single operation. Returns 0 on+ // success, system error code on failure.+ ASIO_DECL int register_internal_descriptor(+ int op_type, socket_type descriptor,+ per_descriptor_data& descriptor_data, reactor_op* op);++ // Move descriptor registration from one descriptor_data object to another.+ ASIO_DECL void move_descriptor(socket_type descriptor,+ per_descriptor_data& target_descriptor_data,+ per_descriptor_data& source_descriptor_data);++ // Post a reactor operation for immediate completion.+ void post_immediate_completion(reactor_op* op, bool is_continuation)+ {+ scheduler_.post_immediate_completion(op, is_continuation);+ }++ // Start a new operation. The reactor operation will be performed when the+ // given descriptor is flagged as ready, or an error has occurred.+ ASIO_DECL void start_op(int op_type, socket_type descriptor,+ per_descriptor_data&, reactor_op* op,+ bool is_continuation, bool allow_speculative);++ // Cancel all operations associated with the given descriptor. The+ // handlers associated with the descriptor will be invoked with the+ // operation_aborted error.+ ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);++ // Cancel any operations that are running against the descriptor and remove+ // its registration from the reactor. The reactor resources associated with+ // the descriptor must be released by calling cleanup_descriptor_data.+ ASIO_DECL void deregister_descriptor(socket_type descriptor,+ per_descriptor_data&, bool closing);++ // Remove the descriptor's registration from the reactor. The reactor+ // resources associated with the descriptor must be released by calling+ // cleanup_descriptor_data.+ ASIO_DECL void deregister_internal_descriptor(+ socket_type descriptor, per_descriptor_data&);++ // Perform any post-deregistration cleanup tasks associated with the+ // descriptor data.+ ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&);++ // Add a new timer queue to the reactor.+ template <typename Time_Traits>+ void add_timer_queue(timer_queue<Time_Traits>& queue);++ // Remove a timer queue from the reactor.+ template <typename Time_Traits>+ void remove_timer_queue(timer_queue<Time_Traits>& queue);++ // Schedule a new operation in the given timer queue to expire at the+ // specified absolute time.+ template <typename Time_Traits>+ void schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);++ // Cancel the timer operations associated with the given token. Returns the+ // number of operations that have been posted or dispatched.+ template <typename Time_Traits>+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());++ // Move the timer operations associated with the given timer.+ template <typename Time_Traits>+ void move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& target,+ typename timer_queue<Time_Traits>::per_timer_data& source);++ // Run /dev/poll once until interrupted or events are ready to be dispatched.+ ASIO_DECL void run(long usec, op_queue<operation>& ops);++ // Interrupt the select loop.+ ASIO_DECL void interrupt();++private:+ // Create the /dev/poll file descriptor. Throws an exception if the descriptor+ // cannot be created.+ ASIO_DECL static int do_dev_poll_create();++ // Helper function to add a new timer queue.+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);++ // Helper function to remove a timer queue.+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);++ // Get the timeout value for the /dev/poll DP_POLL operation. The timeout+ // value is returned as a number of milliseconds. A return value of -1+ // indicates that the poll should block indefinitely.+ ASIO_DECL int get_timeout(int msec);++ // Cancel all operations associated with the given descriptor. The do_cancel+ // function of the handler objects will be invoked. This function does not+ // acquire the dev_poll_reactor's mutex.+ ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,+ const asio::error_code& ec);++ // Add a pending event entry for the given descriptor.+ ASIO_DECL ::pollfd& add_pending_event_change(int descriptor);++ // The scheduler implementation used to post completions.+ scheduler& scheduler_;++ // Mutex to protect access to internal data.+ asio::detail::mutex mutex_;++ // The /dev/poll file descriptor.+ int dev_poll_fd_;++ // Vector of /dev/poll events waiting to be written to the descriptor.+ std::vector< ::pollfd> pending_event_changes_;++ // Hash map to associate a descriptor with a pending event change index.+ hash_map<int, std::size_t> pending_event_change_index_;++ // The interrupter is used to break a blocking DP_POLL operation.+ select_interrupter interrupter_;++ // The queues of read, write and except operations.+ reactor_op_queue<socket_type> op_queue_[max_ops];++ // The timer queues.+ timer_queue_set timer_queues_;++ // Whether the service has been shut down.+ bool shutdown_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/detail/impl/dev_poll_reactor.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/dev_poll_reactor.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_DEV_POLL)++#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/epoll_reactor.hpp view
@@ -0,0 +1,266 @@+//+// detail/epoll_reactor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EPOLL_REACTOR_HPP+#define ASIO_DETAIL_EPOLL_REACTOR_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_EPOLL)++#include "asio/detail/atomic_count.hpp"+#include "asio/detail/conditionally_enabled_mutex.hpp"+#include "asio/detail/limits.hpp"+#include "asio/detail/object_pool.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/select_interrupter.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/timer_queue_base.hpp"+#include "asio/detail/timer_queue_set.hpp"+#include "asio/detail/wait_op.hpp"+#include "asio/execution_context.hpp"++#if defined(ASIO_HAS_TIMERFD)+# include <sys/timerfd.h>+#endif // defined(ASIO_HAS_TIMERFD)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class epoll_reactor+ : public execution_context_service_base<epoll_reactor>+{+private:+ // The mutex type used by this reactor.+ typedef conditionally_enabled_mutex mutex;++public:+ enum op_types { read_op = 0, write_op = 1,+ connect_op = 1, except_op = 2, max_ops = 3 };++ // Per-descriptor queues.+ class descriptor_state : operation+ {+ friend class epoll_reactor;+ friend class object_pool_access;++ descriptor_state* next_;+ descriptor_state* prev_;++ mutex mutex_;+ epoll_reactor* reactor_;+ int descriptor_;+ uint32_t registered_events_;+ op_queue<reactor_op> op_queue_[max_ops];+ bool try_speculative_[max_ops];+ bool shutdown_;++ ASIO_DECL descriptor_state(bool locking);+ void set_ready_events(uint32_t events) { task_result_ = events; }+ void add_ready_events(uint32_t events) { task_result_ |= events; }+ ASIO_DECL operation* perform_io(uint32_t events);+ ASIO_DECL static void do_complete(+ void* owner, operation* base,+ const asio::error_code& ec, std::size_t bytes_transferred);+ };++ // Per-descriptor data.+ typedef descriptor_state* per_descriptor_data;++ // Constructor.+ ASIO_DECL epoll_reactor(asio::execution_context& ctx);++ // Destructor.+ ASIO_DECL ~epoll_reactor();++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Recreate internal descriptors following a fork.+ ASIO_DECL void notify_fork(+ asio::execution_context::fork_event fork_ev);++ // Initialise the task.+ ASIO_DECL void init_task();++ // Register a socket with the reactor. Returns 0 on success, system error+ // code on failure.+ ASIO_DECL int register_descriptor(socket_type descriptor,+ per_descriptor_data& descriptor_data);++ // Register a descriptor with an associated single operation. Returns 0 on+ // success, system error code on failure.+ ASIO_DECL int register_internal_descriptor(+ int op_type, socket_type descriptor,+ per_descriptor_data& descriptor_data, reactor_op* op);++ // Move descriptor registration from one descriptor_data object to another.+ ASIO_DECL void move_descriptor(socket_type descriptor,+ per_descriptor_data& target_descriptor_data,+ per_descriptor_data& source_descriptor_data);++ // Post a reactor operation for immediate completion.+ void post_immediate_completion(reactor_op* op, bool is_continuation)+ {+ scheduler_.post_immediate_completion(op, is_continuation);+ }++ // Start a new operation. The reactor operation will be performed when the+ // given descriptor is flagged as ready, or an error has occurred.+ ASIO_DECL void start_op(int op_type, socket_type descriptor,+ per_descriptor_data& descriptor_data, reactor_op* op,+ bool is_continuation, bool allow_speculative);++ // Cancel all operations associated with the given descriptor. The+ // handlers associated with the descriptor will be invoked with the+ // operation_aborted error.+ ASIO_DECL void cancel_ops(socket_type descriptor,+ per_descriptor_data& descriptor_data);++ // Cancel any operations that are running against the descriptor and remove+ // its registration from the reactor. The reactor resources associated with+ // the descriptor must be released by calling cleanup_descriptor_data.+ ASIO_DECL void deregister_descriptor(socket_type descriptor,+ per_descriptor_data& descriptor_data, bool closing);++ // Remove the descriptor's registration from the reactor. The reactor+ // resources associated with the descriptor must be released by calling+ // cleanup_descriptor_data.+ ASIO_DECL void deregister_internal_descriptor(+ socket_type descriptor, per_descriptor_data& descriptor_data);++ // Perform any post-deregistration cleanup tasks associated with the+ // descriptor data.+ ASIO_DECL void cleanup_descriptor_data(+ per_descriptor_data& descriptor_data);++ // Add a new timer queue to the reactor.+ template <typename Time_Traits>+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue);++ // Remove a timer queue from the reactor.+ template <typename Time_Traits>+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);++ // Schedule a new operation in the given timer queue to expire at the+ // specified absolute time.+ template <typename Time_Traits>+ void schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);++ // Cancel the timer operations associated with the given token. Returns the+ // number of operations that have been posted or dispatched.+ template <typename Time_Traits>+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());++ // Move the timer operations associated with the given timer.+ template <typename Time_Traits>+ void move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& target,+ typename timer_queue<Time_Traits>::per_timer_data& source);++ // Run epoll once until interrupted or events are ready to be dispatched.+ ASIO_DECL void run(long usec, op_queue<operation>& ops);++ // Interrupt the select loop.+ ASIO_DECL void interrupt();++private:+ // The hint to pass to epoll_create to size its data structures.+ enum { epoll_size = 20000 };++ // Create the epoll file descriptor. Throws an exception if the descriptor+ // cannot be created.+ ASIO_DECL static int do_epoll_create();++ // Create the timerfd file descriptor. Does not throw.+ ASIO_DECL static int do_timerfd_create();++ // Allocate a new descriptor state object.+ ASIO_DECL descriptor_state* allocate_descriptor_state();++ // Free an existing descriptor state object.+ ASIO_DECL void free_descriptor_state(descriptor_state* s);++ // Helper function to add a new timer queue.+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);++ // Helper function to remove a timer queue.+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);++ // Called to recalculate and update the timeout.+ ASIO_DECL void update_timeout();++ // Get the timeout value for the epoll_wait call. The timeout value is+ // returned as a number of milliseconds. A return value of -1 indicates+ // that epoll_wait should block indefinitely.+ ASIO_DECL int get_timeout(int msec);++#if defined(ASIO_HAS_TIMERFD)+ // Get the timeout value for the timer descriptor. The return value is the+ // flag argument to be used when calling timerfd_settime.+ ASIO_DECL int get_timeout(itimerspec& ts);+#endif // defined(ASIO_HAS_TIMERFD)++ // The scheduler implementation used to post completions.+ scheduler& scheduler_;++ // Mutex to protect access to internal data.+ mutex mutex_;++ // The interrupter is used to break a blocking epoll_wait call.+ select_interrupter interrupter_;++ // The epoll file descriptor.+ int epoll_fd_;++ // The timer file descriptor.+ int timer_fd_;++ // The timer queues.+ timer_queue_set timer_queues_;++ // Whether the service has been shut down.+ bool shutdown_;++ // Mutex to protect access to the registered descriptors.+ mutex registered_descriptors_mutex_;++ // Keep track of all registered descriptors.+ object_pool<descriptor_state> registered_descriptors_;++ // Helper class to do post-perform_io cleanup.+ struct perform_io_cleanup_on_block_exit;+ friend struct perform_io_cleanup_on_block_exit;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/detail/impl/epoll_reactor.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/epoll_reactor.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_EPOLL)++#endif // ASIO_DETAIL_EPOLL_REACTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/event.hpp view
@@ -0,0 +1,48 @@+//+// detail/event.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EVENT_HPP+#define ASIO_DETAIL_EVENT_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_THREADS)+# include "asio/detail/null_event.hpp"+#elif defined(ASIO_WINDOWS)+# include "asio/detail/win_event.hpp"+#elif defined(ASIO_HAS_PTHREADS)+# include "asio/detail/posix_event.hpp"+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)+# include "asio/detail/std_event.hpp"+#else+# error Only Windows, POSIX and std::condition_variable are supported!+#endif++namespace asio {+namespace detail {++#if !defined(ASIO_HAS_THREADS)+typedef null_event event;+#elif defined(ASIO_WINDOWS)+typedef win_event event;+#elif defined(ASIO_HAS_PTHREADS)+typedef posix_event event;+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)+typedef std_event event;+#endif++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_EVENT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/eventfd_select_interrupter.hpp view
@@ -0,0 +1,83 @@+//+// detail/eventfd_select_interrupter.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail 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_EVENTFD_SELECT_INTERRUPTER_HPP+#define ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_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_EVENTFD)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class eventfd_select_interrupter+{+public:+ // Constructor.+ ASIO_DECL eventfd_select_interrupter();++ // Destructor.+ ASIO_DECL ~eventfd_select_interrupter();++ // Recreate the interrupter's descriptors. Used after a fork.+ ASIO_DECL void recreate();++ // Interrupt the select call.+ ASIO_DECL void interrupt();++ // Reset the select interrupter. Returns true if the reset was successful.+ ASIO_DECL bool reset();++ // Get the read descriptor to be passed to select.+ int read_descriptor() const+ {+ return read_descriptor_;+ }++private:+ // Open the descriptors. Throws on error.+ ASIO_DECL void open_descriptors();++ // Close the descriptors.+ ASIO_DECL void close_descriptors();++ // The read end of a connection used to interrupt the select call. This file+ // descriptor is passed to select such that when it is time to stop, a single+ // 64bit value will be written on the other end of the connection and this+ // descriptor will become readable.+ int read_descriptor_;++ // The write end of a connection used to interrupt the select call. A single+ // 64bit non-zero value may be written to this to wake up the select which is+ // waiting for the other end to become readable. This descriptor will only+ // differ from the read descriptor when a pipe is used.+ int write_descriptor_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/eventfd_select_interrupter.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_EVENTFD)++#endif // ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/executor_function.hpp view
@@ -0,0 +1,203 @@+//+// detail/executor_function.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 {++#if defined(ASIO_HAS_MOVE)++// 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(ASIO_MOVE_CAST(F)(f), a);+ p.v = 0;+ }++ executor_function(executor_function&& other) ASIO_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(ASIO_MOVE_ARG(F) f, const Alloc& a)+ : function_(ASIO_MOVE_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(ASIO_MOVE_CAST(Function)(i->function_));+ p.reset();++ // Make the upcall if required.+ if (call)+ {+ function();+ }+ }++ impl_base* impl_;+};++#else // defined(ASIO_HAS_MOVE)++// Not so lightweight, copyable function object wrapper.+class executor_function+{+public:+ template <typename F, typename Alloc>+ explicit executor_function(const F& f, const Alloc&)+ : impl_(new impl<typename decay<F>::type>(f))+ {+ }++ void operator()()+ {+ impl_->complete_(impl_.get());+ }++private:+ // Base class for polymorphic function implementations.+ struct impl_base+ {+ void (*complete_)(impl_base*);+ };++ // Polymorphic function implementation.+ template <typename F>+ struct impl : impl_base+ {+ impl(const F& f)+ : function_(f)+ {+ complete_ = &executor_function::complete<F>;+ }++ F function_;+ };++ // Helper to complete function invocation.+ template <typename F>+ static void complete(impl_base* i)+ {+ static_cast<impl<F>*>(i)->function_();+ }++ shared_ptr<impl_base> impl_;+};++#endif // defined(ASIO_HAS_MOVE)++// Lightweight, non-owning, copyable function object wrapper.+class executor_function_view+{+public:+ template <typename F>+ explicit executor_function_view(F& f) ASIO_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
+ link/modules/asio-standalone/asio/include/asio/detail/executor_op.hpp view
@@ -0,0 +1,84 @@+//+// detail/executor_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_OP_HPP+#define ASIO_DETAIL_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/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/scheduler_operation.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename Alloc,+ typename Operation = scheduler_operation>+class executor_op : public Operation+{+public:+ ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op);++ template <typename H>+ executor_op(ASIO_MOVE_ARG(H) h, const Alloc& allocator)+ : Operation(&executor_op::do_complete),+ handler_(ASIO_MOVE_CAST(H)(h)),+ allocator_(allocator)+ {+ }++ static void do_complete(void* owner, Operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ executor_op* o(static_cast<executor_op*>(base));+ Alloc allocator(o->allocator_);+ ptr p = { detail::addressof(allocator), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // 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.+ Handler handler(ASIO_MOVE_CAST(Handler)(o->handler_));+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN(());+ asio_handler_invoke_helpers::invoke(handler, handler);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ Alloc allocator_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_EXECUTOR_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/fd_set_adapter.hpp view
@@ -0,0 +1,39 @@+//+// detail/fd_set_adapter.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_FD_SET_ADAPTER_HPP+#define ASIO_DETAIL_FD_SET_ADAPTER_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_WINDOWS_RUNTIME)++#include "asio/detail/posix_fd_set_adapter.hpp"+#include "asio/detail/win_fd_set_adapter.hpp"++namespace asio {+namespace detail {++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+typedef win_fd_set_adapter fd_set_adapter;+#else+typedef posix_fd_set_adapter fd_set_adapter;+#endif++} // namespace detail+} // namespace asio++#endif // !defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/fenced_block.hpp view
@@ -0,0 +1,80 @@+//+// detail/fenced_block.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_FENCED_BLOCK_HPP+#define ASIO_DETAIL_FENCED_BLOCK_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_THREADS) \+ || defined(ASIO_DISABLE_FENCED_BLOCK)+# include "asio/detail/null_fenced_block.hpp"+#elif defined(ASIO_HAS_STD_ATOMIC)+# include "asio/detail/std_fenced_block.hpp"+#elif defined(__MACH__) && defined(__APPLE__)+# include "asio/detail/macos_fenced_block.hpp"+#elif defined(__sun)+# include "asio/detail/solaris_fenced_block.hpp"+#elif defined(__GNUC__) && defined(__arm__) \+ && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)+# include "asio/detail/gcc_arm_fenced_block.hpp"+#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))+# include "asio/detail/gcc_hppa_fenced_block.hpp"+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))+# include "asio/detail/gcc_x86_fenced_block.hpp"+#elif defined(__GNUC__) \+ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \+ && !defined(__INTEL_COMPILER) && !defined(__ICL) \+ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)+# include "asio/detail/gcc_sync_fenced_block.hpp"+#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE)+# include "asio/detail/win_fenced_block.hpp"+#else+# include "asio/detail/null_fenced_block.hpp"+#endif++namespace asio {+namespace detail {++#if !defined(ASIO_HAS_THREADS) \+ || defined(ASIO_DISABLE_FENCED_BLOCK)+typedef null_fenced_block fenced_block;+#elif defined(ASIO_HAS_STD_ATOMIC)+typedef std_fenced_block fenced_block;+#elif defined(__MACH__) && defined(__APPLE__)+typedef macos_fenced_block fenced_block;+#elif defined(__sun)+typedef solaris_fenced_block fenced_block;+#elif defined(__GNUC__) && defined(__arm__) \+ && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)+typedef gcc_arm_fenced_block fenced_block;+#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))+typedef gcc_hppa_fenced_block fenced_block;+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))+typedef gcc_x86_fenced_block fenced_block;+#elif defined(__GNUC__) \+ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \+ && !defined(__INTEL_COMPILER) && !defined(__ICL) \+ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)+typedef gcc_sync_fenced_block fenced_block;+#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE)+typedef win_fenced_block fenced_block;+#else+typedef null_fenced_block fenced_block;+#endif++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_FENCED_BLOCK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/functional.hpp view
@@ -0,0 +1,38 @@+//+// detail/functional.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_FUNCTIONAL_HPP+#define ASIO_DETAIL_FUNCTIONAL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <functional>++#if !defined(ASIO_HAS_STD_FUNCTION)+# include <boost/function.hpp>+#endif // !defined(ASIO_HAS_STD_FUNCTION)++namespace asio {+namespace detail {++#if defined(ASIO_HAS_STD_FUNCTION)+using std::function;+#else // defined(ASIO_HAS_STD_FUNCTION)+using boost::function;+#endif // defined(ASIO_HAS_STD_FUNCTION)++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_FUNCTIONAL_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/future.hpp view
@@ -0,0 +1,33 @@+//+// detail/future.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_FUTURE_HPP+#define ASIO_DETAIL_FUTURE_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_STD_FUTURE)+# include <future>+// Even though the future header is available, libstdc++ may not implement the+// std::future class itself. However, we need to have already included the+// future header to reliably test for _GLIBCXX_HAS_GTHREADS.+# if defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX)+# if defined(_GLIBCXX_HAS_GTHREADS)+# define ASIO_HAS_STD_FUTURE_CLASS 1+# endif // defined(_GLIBCXX_HAS_GTHREADS)+# else // defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX)+# define ASIO_HAS_STD_FUTURE_CLASS 1+# endif // defined(__GNUC__) && !defined(ASIO_HAS_CLANG_LIBCXX)+#endif // defined(ASIO_HAS_STD_FUTURE)++#endif // ASIO_DETAIL_FUTURE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/gcc_arm_fenced_block.hpp view
@@ -0,0 +1,91 @@+//+// detail/gcc_arm_fenced_block.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GCC_ARM_FENCED_BLOCK_HPP+#define ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(__GNUC__) && defined(__arm__)++#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class gcc_arm_fenced_block+ : private noncopyable+{+public:+ enum half_t { half };+ enum full_t { full };++ // Constructor for a half fenced block.+ explicit gcc_arm_fenced_block(half_t)+ {+ }++ // Constructor for a full fenced block.+ explicit gcc_arm_fenced_block(full_t)+ {+ barrier();+ }++ // Destructor.+ ~gcc_arm_fenced_block()+ {+ barrier();+ }++private:+ static void barrier()+ {+#if defined(__ARM_ARCH_4__) \+ || defined(__ARM_ARCH_4T__) \+ || defined(__ARM_ARCH_5__) \+ || defined(__ARM_ARCH_5E__) \+ || defined(__ARM_ARCH_5T__) \+ || defined(__ARM_ARCH_5TE__) \+ || defined(__ARM_ARCH_5TEJ__) \+ || defined(__ARM_ARCH_6__) \+ || defined(__ARM_ARCH_6J__) \+ || defined(__ARM_ARCH_6K__) \+ || defined(__ARM_ARCH_6Z__) \+ || defined(__ARM_ARCH_6ZK__) \+ || defined(__ARM_ARCH_6T2__)+# if defined(__thumb__)+ // This is just a placeholder and almost certainly not sufficient.+ __asm__ __volatile__ ("" : : : "memory");+# else // defined(__thumb__)+ int a = 0, b = 0;+ __asm__ __volatile__ ("swp %0, %1, [%2]"+ : "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc");+# endif // defined(__thumb__)+#else+ // ARMv7 and later.+ __asm__ __volatile__ ("dmb" : : : "memory");+#endif+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(__GNUC__) && defined(__arm__)++#endif // ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/gcc_hppa_fenced_block.hpp view
@@ -0,0 +1,68 @@+//+// detail/gcc_hppa_fenced_block.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GCC_HPPA_FENCED_BLOCK_HPP+#define ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))++#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class gcc_hppa_fenced_block+ : private noncopyable+{+public:+ enum half_t { half };+ enum full_t { full };++ // Constructor for a half fenced block.+ explicit gcc_hppa_fenced_block(half_t)+ {+ }++ // Constructor for a full fenced block.+ explicit gcc_hppa_fenced_block(full_t)+ {+ barrier();+ }++ // Destructor.+ ~gcc_hppa_fenced_block()+ {+ barrier();+ }++private:+ static void barrier()+ {+ // This is just a placeholder and almost certainly not sufficient.+ __asm__ __volatile__ ("" : : : "memory");+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))++#endif // ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/gcc_sync_fenced_block.hpp view
@@ -0,0 +1,65 @@+//+// detail/gcc_sync_fenced_block.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GCC_SYNC_FENCED_BLOCK_HPP+#define ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(__GNUC__) \+ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \+ && !defined(__INTEL_COMPILER) && !defined(__ICL) \+ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)++#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class gcc_sync_fenced_block+ : private noncopyable+{+public:+ enum half_or_full_t { half, full };++ // Constructor.+ explicit gcc_sync_fenced_block(half_or_full_t)+ : value_(0)+ {+ __sync_lock_test_and_set(&value_, 1);+ }++ // Destructor.+ ~gcc_sync_fenced_block()+ {+ __sync_lock_release(&value_);+ }++private:+ int value_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(__GNUC__)+ // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4))+ // && !defined(__INTEL_COMPILER) && !defined(__ICL)+ // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)++#endif // ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/gcc_x86_fenced_block.hpp view
@@ -0,0 +1,99 @@+//+// detail/gcc_x86_fenced_block.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GCC_X86_FENCED_BLOCK_HPP+#define ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))++#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class gcc_x86_fenced_block+ : private noncopyable+{+public:+ enum half_t { half };+ enum full_t { full };++ // Constructor for a half fenced block.+ explicit gcc_x86_fenced_block(half_t)+ {+ }++ // Constructor for a full fenced block.+ explicit gcc_x86_fenced_block(full_t)+ {+ lbarrier();+ }++ // Destructor.+ ~gcc_x86_fenced_block()+ {+ sbarrier();+ }++private:+ static int barrier()+ {+ int r = 0, m = 1;+ __asm__ __volatile__ (+ "xchgl %0, %1" :+ "=r"(r), "=m"(m) :+ "0"(1), "m"(m) :+ "memory", "cc");+ return r;+ }++ static void lbarrier()+ {+#if defined(__SSE2__)+# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)+ __builtin_ia32_lfence();+# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)+ __asm__ __volatile__ ("lfence" ::: "memory");+# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)+#else // defined(__SSE2__)+ barrier();+#endif // defined(__SSE2__)+ }++ static void sbarrier()+ {+#if defined(__SSE2__)+# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)+ __builtin_ia32_sfence();+# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)+ __asm__ __volatile__ ("sfence" ::: "memory");+# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)+#else // defined(__SSE2__)+ barrier();+#endif // defined(__SSE2__)+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))++#endif // ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/global.hpp view
@@ -0,0 +1,52 @@+//+// detail/global.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GLOBAL_HPP+#define ASIO_DETAIL_GLOBAL_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_THREADS)+# include "asio/detail/null_global.hpp"+#elif defined(ASIO_WINDOWS)+# include "asio/detail/win_global.hpp"+#elif defined(ASIO_HAS_PTHREADS)+# include "asio/detail/posix_global.hpp"+#elif defined(ASIO_HAS_STD_CALL_ONCE)+# include "asio/detail/std_global.hpp"+#else+# error Only Windows, POSIX and std::call_once are supported!+#endif++namespace asio {+namespace detail {++template <typename T>+inline T& global()+{+#if !defined(ASIO_HAS_THREADS)+ return null_global<T>();+#elif defined(ASIO_WINDOWS)+ return win_global<T>();+#elif defined(ASIO_HAS_PTHREADS)+ return posix_global<T>();+#elif defined(ASIO_HAS_STD_CALL_ONCE)+ return std_global<T>();+#endif+}++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_GLOBAL_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/handler_alloc_helpers.hpp view
@@ -0,0 +1,284 @@+//+// detail/handler_alloc_helpers.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HANDLER_ALLOC_HELPERS_HPP+#define ASIO_DETAIL_HANDLER_ALLOC_HELPERS_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/memory.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/recycling_allocator.hpp"+#include "asio/detail/thread_info_base.hpp"+#include "asio/associated_allocator.hpp"+#include "asio/handler_alloc_hook.hpp"++#include "asio/detail/push_options.hpp"++// Calls to asio_handler_allocate and asio_handler_deallocate must be made from+// a namespace that does not contain any overloads of these functions. The+// asio_handler_alloc_helpers namespace is defined here for that purpose.+namespace asio_handler_alloc_helpers {++#if defined(ASIO_NO_DEPRECATED)+template <typename Handler>+inline void error_if_hooks_are_defined(Handler& h)+{+ using asio::asio_handler_allocate;+ // If you get an error here it is because some of your handlers still+ // overload asio_handler_allocate, but this hook is no longer used.+ (void)static_cast<asio::asio_handler_allocate_is_no_longer_used>(+ asio_handler_allocate(static_cast<std::size_t>(0),+ asio::detail::addressof(h)));++ using asio::asio_handler_deallocate;+ // If you get an error here it is because some of your handlers still+ // overload asio_handler_deallocate, but this hook is no longer used.+ (void)static_cast<asio::asio_handler_deallocate_is_no_longer_used>(+ asio_handler_deallocate(static_cast<void*>(0),+ static_cast<std::size_t>(0), asio::detail::addressof(h)));+}+#endif // defined(ASIO_NO_DEPRECATED)++template <typename Handler>+inline void* allocate(std::size_t s, Handler& h)+{+#if !defined(ASIO_HAS_HANDLER_HOOKS)+ return ::operator new(s);+#elif defined(ASIO_NO_DEPRECATED)+ // The asio_handler_allocate hook is no longer used to obtain memory.+ (void)&error_if_hooks_are_defined<Handler>;+ (void)h;+#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+ return asio::detail::thread_info_base::allocate(+ asio::detail::thread_context::thread_call_stack::top(), s);+#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+ return ::operator new(size);+#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+#else+ using asio::asio_handler_allocate;+ return asio_handler_allocate(s, asio::detail::addressof(h));+#endif+}++template <typename Handler>+inline void deallocate(void* p, std::size_t s, Handler& h)+{+#if !defined(ASIO_HAS_HANDLER_HOOKS)+ ::operator delete(p);+#elif defined(ASIO_NO_DEPRECATED)+ // The asio_handler_allocate hook is no longer used to obtain memory.+ (void)&error_if_hooks_are_defined<Handler>;+ (void)h;+#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+ asio::detail::thread_info_base::deallocate(+ asio::detail::thread_context::thread_call_stack::top(), p, s);+#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+ (void)s;+ ::operator delete(p);+#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+#else+ using asio::asio_handler_deallocate;+ asio_handler_deallocate(p, s, asio::detail::addressof(h));+#endif+}++} // namespace asio_handler_alloc_helpers++namespace asio {+namespace detail {++template <typename Handler, typename T>+class hook_allocator+{+public:+ typedef T value_type;++ template <typename U>+ struct rebind+ {+ typedef hook_allocator<Handler, U> other;+ };++ explicit hook_allocator(Handler& h)+ : handler_(h)+ {+ }++ template <typename U>+ hook_allocator(const hook_allocator<Handler, U>& a)+ : handler_(a.handler_)+ {+ }++ T* allocate(std::size_t n)+ {+ return static_cast<T*>(+ asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_));+ }++ void deallocate(T* p, std::size_t n)+ {+ asio_handler_alloc_helpers::deallocate(p, sizeof(T) * n, handler_);+ }++//private:+ Handler& handler_;+};++template <typename Handler>+class hook_allocator<Handler, void>+{+public:+ typedef void value_type;++ template <typename U>+ struct rebind+ {+ typedef hook_allocator<Handler, U> other;+ };++ explicit hook_allocator(Handler& h)+ : handler_(h)+ {+ }++ template <typename U>+ hook_allocator(const hook_allocator<Handler, U>& a)+ : handler_(a.handler_)+ {+ }++//private:+ Handler& handler_;+};++template <typename Handler, typename Allocator>+struct get_hook_allocator+{+ typedef Allocator type;++ static type get(Handler&, const Allocator& a)+ {+ return a;+ }+};++template <typename Handler, typename T>+struct get_hook_allocator<Handler, std::allocator<T> >+{+ typedef hook_allocator<Handler, T> type;++ static type get(Handler& handler, const std::allocator<T>&)+ {+ return type(handler);+ }+};++} // namespace detail+} // namespace asio++#define ASIO_DEFINE_HANDLER_PTR(op) \+ struct ptr \+ { \+ Handler* h; \+ op* v; \+ op* p; \+ ~ptr() \+ { \+ reset(); \+ } \+ static op* allocate(Handler& handler) \+ { \+ typedef typename ::asio::associated_allocator< \+ Handler>::type associated_allocator_type; \+ typedef typename ::asio::detail::get_hook_allocator< \+ Handler, associated_allocator_type>::type hook_allocator_type; \+ ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \+ ::asio::detail::get_hook_allocator< \+ Handler, associated_allocator_type>::get( \+ handler, ::asio::get_associated_allocator(handler))); \+ return a.allocate(1); \+ } \+ void reset() \+ { \+ if (p) \+ { \+ p->~op(); \+ p = 0; \+ } \+ if (v) \+ { \+ typedef typename ::asio::associated_allocator< \+ Handler>::type associated_allocator_type; \+ typedef typename ::asio::detail::get_hook_allocator< \+ Handler, associated_allocator_type>::type hook_allocator_type; \+ ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \+ ::asio::detail::get_hook_allocator< \+ Handler, associated_allocator_type>::get( \+ *h, ::asio::get_associated_allocator(*h))); \+ a.deallocate(static_cast<op*>(v), 1); \+ v = 0; \+ } \+ } \+ } \+ /**/++#define ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(purpose, op) \+ struct ptr \+ { \+ const Alloc* a; \+ void* v; \+ op* p; \+ ~ptr() \+ { \+ reset(); \+ } \+ static op* allocate(const Alloc& a) \+ { \+ typedef typename ::asio::detail::get_recycling_allocator< \+ Alloc, purpose>::type recycling_allocator_type; \+ ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \+ ::asio::detail::get_recycling_allocator< \+ Alloc, purpose>::get(a)); \+ return a1.allocate(1); \+ } \+ void reset() \+ { \+ if (p) \+ { \+ p->~op(); \+ p = 0; \+ } \+ if (v) \+ { \+ typedef typename ::asio::detail::get_recycling_allocator< \+ Alloc, purpose>::type recycling_allocator_type; \+ ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \+ ::asio::detail::get_recycling_allocator< \+ Alloc, purpose>::get(*a)); \+ a1.deallocate(static_cast<op*>(v), 1); \+ v = 0; \+ } \+ } \+ } \+ /**/++#define ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op) \+ ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( \+ ::asio::detail::thread_info_base::default_tag, op ) \+ /**/++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/handler_cont_helpers.hpp view
@@ -0,0 +1,45 @@+//+// detail/handler_cont_helpers.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HANDLER_CONT_HELPERS_HPP+#define ASIO_DETAIL_HANDLER_CONT_HELPERS_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/memory.hpp"+#include "asio/handler_continuation_hook.hpp"++#include "asio/detail/push_options.hpp"++// Calls to asio_handler_is_continuation must be made from a namespace that+// does not contain overloads of this function. This namespace is defined here+// for that purpose.+namespace asio_handler_cont_helpers {++template <typename Context>+inline bool is_continuation(Context& context)+{+#if !defined(ASIO_HAS_HANDLER_HOOKS)+ return false;+#else+ using asio::asio_handler_is_continuation;+ return asio_handler_is_continuation(+ asio::detail::addressof(context));+#endif+}++} // namespace asio_handler_cont_helpers++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/handler_invoke_helpers.hpp view
@@ -0,0 +1,80 @@+//+// detail/handler_invoke_helpers.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HANDLER_INVOKE_HELPERS_HPP+#define ASIO_DETAIL_HANDLER_INVOKE_HELPERS_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/memory.hpp"+#include "asio/handler_invoke_hook.hpp"++#include "asio/detail/push_options.hpp"++// Calls to asio_handler_invoke must be made from a namespace that does not+// contain overloads of this function. The asio_handler_invoke_helpers+// namespace is defined here for that purpose.+namespace asio_handler_invoke_helpers {++#if defined(ASIO_NO_DEPRECATED)+template <typename Function, typename Context>+inline void error_if_hook_is_defined(Function& function, Context& context)+{+ using asio::asio_handler_invoke;+ // If you get an error here it is because some of your handlers still+ // overload asio_handler_invoke, but this hook is no longer used.+ (void)static_cast<asio::asio_handler_invoke_is_no_longer_used>(+ asio_handler_invoke(function, asio::detail::addressof(context)));+}+#endif // defined(ASIO_NO_DEPRECATED)++template <typename Function, typename Context>+inline void invoke(Function& function, Context& context)+{+#if !defined(ASIO_HAS_HANDLER_HOOKS)+ Function tmp(function);+ tmp();+#elif defined(ASIO_NO_DEPRECATED)+ // The asio_handler_invoke hook is no longer used to invoke the function.+ (void)&error_if_hook_is_defined<Function, Context>;+ (void)context;+ function();+#else+ using asio::asio_handler_invoke;+ asio_handler_invoke(function, asio::detail::addressof(context));+#endif+}++template <typename Function, typename Context>+inline void invoke(const Function& function, Context& context)+{+#if !defined(ASIO_HAS_HANDLER_HOOKS)+ Function tmp(function);+ tmp();+#elif defined(ASIO_NO_DEPRECATED)+ // The asio_handler_invoke hook is no longer used to invoke the function.+ (void)&error_if_hook_is_defined<const Function, Context>;+ (void)context;+ Function tmp(function);+ tmp();+#else+ using asio::asio_handler_invoke;+ asio_handler_invoke(function, asio::detail::addressof(context));+#endif+}++} // namespace asio_handler_invoke_helpers++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/handler_tracking.hpp view
@@ -0,0 +1,264 @@+//+// detail/handler_tracking.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HANDLER_TRACKING_HPP+#define ASIO_DETAIL_HANDLER_TRACKING_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++namespace asio {++class execution_context;++} // namespace asio++#if defined(ASIO_CUSTOM_HANDLER_TRACKING)+# include ASIO_CUSTOM_HANDLER_TRACKING+#elif defined(ASIO_ENABLE_HANDLER_TRACKING)+# include "asio/error_code.hpp"+# include "asio/detail/cstdint.hpp"+# include "asio/detail/static_mutex.hpp"+# include "asio/detail/tss_ptr.hpp"+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++#if defined(ASIO_CUSTOM_HANDLER_TRACKING)++// The user-specified header must define the following macros:+// - ASIO_INHERIT_TRACKED_HANDLER+// - ASIO_ALSO_INHERIT_TRACKED_HANDLER+// - ASIO_HANDLER_TRACKING_INIT+// - ASIO_HANDLER_CREATION(args)+// - ASIO_HANDLER_COMPLETION(args)+// - ASIO_HANDLER_INVOCATION_BEGIN(args)+// - ASIO_HANDLER_INVOCATION_END+// - ASIO_HANDLER_OPERATION(args)+// - ASIO_HANDLER_REACTOR_REGISTRATION(args)+// - ASIO_HANDLER_REACTOR_DEREGISTRATION(args)+// - ASIO_HANDLER_REACTOR_READ_EVENT+// - ASIO_HANDLER_REACTOR_WRITE_EVENT+// - ASIO_HANDLER_REACTOR_ERROR_EVENT+// - ASIO_HANDLER_REACTOR_EVENTS(args)+// - ASIO_HANDLER_REACTOR_OPERATION(args)++# if !defined(ASIO_ENABLE_HANDLER_TRACKING)+# define ASIO_ENABLE_HANDLER_TRACKING 1+# endif /// !defined(ASIO_ENABLE_HANDLER_TRACKING)++#elif defined(ASIO_ENABLE_HANDLER_TRACKING)++class handler_tracking+{+public:+ class completion;++ // Base class for objects containing tracked handlers.+ class tracked_handler+ {+ private:+ // Only the handler_tracking class will have access to the id.+ friend class handler_tracking;+ friend class completion;+ uint64_t id_;++ protected:+ // Constructor initialises with no id.+ tracked_handler() : id_(0) {}++ // Prevent deletion through this type.+ ~tracked_handler() {}+ };++ // Initialise the tracking system.+ ASIO_DECL static void init();++ class location+ {+ public:+ // Constructor adds a location to the stack.+ ASIO_DECL explicit location(const char* file,+ int line, const char* func);++ // Destructor removes a location from the stack.+ ASIO_DECL ~location();++ private:+ // Disallow copying and assignment.+ location(const location&) ASIO_DELETED;+ location& operator=(const location&) ASIO_DELETED;++ friend class handler_tracking;+ const char* file_;+ int line_;+ const char* func_;+ location* next_;+ };++ // Record the creation of a tracked handler.+ ASIO_DECL static void creation(+ execution_context& context, tracked_handler& h,+ const char* object_type, void* object,+ uintmax_t native_handle, const char* op_name);++ class completion+ {+ public:+ // Constructor records that handler is to be invoked with no arguments.+ ASIO_DECL explicit completion(const tracked_handler& h);++ // Destructor records only when an exception is thrown from the handler, or+ // if the memory is being freed without the handler having been invoked.+ ASIO_DECL ~completion();++ // Records that handler is to be invoked with no arguments.+ ASIO_DECL void invocation_begin();++ // Records that handler is to be invoked with one arguments.+ ASIO_DECL void invocation_begin(const asio::error_code& ec);++ // Constructor records that handler is to be invoked with two arguments.+ ASIO_DECL void invocation_begin(+ const asio::error_code& ec, std::size_t bytes_transferred);++ // Constructor records that handler is to be invoked with two arguments.+ ASIO_DECL void invocation_begin(+ const asio::error_code& ec, int signal_number);++ // Constructor records that handler is to be invoked with two arguments.+ ASIO_DECL void invocation_begin(+ const asio::error_code& ec, const char* arg);++ // Record that handler invocation has ended.+ ASIO_DECL void invocation_end();++ private:+ friend class handler_tracking;+ uint64_t id_;+ bool invoked_;+ completion* next_;+ };++ // Record an operation that is not directly associated with a handler.+ ASIO_DECL static void operation(execution_context& context,+ const char* object_type, void* object,+ uintmax_t native_handle, const char* op_name);++ // Record that a descriptor has been registered with the reactor.+ ASIO_DECL static void reactor_registration(execution_context& context,+ uintmax_t native_handle, uintmax_t registration);++ // Record that a descriptor has been deregistered from the reactor.+ ASIO_DECL static void reactor_deregistration(execution_context& context,+ uintmax_t native_handle, uintmax_t registration);++ // Record a reactor-based operation that is associated with a handler.+ ASIO_DECL static void reactor_events(execution_context& context,+ uintmax_t registration, unsigned events);++ // Record a reactor-based operation that is associated with a handler.+ ASIO_DECL static void reactor_operation(+ const tracked_handler& h, const char* op_name,+ const asio::error_code& ec);++ // Record a reactor-based operation that is associated with a handler.+ ASIO_DECL static void reactor_operation(+ const tracked_handler& h, const char* op_name,+ const asio::error_code& ec, std::size_t bytes_transferred);++ // Write a line of output.+ ASIO_DECL static void write_line(const char* format, ...);++private:+ struct tracking_state;+ ASIO_DECL static tracking_state* get_state();+};++# define ASIO_INHERIT_TRACKED_HANDLER \+ : public asio::detail::handler_tracking::tracked_handler++# define ASIO_ALSO_INHERIT_TRACKED_HANDLER \+ , public asio::detail::handler_tracking::tracked_handler++# define ASIO_HANDLER_TRACKING_INIT \+ asio::detail::handler_tracking::init()++# define ASIO_HANDLER_LOCATION(args) \+ asio::detail::handler_tracking::location tracked_location args++# define ASIO_HANDLER_CREATION(args) \+ asio::detail::handler_tracking::creation args++# define ASIO_HANDLER_COMPLETION(args) \+ asio::detail::handler_tracking::completion tracked_completion args++# define ASIO_HANDLER_INVOCATION_BEGIN(args) \+ tracked_completion.invocation_begin args++# define ASIO_HANDLER_INVOCATION_END \+ tracked_completion.invocation_end()++# define ASIO_HANDLER_OPERATION(args) \+ asio::detail::handler_tracking::operation args++# define ASIO_HANDLER_REACTOR_REGISTRATION(args) \+ asio::detail::handler_tracking::reactor_registration args++# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \+ asio::detail::handler_tracking::reactor_deregistration args++# define ASIO_HANDLER_REACTOR_READ_EVENT 1+# define ASIO_HANDLER_REACTOR_WRITE_EVENT 2+# define ASIO_HANDLER_REACTOR_ERROR_EVENT 4++# define ASIO_HANDLER_REACTOR_EVENTS(args) \+ asio::detail::handler_tracking::reactor_events args++# define ASIO_HANDLER_REACTOR_OPERATION(args) \+ asio::detail::handler_tracking::reactor_operation args++#else // defined(ASIO_ENABLE_HANDLER_TRACKING)++# define ASIO_INHERIT_TRACKED_HANDLER+# define ASIO_ALSO_INHERIT_TRACKED_HANDLER+# define ASIO_HANDLER_TRACKING_INIT (void)0+# define ASIO_HANDLER_LOCATION(loc) (void)0+# define ASIO_HANDLER_CREATION(args) (void)0+# define ASIO_HANDLER_COMPLETION(args) (void)0+# define ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0+# define ASIO_HANDLER_INVOCATION_END (void)0+# define ASIO_HANDLER_OPERATION(args) (void)0+# define ASIO_HANDLER_REACTOR_REGISTRATION(args) (void)0+# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) (void)0+# define ASIO_HANDLER_REACTOR_READ_EVENT 0+# define ASIO_HANDLER_REACTOR_WRITE_EVENT 0+# define ASIO_HANDLER_REACTOR_ERROR_EVENT 0+# define ASIO_HANDLER_REACTOR_EVENTS(args) (void)0+# define ASIO_HANDLER_REACTOR_OPERATION(args) (void)0++#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/handler_tracking.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_HANDLER_TRACKING_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/handler_type_requirements.hpp view
@@ -0,0 +1,556 @@+//+// detail/handler_type_requirements.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HANDLER_TYPE_REQUIREMENTS_HPP+#define ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++// Older versions of gcc have difficulty compiling the sizeof expressions where+// we test the handler type requirements. We'll disable checking of handler type+// requirements for those compilers, but otherwise enable it by default.+#if !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)+# if !defined(__GNUC__) || (__GNUC__ >= 4)+# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS 1+# endif // !defined(__GNUC__) || (__GNUC__ >= 4)+#endif // !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)++// With C++0x we can use a combination of enhanced SFINAE and static_assert to+// generate better template error messages. As this technique is not yet widely+// portable, we'll only enable it for tested compilers.+#if !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)+# if defined(__GNUC__)+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)+# if defined(__GXX_EXPERIMENTAL_CXX0X__)+# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)+# endif // defined(__GNUC__)+# if defined(ASIO_MSVC)+# if (_MSC_VER >= 1600)+# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1+# endif // (_MSC_VER >= 1600)+# endif // defined(ASIO_MSVC)+# if defined(__clang__)+# if __has_feature(__cxx_static_assert__)+# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1+# endif // __has_feature(cxx_static_assert)+# endif // defined(__clang__)+#endif // !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)++#if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)+# include "asio/async_result.hpp"+#endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)++namespace asio {+namespace detail {++#if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)++# if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)++template <typename Handler>+auto zero_arg_copyable_handler_test(Handler h, void*)+ -> decltype(+ sizeof(Handler(static_cast<const Handler&>(h))),+ ((h)()),+ char(0));++template <typename Handler>+char (&zero_arg_copyable_handler_test(Handler, ...))[2];++template <typename Handler, typename Arg1>+auto one_arg_handler_test(Handler h, Arg1* a1)+ -> decltype(+ sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))),+ ((h)(*a1)),+ char(0));++template <typename Handler>+char (&one_arg_handler_test(Handler h, ...))[2];++template <typename Handler, typename Arg1, typename Arg2>+auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2)+ -> decltype(+ sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))),+ ((h)(*a1, *a2)),+ char(0));++template <typename Handler>+char (&two_arg_handler_test(Handler, ...))[2];++template <typename Handler, typename Arg1, typename Arg2>+auto two_arg_move_handler_test(Handler h, Arg1* a1, Arg2* a2)+ -> decltype(+ sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))),+ ((h)(*a1, ASIO_MOVE_CAST(Arg2)(*a2))),+ char(0));++template <typename Handler>+char (&two_arg_move_handler_test(Handler, ...))[2];++# define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \+ static_assert(expr, msg);++# else // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)++# define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg)++# endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)++template <typename T> T& lvref();+template <typename T> T& lvref(T);+template <typename T> const T& clvref();+template <typename T> const T& clvref(T);+#if defined(ASIO_HAS_MOVE)+template <typename T> T rvref();+template <typename T> T rvref(T);+#else // defined(ASIO_HAS_MOVE)+template <typename T> const T& rvref();+template <typename T> const T& rvref(T);+#endif // defined(ASIO_HAS_MOVE)+template <typename T> char argbyv(T);++template <int>+struct handler_type_requirements+{+};++#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \+ handler_type, handler) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void()) asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::zero_arg_copyable_handler_test( \+ asio::detail::clvref< \+ asio_true_handler_type>(), 0)) == 1, \+ "CompletionHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::clvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()(), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_READ_HANDLER_CHECK( \+ handler_type, handler) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code, std::size_t)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::two_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0), \+ static_cast<const std::size_t*>(0))) == 1, \+ "ReadHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>(), \+ asio::detail::lvref<const std::size_t>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_WRITE_HANDLER_CHECK( \+ handler_type, handler) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code, std::size_t)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::two_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0), \+ static_cast<const std::size_t*>(0))) == 1, \+ "WriteHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>(), \+ asio::detail::lvref<const std::size_t>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_ACCEPT_HANDLER_CHECK( \+ handler_type, handler) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::one_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0))) == 1, \+ "AcceptHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \+ handler_type, handler, socket_type) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code, socket_type)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::two_arg_move_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0), \+ static_cast<socket_type*>(0))) == 1, \+ "MoveAcceptHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>(), \+ asio::detail::rvref<socket_type>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_CONNECT_HANDLER_CHECK( \+ handler_type, handler) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::one_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0))) == 1, \+ "ConnectHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_RANGE_CONNECT_HANDLER_CHECK( \+ handler_type, handler, endpoint_type) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code, endpoint_type)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::two_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0), \+ static_cast<const endpoint_type*>(0))) == 1, \+ "RangeConnectHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>(), \+ asio::detail::lvref<const endpoint_type>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \+ handler_type, handler, iter_type) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code, iter_type)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::two_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0), \+ static_cast<const iter_type*>(0))) == 1, \+ "IteratorConnectHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>(), \+ asio::detail::lvref<const iter_type>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_RESOLVE_HANDLER_CHECK( \+ handler_type, handler, range_type) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code, range_type)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::two_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0), \+ static_cast<const range_type*>(0))) == 1, \+ "ResolveHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>(), \+ asio::detail::lvref<const range_type>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_WAIT_HANDLER_CHECK( \+ handler_type, handler) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::one_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0))) == 1, \+ "WaitHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_SIGNAL_HANDLER_CHECK( \+ handler_type, handler) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code, int)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::two_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0), \+ static_cast<const int*>(0))) == 1, \+ "SignalHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>(), \+ asio::detail::lvref<const int>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_HANDSHAKE_HANDLER_CHECK( \+ handler_type, handler) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::one_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0))) == 1, \+ "HandshakeHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \+ handler_type, handler) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code, std::size_t)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::two_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0), \+ static_cast<const std::size_t*>(0))) == 1, \+ "BufferedHandshakeHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>(), \+ asio::detail::lvref<const std::size_t>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#define ASIO_SHUTDOWN_HANDLER_CHECK( \+ handler_type, handler) \+ \+ typedef ASIO_HANDLER_TYPE(handler_type, \+ void(asio::error_code)) \+ asio_true_handler_type; \+ \+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \+ sizeof(asio::detail::one_arg_handler_test( \+ asio::detail::rvref< \+ asio_true_handler_type>(), \+ static_cast<const asio::error_code*>(0))) == 1, \+ "ShutdownHandler type requirements not met") \+ \+ typedef asio::detail::handler_type_requirements< \+ sizeof( \+ asio::detail::argbyv( \+ asio::detail::rvref< \+ asio_true_handler_type>())) + \+ sizeof( \+ asio::detail::lvref< \+ asio_true_handler_type>()( \+ asio::detail::lvref<const asio::error_code>()), \+ char(0))> ASIO_UNUSED_TYPEDEF++#else // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)++#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \+ handler_type, handler) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_READ_HANDLER_CHECK( \+ handler_type, handler) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_WRITE_HANDLER_CHECK( \+ handler_type, handler) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_ACCEPT_HANDLER_CHECK( \+ handler_type, handler) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \+ handler_type, handler, socket_type) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_CONNECT_HANDLER_CHECK( \+ handler_type, handler) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_RANGE_CONNECT_HANDLER_CHECK( \+ handler_type, handler, iter_type) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \+ handler_type, handler, iter_type) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_RESOLVE_HANDLER_CHECK( \+ handler_type, handler, iter_type) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_WAIT_HANDLER_CHECK( \+ handler_type, handler) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_SIGNAL_HANDLER_CHECK( \+ handler_type, handler) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_HANDSHAKE_HANDLER_CHECK( \+ handler_type, handler) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \+ handler_type, handler) \+ typedef int ASIO_UNUSED_TYPEDEF++#define ASIO_SHUTDOWN_HANDLER_CHECK( \+ handler_type, handler) \+ typedef int ASIO_UNUSED_TYPEDEF++#endif // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/handler_work.hpp view
@@ -0,0 +1,438 @@+//+// detail/handler_work.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HANDLER_WORK_HPP+#define ASIO_DETAIL_HANDLER_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/associated_executor.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution/allocator.hpp"+#include "asio/execution/blocking.hpp"+#include "asio/execution/execute.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution/outstanding_work.hpp"+#include "asio/executor_work_guard.hpp"+#include "asio/prefer.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++class executor;+class io_context;++namespace execution {++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename...> class any_executor;++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename, typename, typename, typename, typename,+ typename, typename, typename, typename> class any_executor;++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++} // namespace execution+namespace detail {++template <typename Executor, typename CandidateExecutor = void,+ typename IoContext = io_context,+ typename PolymorphicExecutor = executor, typename = void>+class handler_work_base+{+public:+ explicit handler_work_base(const Executor& ex) ASIO_NOEXCEPT+ : executor_(asio::prefer(ex, execution::outstanding_work.tracked))+ {+ }++ template <typename OtherExecutor>+ handler_work_base(const Executor& ex,+ const OtherExecutor&) ASIO_NOEXCEPT+ : executor_(asio::prefer(ex, execution::outstanding_work.tracked))+ {+ }++ handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT+ : executor_(other.executor_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT+ : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ bool owns_work() const ASIO_NOEXCEPT+ {+ return true;+ }++ template <typename Function, typename Handler>+ void dispatch(Function& function, Handler& handler)+ {+ execution::execute(+ asio::prefer(executor_,+ execution::blocking.possibly,+ execution::allocator((get_associated_allocator)(handler))),+ ASIO_MOVE_CAST(Function)(function));+ }++private:+ typedef typename decay<+ typename prefer_result<Executor,+ execution::outstanding_work_t::tracked_t+ >::type+ >::type executor_type;++ executor_type executor_;+};++template <typename Executor, typename CandidateExecutor,+ typename IoContext, typename PolymorphicExecutor>+class handler_work_base<Executor, CandidateExecutor,+ IoContext, PolymorphicExecutor,+ typename enable_if<+ !execution::is_executor<Executor>::value+ && (!is_same<Executor, PolymorphicExecutor>::value+ || !is_same<CandidateExecutor, void>::value)+ >::type>+{+public:+ explicit handler_work_base(const Executor& ex) ASIO_NOEXCEPT+ : executor_(ex),+ owns_work_(true)+ {+ executor_.on_work_started();+ }++ handler_work_base(const Executor& ex,+ const Executor& candidate) ASIO_NOEXCEPT+ : executor_(ex),+ owns_work_(ex != candidate)+ {+ if (owns_work_)+ executor_.on_work_started();+ }++ template <typename OtherExecutor>+ handler_work_base(const Executor& ex,+ const OtherExecutor&) ASIO_NOEXCEPT+ : executor_(ex),+ owns_work_(true)+ {+ executor_.on_work_started();+ }++ handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT+ : executor_(other.executor_),+ owns_work_(other.owns_work_)+ {+ if (owns_work_)+ executor_.on_work_started();+ }++#if defined(ASIO_HAS_MOVE)+ handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT+ : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)),+ owns_work_(other.owns_work_)+ {+ other.owns_work_ = false;+ }+#endif // defined(ASIO_HAS_MOVE)++ ~handler_work_base()+ {+ if (owns_work_)+ executor_.on_work_finished();+ }++ bool owns_work() const ASIO_NOEXCEPT+ {+ return owns_work_;+ }++ template <typename Function, typename Handler>+ void dispatch(Function& function, Handler& handler)+ {+ executor_.dispatch(ASIO_MOVE_CAST(Function)(function),+ asio::get_associated_allocator(handler));+ }++private:+ Executor executor_;+ bool owns_work_;+};++template <typename Executor, typename IoContext, typename PolymorphicExecutor>+class handler_work_base<Executor, void, IoContext, PolymorphicExecutor,+ typename enable_if<+ is_same<+ Executor,+ typename IoContext::executor_type+ >::value+ >::type>+{+public:+ explicit handler_work_base(const Executor&)+ {+ }++ bool owns_work() const ASIO_NOEXCEPT+ {+ return false;+ }++ template <typename Function, typename Handler>+ void dispatch(Function& function, Handler& handler)+ {+ // When using a native implementation, I/O completion handlers are+ // already dispatched according to the execution context's executor's+ // rules. We can call the function directly.+ asio_handler_invoke_helpers::invoke(function, handler);+ }+};++template <typename Executor, typename IoContext>+class handler_work_base<Executor, void, IoContext, Executor>+{+public:+ explicit handler_work_base(const Executor& ex) ASIO_NOEXCEPT+#if !defined(ASIO_NO_TYPEID)+ : executor_(+ ex.target_type() == typeid(typename IoContext::executor_type)+ ? Executor() : ex)+#else // !defined(ASIO_NO_TYPEID)+ : executor_(ex)+#endif // !defined(ASIO_NO_TYPEID)+ {+ if (executor_)+ executor_.on_work_started();+ }++ handler_work_base(const Executor& ex,+ const Executor& candidate) ASIO_NOEXCEPT+ : executor_(ex != candidate ? ex : Executor())+ {+ if (executor_)+ executor_.on_work_started();+ }++ template <typename OtherExecutor>+ handler_work_base(const Executor& ex,+ const OtherExecutor&) ASIO_NOEXCEPT+ : executor_(ex)+ {+ executor_.on_work_started();+ }++ handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT+ : executor_(other.executor_)+ {+ if (executor_)+ executor_.on_work_started();+ }++#if defined(ASIO_HAS_MOVE)+ handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT+ : executor_(ASIO_MOVE_CAST(Executor)(other.executor_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ ~handler_work_base()+ {+ if (executor_)+ executor_.on_work_finished();+ }++ bool owns_work() const ASIO_NOEXCEPT+ {+ return !!executor_;+ }++ template <typename Function, typename Handler>+ void dispatch(Function& function, Handler& handler)+ {+ executor_.dispatch(ASIO_MOVE_CAST(Function)(function),+ asio::get_associated_allocator(handler));+ }++private:+ Executor executor_;+};++template <+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)+ typename... SupportableProperties,+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ typename T1, typename T2, typename T3, typename T4, typename T5,+ typename T6, typename T7, typename T8, typename T9,+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ typename IoContext, typename PolymorphicExecutor>+class handler_work_base<+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)+ execution::any_executor<SupportableProperties...>,+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>,+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ void, IoContext, PolymorphicExecutor>+{+public:+ typedef+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)+ execution::any_executor<SupportableProperties...>+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ executor_type;++ explicit handler_work_base(const executor_type& ex) ASIO_NOEXCEPT+#if !defined(ASIO_NO_TYPEID)+ : executor_(+ ex.target_type() == typeid(typename IoContext::executor_type)+ ? executor_type()+ : asio::prefer(ex, execution::outstanding_work.tracked))+#else // !defined(ASIO_NO_TYPEID)+ : executor_(asio::prefer(ex, execution::outstanding_work.tracked))+#endif // !defined(ASIO_NO_TYPEID)+ {+ }++ handler_work_base(const executor_type& ex,+ const executor_type& candidate) ASIO_NOEXCEPT+ : executor_(ex != candidate ? ex : executor_type())+ {+ }++ template <typename OtherExecutor>+ handler_work_base(const executor_type& ex,+ const OtherExecutor&) ASIO_NOEXCEPT+ : executor_(asio::prefer(ex, execution::outstanding_work.tracked))+ {+ }++ handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT+ : executor_(other.executor_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT+ : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ bool owns_work() const ASIO_NOEXCEPT+ {+ return !!executor_;+ }++ template <typename Function, typename Handler>+ void dispatch(Function& function, Handler& handler)+ {+ execution::execute(+ asio::prefer(executor_,+ execution::blocking.possibly,+ execution::allocator((get_associated_allocator)(handler))),+ ASIO_MOVE_CAST(Function)(function));+ }++private:+ executor_type executor_;+};++template <typename Handler, typename IoExecutor, typename = void>+class handler_work :+ handler_work_base<IoExecutor>,+ handler_work_base<typename associated_executor<+ Handler, IoExecutor>::type, IoExecutor>+{+public:+ typedef handler_work_base<IoExecutor> base1_type;+ typedef handler_work_base<typename associated_executor<+ Handler, IoExecutor>::type, IoExecutor> base2_type;++ handler_work(Handler& handler, const IoExecutor& io_ex) ASIO_NOEXCEPT+ : base1_type(io_ex),+ base2_type(asio::get_associated_executor(handler, io_ex), io_ex)+ {+ }++ template <typename Function>+ void complete(Function& function, Handler& handler)+ {+ if (!base1_type::owns_work() && !base2_type::owns_work())+ {+ // When using a native implementation, I/O completion handlers are+ // already dispatched according to the execution context's executor's+ // rules. We can call the function directly.+ asio_handler_invoke_helpers::invoke(function, handler);+ }+ else+ {+ base2_type::dispatch(function, handler);+ }+ }+};++template <typename Handler, typename IoExecutor>+class handler_work<+ Handler, IoExecutor,+ typename enable_if<+ is_same<+ typename associated_executor<Handler,+ IoExecutor>::asio_associated_executor_is_unspecialised,+ void+ >::value+ >::type> : handler_work_base<IoExecutor>+{+public:+ typedef handler_work_base<IoExecutor> base1_type;++ handler_work(Handler&, const IoExecutor& io_ex) ASIO_NOEXCEPT+ : base1_type(io_ex)+ {+ }++ template <typename Function>+ void complete(Function& function, Handler& handler)+ {+ if (!base1_type::owns_work())+ {+ // When using a native implementation, I/O completion handlers are+ // already dispatched according to the execution context's executor's+ // rules. We can call the function directly.+ asio_handler_invoke_helpers::invoke(function, handler);+ }+ else+ {+ base1_type::dispatch(function, handler);+ }+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_HANDLER_WORK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/hash_map.hpp view
@@ -0,0 +1,331 @@+//+// detail/hash_map.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HASH_MAP_HPP+#define ASIO_DETAIL_HASH_MAP_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <list>+#include <utility>+#include "asio/detail/assert.hpp"+#include "asio/detail/noncopyable.hpp"++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# include "asio/detail/socket_types.hpp"+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++inline std::size_t calculate_hash_value(int i)+{+ return static_cast<std::size_t>(i);+}++inline std::size_t calculate_hash_value(void* p)+{+ return reinterpret_cast<std::size_t>(p)+ + (reinterpret_cast<std::size_t>(p) >> 3);+}++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+inline std::size_t calculate_hash_value(SOCKET s)+{+ return static_cast<std::size_t>(s);+}+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++// Note: assumes K and V are POD types.+template <typename K, typename V>+class hash_map+ : private noncopyable+{+public:+ // The type of a value in the map.+ typedef std::pair<K, V> value_type;++ // The type of a non-const iterator over the hash map.+ typedef typename std::list<value_type>::iterator iterator;++ // The type of a const iterator over the hash map.+ typedef typename std::list<value_type>::const_iterator const_iterator;++ // Constructor.+ hash_map()+ : size_(0),+ buckets_(0),+ num_buckets_(0)+ {+ }++ // Destructor.+ ~hash_map()+ {+ delete[] buckets_;+ }++ // Get an iterator for the beginning of the map.+ iterator begin()+ {+ return values_.begin();+ }++ // Get an iterator for the beginning of the map.+ const_iterator begin() const+ {+ return values_.begin();+ }++ // Get an iterator for the end of the map.+ iterator end()+ {+ return values_.end();+ }++ // Get an iterator for the end of the map.+ const_iterator end() const+ {+ return values_.end();+ }++ // Check whether the map is empty.+ bool empty() const+ {+ return values_.empty();+ }++ // Find an entry in the map.+ iterator find(const K& k)+ {+ if (num_buckets_)+ {+ size_t bucket = calculate_hash_value(k) % num_buckets_;+ iterator it = buckets_[bucket].first;+ if (it == values_.end())+ return values_.end();+ iterator end_it = buckets_[bucket].last;+ ++end_it;+ while (it != end_it)+ {+ if (it->first == k)+ return it;+ ++it;+ }+ }+ return values_.end();+ }++ // Find an entry in the map.+ const_iterator find(const K& k) const+ {+ if (num_buckets_)+ {+ size_t bucket = calculate_hash_value(k) % num_buckets_;+ const_iterator it = buckets_[bucket].first;+ if (it == values_.end())+ return it;+ const_iterator end_it = buckets_[bucket].last;+ ++end_it;+ while (it != end_it)+ {+ if (it->first == k)+ return it;+ ++it;+ }+ }+ return values_.end();+ }++ // Insert a new entry into the map.+ std::pair<iterator, bool> insert(const value_type& v)+ {+ if (size_ + 1 >= num_buckets_)+ rehash(hash_size(size_ + 1));+ size_t bucket = calculate_hash_value(v.first) % num_buckets_;+ iterator it = buckets_[bucket].first;+ if (it == values_.end())+ {+ buckets_[bucket].first = buckets_[bucket].last =+ values_insert(values_.end(), v);+ ++size_;+ return std::pair<iterator, bool>(buckets_[bucket].last, true);+ }+ iterator end_it = buckets_[bucket].last;+ ++end_it;+ while (it != end_it)+ {+ if (it->first == v.first)+ return std::pair<iterator, bool>(it, false);+ ++it;+ }+ buckets_[bucket].last = values_insert(end_it, v);+ ++size_;+ return std::pair<iterator, bool>(buckets_[bucket].last, true);+ }++ // Erase an entry from the map.+ void erase(iterator it)+ {+ ASIO_ASSERT(it != values_.end());+ ASIO_ASSERT(num_buckets_ != 0);++ size_t bucket = calculate_hash_value(it->first) % num_buckets_;+ bool is_first = (it == buckets_[bucket].first);+ bool is_last = (it == buckets_[bucket].last);+ if (is_first && is_last)+ buckets_[bucket].first = buckets_[bucket].last = values_.end();+ else if (is_first)+ ++buckets_[bucket].first;+ else if (is_last)+ --buckets_[bucket].last;++ values_erase(it);+ --size_;+ }++ // Erase a key from the map.+ void erase(const K& k)+ {+ iterator it = find(k);+ if (it != values_.end())+ erase(it);+ }++ // Remove all entries from the map.+ void clear()+ {+ // Clear the values.+ values_.clear();+ size_ = 0;++ // Initialise all buckets to empty.+ iterator end_it = values_.end();+ for (size_t i = 0; i < num_buckets_; ++i)+ buckets_[i].first = buckets_[i].last = end_it;+ }++private:+ // Calculate the hash size for the specified number of elements.+ static std::size_t hash_size(std::size_t num_elems)+ {+ static std::size_t sizes[] =+ {+#if defined(ASIO_HASH_MAP_BUCKETS)+ ASIO_HASH_MAP_BUCKETS+#else // ASIO_HASH_MAP_BUCKETS+ 3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,+ 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,+ 12582917, 25165843+#endif // ASIO_HASH_MAP_BUCKETS+ };+ const std::size_t nth_size = sizeof(sizes) / sizeof(std::size_t) - 1;+ for (std::size_t i = 0; i < nth_size; ++i)+ if (num_elems < sizes[i])+ return sizes[i];+ return sizes[nth_size];+ }++ // Re-initialise the hash from the values already contained in the list.+ void rehash(std::size_t num_buckets)+ {+ if (num_buckets == num_buckets_)+ return;+ ASIO_ASSERT(num_buckets != 0);++ iterator end_iter = values_.end();++ // Update number of buckets and initialise all buckets to empty.+ bucket_type* tmp = new bucket_type[num_buckets];+ delete[] buckets_;+ buckets_ = tmp;+ num_buckets_ = num_buckets;+ for (std::size_t i = 0; i < num_buckets_; ++i)+ buckets_[i].first = buckets_[i].last = end_iter;++ // Put all values back into the hash.+ iterator iter = values_.begin();+ while (iter != end_iter)+ {+ std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_;+ if (buckets_[bucket].last == end_iter)+ {+ buckets_[bucket].first = buckets_[bucket].last = iter++;+ }+ else if (++buckets_[bucket].last == iter)+ {+ ++iter;+ }+ else+ {+ values_.splice(buckets_[bucket].last, values_, iter++);+ --buckets_[bucket].last;+ }+ }+ }++ // Insert an element into the values list by splicing from the spares list,+ // if a spare is available, and otherwise by inserting a new element.+ iterator values_insert(iterator it, const value_type& v)+ {+ if (spares_.empty())+ {+ return values_.insert(it, v);+ }+ else+ {+ spares_.front() = v;+ values_.splice(it, spares_, spares_.begin());+ return --it;+ }+ }++ // Erase an element from the values list by splicing it to the spares list.+ void values_erase(iterator it)+ {+ *it = value_type();+ spares_.splice(spares_.begin(), values_, it);+ }++ // The number of elements in the hash.+ std::size_t size_;++ // The list of all values in the hash map.+ std::list<value_type> values_;++ // The list of spare nodes waiting to be recycled. Assumes that POD types only+ // are stored in the hash map.+ std::list<value_type> spares_;++ // The type for a bucket in the hash table.+ struct bucket_type+ {+ iterator first;+ iterator last;+ };++ // The buckets in the hash.+ bucket_type* buckets_;++ // The number of buckets in the hash.+ std::size_t num_buckets_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_HASH_MAP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/buffer_sequence_adapter.ipp view
@@ -0,0 +1,118 @@+//+// detail/impl/buffer_sequence_adapter.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP+#define ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(ASIO_WINDOWS_RUNTIME)++#include <robuffer.h>+#include <windows.storage.streams.h>+#include <wrl/implements.h>+#include "asio/detail/buffer_sequence_adapter.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class winrt_buffer_impl :+ public Microsoft::WRL::RuntimeClass<+ Microsoft::WRL::RuntimeClassFlags<+ Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>,+ ABI::Windows::Storage::Streams::IBuffer,+ Windows::Storage::Streams::IBufferByteAccess>+{+public:+ explicit winrt_buffer_impl(const asio::const_buffer& b)+ {+ bytes_ = const_cast<byte*>(static_cast<const byte*>(b.data()));+ length_ = b.size();+ capacity_ = b.size();+ }++ explicit winrt_buffer_impl(const asio::mutable_buffer& b)+ {+ bytes_ = static_cast<byte*>(b.data());+ length_ = 0;+ capacity_ = b.size();+ }++ ~winrt_buffer_impl()+ {+ }++ STDMETHODIMP Buffer(byte** value)+ {+ *value = bytes_;+ return S_OK;+ }++ STDMETHODIMP get_Capacity(UINT32* value)+ {+ *value = capacity_;+ return S_OK;+ }++ STDMETHODIMP get_Length(UINT32 *value)+ {+ *value = length_;+ return S_OK;+ }++ STDMETHODIMP put_Length(UINT32 value)+ {+ if (value > capacity_)+ return E_INVALIDARG;+ length_ = value;+ return S_OK;+ }++private:+ byte* bytes_;+ UINT32 length_;+ UINT32 capacity_;+};++void buffer_sequence_adapter_base::init_native_buffer(+ buffer_sequence_adapter_base::native_buffer_type& buf,+ const asio::mutable_buffer& buffer)+{+ std::memset(&buf, 0, sizeof(native_buffer_type));+ Microsoft::WRL::ComPtr<IInspectable> insp+ = Microsoft::WRL::Make<winrt_buffer_impl>(buffer);+ buf = reinterpret_cast<Windows::Storage::Streams::IBuffer^>(insp.Get());+}++void buffer_sequence_adapter_base::init_native_buffer(+ buffer_sequence_adapter_base::native_buffer_type& buf,+ const asio::const_buffer& buffer)+{+ std::memset(&buf, 0, sizeof(native_buffer_type));+ Microsoft::WRL::ComPtr<IInspectable> insp+ = Microsoft::WRL::Make<winrt_buffer_impl>(buffer);+ Platform::Object^ buf_obj = reinterpret_cast<Platform::Object^>(insp.Get());+ buf = reinterpret_cast<Windows::Storage::Streams::IBuffer^>(insp.Get());+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/descriptor_ops.ipp view
@@ -0,0 +1,608 @@+//+// detail/impl/descriptor_ops.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_DESCRIPTOR_OPS_IPP+#define ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cerrno>+#include "asio/detail/descriptor_ops.hpp"+#include "asio/error.hpp"++#if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {+namespace descriptor_ops {++int open(const char* path, int flags, asio::error_code& ec)+{+ int result = ::open(path, flags);+ get_last_error(ec, result < 0);+ return result;+}++int close(int d, state_type& state, asio::error_code& ec)+{+ int result = 0;+ if (d != -1)+ {+ result = ::close(d);+ get_last_error(ec, result < 0);++ if (result != 0+ && (ec == asio::error::would_block+ || ec == asio::error::try_again))+ {+ // According to UNIX Network Programming Vol. 1, it is possible for+ // close() to fail with EWOULDBLOCK under certain circumstances. What+ // isn't clear is the state of the descriptor after this error. The one+ // current OS where this behaviour is seen, Windows, says that the socket+ // remains open. Therefore we'll put the descriptor back into blocking+ // mode and have another attempt at closing it.+#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+ int flags = ::fcntl(d, F_GETFL, 0);+ if (flags >= 0)+ ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK);+#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+ ioctl_arg_type arg = 0;+ ::ioctl(d, FIONBIO, &arg);+#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+ state &= ~non_blocking;++ result = ::close(d);+ get_last_error(ec, result < 0);+ }+ }++ return result;+}++bool set_user_non_blocking(int d, state_type& state,+ bool value, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return false;+ }++#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+ int result = ::fcntl(d, F_GETFL, 0);+ get_last_error(ec, result < 0);+ if (result >= 0)+ {+ int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));+ result = ::fcntl(d, F_SETFL, flag);+ get_last_error(ec, result < 0);+ }+#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+ ioctl_arg_type arg = (value ? 1 : 0);+ int result = ::ioctl(d, FIONBIO, &arg);+ get_last_error(ec, result < 0);+#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)++ if (result >= 0)+ {+ if (value)+ state |= user_set_non_blocking;+ else+ {+ // Clearing the user-set non-blocking mode always overrides any+ // internally-set non-blocking flag. Any subsequent asynchronous+ // operations will need to re-enable non-blocking I/O.+ state &= ~(user_set_non_blocking | internal_non_blocking);+ }+ return true;+ }++ return false;+}++bool set_internal_non_blocking(int d, state_type& state,+ bool value, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return false;+ }++ if (!value && (state & user_set_non_blocking))+ {+ // It does not make sense to clear the internal non-blocking flag if the+ // user still wants non-blocking behaviour. Return an error and let the+ // caller figure out whether to update the user-set non-blocking flag.+ ec = asio::error::invalid_argument;+ return false;+ }++#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+ int result = ::fcntl(d, F_GETFL, 0);+ get_last_error(ec, result < 0);+ if (result >= 0)+ {+ int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));+ result = ::fcntl(d, F_SETFL, flag);+ get_last_error(ec, result < 0);+ }+#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+ ioctl_arg_type arg = (value ? 1 : 0);+ int result = ::ioctl(d, FIONBIO, &arg);+ get_last_error(ec, result < 0);+#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)++ if (result >= 0)+ {+ if (value)+ state |= internal_non_blocking;+ else+ state &= ~internal_non_blocking;+ return true;+ }++ return false;+}++std::size_t sync_read(int d, state_type state, buf* bufs,+ std::size_t count, bool all_empty, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // A request to read 0 bytes on a stream is a no-op.+ if (all_empty)+ {+ ec.assign(0, ec.category());+ return 0;+ }++ // Read some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count));+ get_last_error(ec, bytes < 0);++ // Check if operation succeeded.+ if (bytes > 0)+ return bytes;++ // Check for EOF.+ if (bytes == 0)+ {+ ec = asio::error::eof;+ return 0;+ }++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for descriptor to become ready.+ if (descriptor_ops::poll_read(d, 0, ec) < 0)+ return 0;+ }+}++std::size_t sync_read1(int d, state_type state, void* data,+ std::size_t size, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // A request to read 0 bytes on a stream is a no-op.+ if (size == 0)+ {+ ec.assign(0, ec.category());+ return 0;+ }++ // Read some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = ::read(d, data, size);+ get_last_error(ec, bytes < 0);++ // Check if operation succeeded.+ if (bytes > 0)+ return bytes;++ // Check for EOF.+ if (bytes == 0)+ {+ ec = asio::error::eof;+ return 0;+ }++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for descriptor to become ready.+ if (descriptor_ops::poll_read(d, 0, ec) < 0)+ return 0;+ }+}++bool non_blocking_read(int d, buf* bufs, std::size_t count,+ asio::error_code& ec, std::size_t& bytes_transferred)+{+ for (;;)+ {+ // Read some data.+ signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count));+ get_last_error(ec, bytes < 0);++ // Check for end of stream.+ if (bytes == 0)+ {+ ec = asio::error::eof;+ return true;+ }++ // Check if operation succeeded.+ if (bytes > 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++bool non_blocking_read1(int d, void* data, std::size_t size,+ asio::error_code& ec, std::size_t& bytes_transferred)+{+ for (;;)+ {+ // Read some data.+ signed_size_type bytes = ::read(d, data, size);+ get_last_error(ec, bytes < 0);++ // Check for end of stream.+ if (bytes == 0)+ {+ ec = asio::error::eof;+ return true;+ }++ // Check if operation succeeded.+ if (bytes > 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++std::size_t sync_write(int d, state_type state, const buf* bufs,+ std::size_t count, bool all_empty, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // A request to write 0 bytes on a stream is a no-op.+ if (all_empty)+ {+ ec.assign(0, ec.category());+ return 0;+ }++ // Write some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count));+ get_last_error(ec, bytes < 0);++ // Check if operation succeeded.+ if (bytes > 0)+ return bytes;++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for descriptor to become ready.+ if (descriptor_ops::poll_write(d, 0, ec) < 0)+ return 0;+ }+}++std::size_t sync_write1(int d, state_type state, const void* data,+ std::size_t size, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // A request to write 0 bytes on a stream is a no-op.+ if (size == 0)+ {+ ec.assign(0, ec.category());+ return 0;+ }++ // Write some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = ::write(d, data, size);+ get_last_error(ec, bytes < 0);++ // Check if operation succeeded.+ if (bytes > 0)+ return bytes;++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for descriptor to become ready.+ if (descriptor_ops::poll_write(d, 0, ec) < 0)+ return 0;+ }+}++bool non_blocking_write(int d, const buf* bufs, std::size_t count,+ asio::error_code& ec, std::size_t& bytes_transferred)+{+ for (;;)+ {+ // Write some data.+ signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count));+ get_last_error(ec, bytes < 0);++ // Check if operation succeeded.+ if (bytes >= 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++bool non_blocking_write1(int d, const void* data, std::size_t size,+ asio::error_code& ec, std::size_t& bytes_transferred)+{+ for (;;)+ {+ // Write some data.+ signed_size_type bytes = ::write(d, data, size);+ get_last_error(ec, bytes < 0);++ // Check if operation succeeded.+ if (bytes >= 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++int ioctl(int d, state_type& state, long cmd,+ ioctl_arg_type* arg, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return -1;+ }++ int result = ::ioctl(d, cmd, arg);+ get_last_error(ec, result < 0);++ if (result >= 0)+ {+ // When updating the non-blocking mode we always perform the ioctl syscall,+ // even if the flags would otherwise indicate that the descriptor is+ // already in the correct state. This ensures that the underlying+ // descriptor is put into the state that has been requested by the user. If+ // the ioctl syscall was successful then we need to update the flags to+ // match.+ if (cmd == static_cast<long>(FIONBIO))+ {+ if (*arg)+ {+ state |= user_set_non_blocking;+ }+ else+ {+ // Clearing the non-blocking mode always overrides any internally-set+ // non-blocking flag. Any subsequent asynchronous operations will need+ // to re-enable non-blocking I/O.+ state &= ~(user_set_non_blocking | internal_non_blocking);+ }+ }+ }++ return result;+}++int fcntl(int d, int cmd, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return -1;+ }++ int result = ::fcntl(d, cmd);+ get_last_error(ec, result < 0);+ return result;+}++int fcntl(int d, int cmd, long arg, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return -1;+ }++ int result = ::fcntl(d, cmd, arg);+ get_last_error(ec, result < 0);+ return result;+}++int poll_read(int d, state_type state, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return -1;+ }++ pollfd fds;+ fds.fd = d;+ fds.events = POLLIN;+ fds.revents = 0;+ int timeout = (state & user_set_non_blocking) ? 0 : -1;+ int result = ::poll(&fds, 1, timeout);+ get_last_error(ec, result < 0);+ if (result == 0)+ if (state & user_set_non_blocking)+ ec = asio::error::would_block;+ return result;+}++int poll_write(int d, state_type state, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return -1;+ }++ pollfd fds;+ fds.fd = d;+ fds.events = POLLOUT;+ fds.revents = 0;+ int timeout = (state & user_set_non_blocking) ? 0 : -1;+ int result = ::poll(&fds, 1, timeout);+ get_last_error(ec, result < 0);+ if (result == 0)+ if (state & user_set_non_blocking)+ ec = asio::error::would_block;+ return result;+}++int poll_error(int d, state_type state, asio::error_code& ec)+{+ if (d == -1)+ {+ ec = asio::error::bad_descriptor;+ return -1;+ }++ pollfd fds;+ fds.fd = d;+ fds.events = POLLPRI | POLLERR | POLLHUP;+ fds.revents = 0;+ int timeout = (state & user_set_non_blocking) ? 0 : -1;+ int result = ::poll(&fds, 1, timeout);+ get_last_error(ec, result < 0);+ if (result == 0)+ if (state & user_set_non_blocking)+ ec = asio::error::would_block;+ return result;+}++} // namespace descriptor_ops+} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)++#endif // ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/dev_poll_reactor.hpp view
@@ -0,0 +1,91 @@+//+// detail/impl/dev_poll_reactor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_DEV_POLL_REACTOR_HPP+#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_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_DEV_POLL)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Time_Traits>+void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)+{+ do_add_timer_queue(queue);+}++template <typename Time_Traits>+void dev_poll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)+{+ do_remove_timer_queue(queue);+}++template <typename Time_Traits>+void dev_poll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ if (shutdown_)+ {+ scheduler_.post_immediate_completion(op, false);+ return;+ }++ bool earliest = queue.enqueue_timer(time, timer, op);+ scheduler_.work_started();+ if (earliest)+ interrupter_.interrupt();+}++template <typename Time_Traits>+std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled)+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ op_queue<operation> ops;+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);+ lock.unlock();+ scheduler_.post_deferred_completions(ops);+ return n;+}++template <typename Time_Traits>+void dev_poll_reactor::move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& target,+ typename timer_queue<Time_Traits>::per_timer_data& source)+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ op_queue<operation> ops;+ queue.cancel_timer(target, ops);+ queue.move_timer(target, source);+ lock.unlock();+ scheduler_.post_deferred_completions(ops);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_DEV_POLL)++#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/dev_poll_reactor.ipp view
@@ -0,0 +1,446 @@+//+// detail/impl/dev_poll_reactor.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_DEV_POLL_REACTOR_IPP+#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP++#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_DEV_POLL)++#include "asio/detail/dev_poll_reactor.hpp"+#include "asio/detail/assert.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++dev_poll_reactor::dev_poll_reactor(asio::execution_context& ctx)+ : asio::detail::execution_context_service_base<dev_poll_reactor>(ctx),+ scheduler_(use_service<scheduler>(ctx)),+ mutex_(),+ dev_poll_fd_(do_dev_poll_create()),+ interrupter_(),+ shutdown_(false)+{+ // Add the interrupter's descriptor to /dev/poll.+ ::pollfd ev = { 0, 0, 0 };+ ev.fd = interrupter_.read_descriptor();+ ev.events = POLLIN | POLLERR;+ ev.revents = 0;+ ::write(dev_poll_fd_, &ev, sizeof(ev));+}++dev_poll_reactor::~dev_poll_reactor()+{+ shutdown();+ ::close(dev_poll_fd_);+}++void dev_poll_reactor::shutdown()+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ shutdown_ = true;+ lock.unlock();++ op_queue<operation> ops;++ for (int i = 0; i < max_ops; ++i)+ op_queue_[i].get_all_operations(ops);++ timer_queues_.get_all_timers(ops);++ scheduler_.abandon_operations(ops);+} ++void dev_poll_reactor::notify_fork(+ asio::execution_context::fork_event fork_ev)+{+ if (fork_ev == asio::execution_context::fork_child)+ {+ detail::mutex::scoped_lock lock(mutex_);++ if (dev_poll_fd_ != -1)+ ::close(dev_poll_fd_);+ dev_poll_fd_ = -1;+ dev_poll_fd_ = do_dev_poll_create();++ interrupter_.recreate();++ // Add the interrupter's descriptor to /dev/poll.+ ::pollfd ev = { 0, 0, 0 };+ ev.fd = interrupter_.read_descriptor();+ ev.events = POLLIN | POLLERR;+ ev.revents = 0;+ ::write(dev_poll_fd_, &ev, sizeof(ev));++ // Re-register all descriptors with /dev/poll. The changes will be written+ // to the /dev/poll descriptor the next time the reactor is run.+ for (int i = 0; i < max_ops; ++i)+ {+ reactor_op_queue<socket_type>::iterator iter = op_queue_[i].begin();+ reactor_op_queue<socket_type>::iterator end = op_queue_[i].end();+ for (; iter != end; ++iter)+ {+ ::pollfd& pending_ev = add_pending_event_change(iter->first);+ pending_ev.events |= POLLERR | POLLHUP;+ switch (i)+ {+ case read_op: pending_ev.events |= POLLIN; break;+ case write_op: pending_ev.events |= POLLOUT; break;+ case except_op: pending_ev.events |= POLLPRI; break;+ default: break;+ }+ }+ }+ interrupter_.interrupt();+ }+}++void dev_poll_reactor::init_task()+{+ scheduler_.init_task();+}++int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&)+{+ return 0;+}++int dev_poll_reactor::register_internal_descriptor(int op_type,+ socket_type descriptor, per_descriptor_data&, reactor_op* op)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ op_queue_[op_type].enqueue_operation(descriptor, op);+ ::pollfd& ev = add_pending_event_change(descriptor);+ ev.events = POLLERR | POLLHUP;+ switch (op_type)+ {+ case read_op: ev.events |= POLLIN; break;+ case write_op: ev.events |= POLLOUT; break;+ case except_op: ev.events |= POLLPRI; break;+ default: break;+ }+ interrupter_.interrupt();++ return 0;+}++void dev_poll_reactor::move_descriptor(socket_type,+ dev_poll_reactor::per_descriptor_data&,+ dev_poll_reactor::per_descriptor_data&)+{+}++void dev_poll_reactor::start_op(int op_type, socket_type descriptor,+ dev_poll_reactor::per_descriptor_data&, reactor_op* op,+ bool is_continuation, bool allow_speculative)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ if (shutdown_)+ {+ post_immediate_completion(op, is_continuation);+ return;+ }++ if (allow_speculative)+ {+ if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor))+ {+ if (!op_queue_[op_type].has_operation(descriptor))+ {+ if (op->perform())+ {+ lock.unlock();+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }+ }+ }+ }++ bool first = op_queue_[op_type].enqueue_operation(descriptor, op);+ scheduler_.work_started();+ if (first)+ {+ ::pollfd& ev = add_pending_event_change(descriptor);+ ev.events = POLLERR | POLLHUP;+ if (op_type == read_op+ || op_queue_[read_op].has_operation(descriptor))+ ev.events |= POLLIN;+ if (op_type == write_op+ || op_queue_[write_op].has_operation(descriptor))+ ev.events |= POLLOUT;+ if (op_type == except_op+ || op_queue_[except_op].has_operation(descriptor))+ ev.events |= POLLPRI;+ interrupter_.interrupt();+ }+}++void dev_poll_reactor::cancel_ops(socket_type descriptor,+ dev_poll_reactor::per_descriptor_data&)+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);+}++void dev_poll_reactor::deregister_descriptor(socket_type descriptor,+ dev_poll_reactor::per_descriptor_data&, bool)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ // Remove the descriptor from /dev/poll.+ ::pollfd& ev = add_pending_event_change(descriptor);+ ev.events = POLLREMOVE;+ interrupter_.interrupt();++ // Cancel any outstanding operations associated with the descriptor.+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);+}++void dev_poll_reactor::deregister_internal_descriptor(+ socket_type descriptor, dev_poll_reactor::per_descriptor_data&)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ // Remove the descriptor from /dev/poll. Since this function is only called+ // during a fork, we can apply the change immediately.+ ::pollfd ev = { 0, 0, 0 };+ ev.fd = descriptor;+ ev.events = POLLREMOVE;+ ev.revents = 0;+ ::write(dev_poll_fd_, &ev, sizeof(ev));++ // Destroy all operations associated with the descriptor.+ op_queue<operation> ops;+ asio::error_code ec;+ for (int i = 0; i < max_ops; ++i)+ op_queue_[i].cancel_operations(descriptor, ops, ec);+}++void dev_poll_reactor::cleanup_descriptor_data(+ dev_poll_reactor::per_descriptor_data&)+{+}++void dev_poll_reactor::run(long usec, op_queue<operation>& ops)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ // We can return immediately if there's no work to do and the reactor is+ // not supposed to block.+ if (usec == 0 && op_queue_[read_op].empty() && op_queue_[write_op].empty()+ && op_queue_[except_op].empty() && timer_queues_.all_empty())+ return;++ // Write the pending event registration changes to the /dev/poll descriptor.+ std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();+ if (events_size > 0)+ {+ errno = 0;+ int result = ::write(dev_poll_fd_,+ &pending_event_changes_[0], events_size);+ if (result != static_cast<int>(events_size))+ {+ asio::error_code ec = asio::error_code(+ errno, asio::error::get_system_category());+ for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)+ {+ int descriptor = pending_event_changes_[i].fd;+ for (int j = 0; j < max_ops; ++j)+ op_queue_[j].cancel_operations(descriptor, ops, ec);+ }+ }+ pending_event_changes_.clear();+ pending_event_change_index_.clear();+ }++ // Calculate timeout.+ int timeout;+ if (usec == 0)+ timeout = 0;+ else+ {+ timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1);+ timeout = get_timeout(timeout);+ }+ lock.unlock();++ // Block on the /dev/poll descriptor.+ ::pollfd events[128] = { { 0, 0, 0 } };+ ::dvpoll dp = { 0, 0, 0 };+ dp.dp_fds = events;+ dp.dp_nfds = 128;+ dp.dp_timeout = timeout;+ int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);++ lock.lock();++ // Dispatch the waiting events.+ for (int i = 0; i < num_events; ++i)+ {+ int descriptor = events[i].fd;+ if (descriptor == interrupter_.read_descriptor())+ {+ interrupter_.reset();+ }+ else+ {+ bool more_reads = false;+ bool more_writes = false;+ bool more_except = false;++ // Exception operations must be processed first to ensure that any+ // out-of-band data is read before normal data.+ if (events[i].events & (POLLPRI | POLLERR | POLLHUP))+ more_except =+ op_queue_[except_op].perform_operations(descriptor, ops);+ else+ more_except = op_queue_[except_op].has_operation(descriptor);++ if (events[i].events & (POLLIN | POLLERR | POLLHUP))+ more_reads = op_queue_[read_op].perform_operations(descriptor, ops);+ else+ more_reads = op_queue_[read_op].has_operation(descriptor);++ if (events[i].events & (POLLOUT | POLLERR | POLLHUP))+ more_writes = op_queue_[write_op].perform_operations(descriptor, ops);+ else+ more_writes = op_queue_[write_op].has_operation(descriptor);++ if ((events[i].events & (POLLERR | POLLHUP)) != 0+ && !more_except && !more_reads && !more_writes)+ {+ // If we have an event and no operations associated with the+ // descriptor then we need to delete the descriptor from /dev/poll.+ // The poll operation can produce POLLHUP or POLLERR events when there+ // is no operation pending, so if we do not remove the descriptor we+ // can end up in a tight polling loop.+ ::pollfd ev = { 0, 0, 0 };+ ev.fd = descriptor;+ ev.events = POLLREMOVE;+ ev.revents = 0;+ ::write(dev_poll_fd_, &ev, sizeof(ev));+ }+ else+ {+ ::pollfd ev = { 0, 0, 0 };+ ev.fd = descriptor;+ ev.events = POLLERR | POLLHUP;+ if (more_reads)+ ev.events |= POLLIN;+ if (more_writes)+ ev.events |= POLLOUT;+ if (more_except)+ ev.events |= POLLPRI;+ ev.revents = 0;+ int result = ::write(dev_poll_fd_, &ev, sizeof(ev));+ if (result != sizeof(ev))+ {+ asio::error_code ec(errno,+ asio::error::get_system_category());+ for (int j = 0; j < max_ops; ++j)+ op_queue_[j].cancel_operations(descriptor, ops, ec);+ }+ }+ }+ }+ timer_queues_.get_ready_timers(ops);+}++void dev_poll_reactor::interrupt()+{+ interrupter_.interrupt();+}++int dev_poll_reactor::do_dev_poll_create()+{+ int fd = ::open("/dev/poll", O_RDWR);+ if (fd == -1)+ {+ asio::error_code ec(errno,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "/dev/poll");+ }+ return fd;+}++void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(mutex_);+ timer_queues_.insert(&queue);+}++void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(mutex_);+ timer_queues_.erase(&queue);+}++int dev_poll_reactor::get_timeout(int msec)+{+ // By default we will wait no longer than 5 minutes. This will ensure that+ // any changes to the system clock are detected after no longer than this.+ const int max_msec = 5 * 60 * 1000;+ return timer_queues_.wait_duration_msec(+ (msec < 0 || max_msec < msec) ? max_msec : msec);+}++void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor,+ const asio::error_code& ec)+{+ bool need_interrupt = false;+ op_queue<operation> ops;+ for (int i = 0; i < max_ops; ++i)+ need_interrupt = op_queue_[i].cancel_operations(+ descriptor, ops, ec) || need_interrupt;+ scheduler_.post_deferred_completions(ops);+ if (need_interrupt)+ interrupter_.interrupt();+}++::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor)+{+ hash_map<int, std::size_t>::iterator iter+ = pending_event_change_index_.find(descriptor);+ if (iter == pending_event_change_index_.end())+ {+ std::size_t index = pending_event_changes_.size();+ pending_event_changes_.reserve(pending_event_changes_.size() + 1);+ pending_event_change_index_.insert(std::make_pair(descriptor, index));+ pending_event_changes_.push_back(::pollfd());+ pending_event_changes_[index].fd = descriptor;+ pending_event_changes_[index].revents = 0;+ return pending_event_changes_[index];+ }+ else+ {+ return pending_event_changes_[iter->second];+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_DEV_POLL)++#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/epoll_reactor.hpp view
@@ -0,0 +1,89 @@+//+// detail/impl/epoll_reactor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_EPOLL_REACTOR_HPP+#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#if defined(ASIO_HAS_EPOLL)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Time_Traits>+void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)+{+ do_add_timer_queue(queue);+}++template <typename Time_Traits>+void epoll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)+{+ do_remove_timer_queue(queue);+}++template <typename Time_Traits>+void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)+{+ mutex::scoped_lock lock(mutex_);++ if (shutdown_)+ {+ scheduler_.post_immediate_completion(op, false);+ return;+ }++ bool earliest = queue.enqueue_timer(time, timer, op);+ scheduler_.work_started();+ if (earliest)+ update_timeout();+}++template <typename Time_Traits>+std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled)+{+ mutex::scoped_lock lock(mutex_);+ op_queue<operation> ops;+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);+ lock.unlock();+ scheduler_.post_deferred_completions(ops);+ return n;+}++template <typename Time_Traits>+void epoll_reactor::move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& target,+ typename timer_queue<Time_Traits>::per_timer_data& source)+{+ mutex::scoped_lock lock(mutex_);+ op_queue<operation> ops;+ queue.cancel_timer(target, ops);+ queue.move_timer(target, source);+ lock.unlock();+ scheduler_.post_deferred_completions(ops);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_EPOLL)++#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/epoll_reactor.ipp view
@@ -0,0 +1,787 @@+//+// detail/impl/epoll_reactor.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_EPOLL_REACTOR_IPP+#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP++#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_EPOLL)++#include <cstddef>+#include <sys/epoll.h>+#include "asio/detail/epoll_reactor.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#if defined(ASIO_HAS_TIMERFD)+# include <sys/timerfd.h>+#endif // defined(ASIO_HAS_TIMERFD)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++epoll_reactor::epoll_reactor(asio::execution_context& ctx)+ : execution_context_service_base<epoll_reactor>(ctx),+ scheduler_(use_service<scheduler>(ctx)),+ mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(+ REACTOR_REGISTRATION, scheduler_.concurrency_hint())),+ interrupter_(),+ epoll_fd_(do_epoll_create()),+ timer_fd_(do_timerfd_create()),+ shutdown_(false),+ registered_descriptors_mutex_(mutex_.enabled())+{+ // Add the interrupter's descriptor to epoll.+ epoll_event ev = { 0, { 0 } };+ ev.events = EPOLLIN | EPOLLERR | EPOLLET;+ ev.data.ptr = &interrupter_;+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);+ interrupter_.interrupt();++ // Add the timer descriptor to epoll.+ if (timer_fd_ != -1)+ {+ ev.events = EPOLLIN | EPOLLERR;+ ev.data.ptr = &timer_fd_;+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);+ }+}++epoll_reactor::~epoll_reactor()+{+ if (epoll_fd_ != -1)+ close(epoll_fd_);+ if (timer_fd_ != -1)+ close(timer_fd_);+}++void epoll_reactor::shutdown()+{+ mutex::scoped_lock lock(mutex_);+ shutdown_ = true;+ lock.unlock();++ op_queue<operation> ops;++ while (descriptor_state* state = registered_descriptors_.first())+ {+ for (int i = 0; i < max_ops; ++i)+ ops.push(state->op_queue_[i]);+ state->shutdown_ = true;+ registered_descriptors_.free(state);+ }++ timer_queues_.get_all_timers(ops);++ scheduler_.abandon_operations(ops);+}++void epoll_reactor::notify_fork(+ asio::execution_context::fork_event fork_ev)+{+ if (fork_ev == asio::execution_context::fork_child)+ {+ if (epoll_fd_ != -1)+ ::close(epoll_fd_);+ epoll_fd_ = -1;+ epoll_fd_ = do_epoll_create();++ if (timer_fd_ != -1)+ ::close(timer_fd_);+ timer_fd_ = -1;+ timer_fd_ = do_timerfd_create();++ interrupter_.recreate();++ // Add the interrupter's descriptor to epoll.+ epoll_event ev = { 0, { 0 } };+ ev.events = EPOLLIN | EPOLLERR | EPOLLET;+ ev.data.ptr = &interrupter_;+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);+ interrupter_.interrupt();++ // Add the timer descriptor to epoll.+ if (timer_fd_ != -1)+ {+ ev.events = EPOLLIN | EPOLLERR;+ ev.data.ptr = &timer_fd_;+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);+ }++ update_timeout();++ // Re-register all descriptors with epoll.+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);+ for (descriptor_state* state = registered_descriptors_.first();+ state != 0; state = state->next_)+ {+ ev.events = state->registered_events_;+ ev.data.ptr = state;+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, state->descriptor_, &ev);+ if (result != 0)+ {+ asio::error_code ec(errno,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "epoll re-registration");+ }+ }+ }+}++void epoll_reactor::init_task()+{+ scheduler_.init_task();+}++int epoll_reactor::register_descriptor(socket_type descriptor,+ epoll_reactor::per_descriptor_data& descriptor_data)+{+ descriptor_data = allocate_descriptor_state();++ ASIO_HANDLER_REACTOR_REGISTRATION((+ context(), static_cast<uintmax_t>(descriptor),+ reinterpret_cast<uintmax_t>(descriptor_data)));++ {+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);++ descriptor_data->reactor_ = this;+ descriptor_data->descriptor_ = descriptor;+ descriptor_data->shutdown_ = false;+ for (int i = 0; i < max_ops; ++i)+ descriptor_data->try_speculative_[i] = true;+ }++ epoll_event ev = { 0, { 0 } };+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET;+ descriptor_data->registered_events_ = ev.events;+ ev.data.ptr = descriptor_data;+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);+ if (result != 0)+ {+ if (errno == EPERM)+ {+ // This file descriptor type is not supported by epoll. However, if it is+ // a regular file then operations on it will not block. We will allow+ // this descriptor to be used and fail later if an operation on it would+ // otherwise require a trip through the reactor.+ descriptor_data->registered_events_ = 0;+ return 0;+ }+ return errno;+ }++ return 0;+}++int epoll_reactor::register_internal_descriptor(+ int op_type, socket_type descriptor,+ epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op)+{+ descriptor_data = allocate_descriptor_state();++ ASIO_HANDLER_REACTOR_REGISTRATION((+ context(), static_cast<uintmax_t>(descriptor),+ reinterpret_cast<uintmax_t>(descriptor_data)));++ {+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);++ descriptor_data->reactor_ = this;+ descriptor_data->descriptor_ = descriptor;+ descriptor_data->shutdown_ = false;+ descriptor_data->op_queue_[op_type].push(op);+ for (int i = 0; i < max_ops; ++i)+ descriptor_data->try_speculative_[i] = true;+ }++ epoll_event ev = { 0, { 0 } };+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET;+ descriptor_data->registered_events_ = ev.events;+ ev.data.ptr = descriptor_data;+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);+ if (result != 0)+ return errno;++ return 0;+}++void epoll_reactor::move_descriptor(socket_type,+ epoll_reactor::per_descriptor_data& target_descriptor_data,+ epoll_reactor::per_descriptor_data& source_descriptor_data)+{+ target_descriptor_data = source_descriptor_data;+ source_descriptor_data = 0;+}++void epoll_reactor::start_op(int op_type, socket_type descriptor,+ epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op,+ bool is_continuation, bool allow_speculative)+{+ if (!descriptor_data)+ {+ op->ec_ = asio::error::bad_descriptor;+ post_immediate_completion(op, is_continuation);+ return;+ }++ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);++ if (descriptor_data->shutdown_)+ {+ post_immediate_completion(op, is_continuation);+ return;+ }++ if (descriptor_data->op_queue_[op_type].empty())+ {+ if (allow_speculative+ && (op_type != read_op+ || descriptor_data->op_queue_[except_op].empty()))+ {+ if (descriptor_data->try_speculative_[op_type])+ {+ if (reactor_op::status status = op->perform())+ {+ if (status == reactor_op::done_and_exhausted)+ if (descriptor_data->registered_events_ != 0)+ descriptor_data->try_speculative_[op_type] = false;+ descriptor_lock.unlock();+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }+ }++ if (descriptor_data->registered_events_ == 0)+ {+ op->ec_ = asio::error::operation_not_supported;+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }++ if (op_type == write_op)+ {+ if ((descriptor_data->registered_events_ & EPOLLOUT) == 0)+ {+ epoll_event ev = { 0, { 0 } };+ ev.events = descriptor_data->registered_events_ | EPOLLOUT;+ ev.data.ptr = descriptor_data;+ if (epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev) == 0)+ {+ descriptor_data->registered_events_ |= ev.events;+ }+ else+ {+ op->ec_ = asio::error_code(errno,+ asio::error::get_system_category());+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }+ }+ }+ }+ else if (descriptor_data->registered_events_ == 0)+ {+ op->ec_ = asio::error::operation_not_supported;+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }+ else+ {+ if (op_type == write_op)+ {+ descriptor_data->registered_events_ |= EPOLLOUT;+ }++ epoll_event ev = { 0, { 0 } };+ ev.events = descriptor_data->registered_events_;+ ev.data.ptr = descriptor_data;+ epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);+ }+ }++ descriptor_data->op_queue_[op_type].push(op);+ scheduler_.work_started();+}++void epoll_reactor::cancel_ops(socket_type,+ epoll_reactor::per_descriptor_data& descriptor_data)+{+ if (!descriptor_data)+ return;++ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);++ op_queue<operation> ops;+ for (int i = 0; i < max_ops; ++i)+ {+ while (reactor_op* op = descriptor_data->op_queue_[i].front())+ {+ op->ec_ = asio::error::operation_aborted;+ descriptor_data->op_queue_[i].pop();+ ops.push(op);+ }+ }++ descriptor_lock.unlock();++ scheduler_.post_deferred_completions(ops);+}++void epoll_reactor::deregister_descriptor(socket_type descriptor,+ epoll_reactor::per_descriptor_data& descriptor_data, bool closing)+{+ if (!descriptor_data)+ return;++ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);++ if (!descriptor_data->shutdown_)+ {+ if (closing)+ {+ // The descriptor will be automatically removed from the epoll set when+ // it is closed.+ }+ else if (descriptor_data->registered_events_ != 0)+ {+ epoll_event ev = { 0, { 0 } };+ epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);+ }++ op_queue<operation> ops;+ for (int i = 0; i < max_ops; ++i)+ {+ while (reactor_op* op = descriptor_data->op_queue_[i].front())+ {+ op->ec_ = asio::error::operation_aborted;+ descriptor_data->op_queue_[i].pop();+ ops.push(op);+ }+ }++ descriptor_data->descriptor_ = -1;+ descriptor_data->shutdown_ = true;++ descriptor_lock.unlock();++ ASIO_HANDLER_REACTOR_DEREGISTRATION((+ context(), static_cast<uintmax_t>(descriptor),+ reinterpret_cast<uintmax_t>(descriptor_data)));++ scheduler_.post_deferred_completions(ops);++ // Leave descriptor_data set so that it will be freed by the subsequent+ // call to cleanup_descriptor_data.+ }+ else+ {+ // We are shutting down, so prevent cleanup_descriptor_data from freeing+ // the descriptor_data object and let the destructor free it instead.+ descriptor_data = 0;+ }+}++void epoll_reactor::deregister_internal_descriptor(socket_type descriptor,+ epoll_reactor::per_descriptor_data& descriptor_data)+{+ if (!descriptor_data)+ return;++ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);++ if (!descriptor_data->shutdown_)+ {+ epoll_event ev = { 0, { 0 } };+ epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);++ op_queue<operation> ops;+ for (int i = 0; i < max_ops; ++i)+ ops.push(descriptor_data->op_queue_[i]);++ descriptor_data->descriptor_ = -1;+ descriptor_data->shutdown_ = true;++ descriptor_lock.unlock();++ ASIO_HANDLER_REACTOR_DEREGISTRATION((+ context(), static_cast<uintmax_t>(descriptor),+ reinterpret_cast<uintmax_t>(descriptor_data)));++ // Leave descriptor_data set so that it will be freed by the subsequent+ // call to cleanup_descriptor_data.+ }+ else+ {+ // We are shutting down, so prevent cleanup_descriptor_data from freeing+ // the descriptor_data object and let the destructor free it instead.+ descriptor_data = 0;+ }+}++void epoll_reactor::cleanup_descriptor_data(+ per_descriptor_data& descriptor_data)+{+ if (descriptor_data)+ {+ free_descriptor_state(descriptor_data);+ descriptor_data = 0;+ }+}++void epoll_reactor::run(long usec, op_queue<operation>& ops)+{+ // This code relies on the fact that the scheduler queues the reactor task+ // behind all descriptor operations generated by this function. This means,+ // that by the time we reach this point, any previously returned descriptor+ // operations have already been dequeued. Therefore it is now safe for us to+ // reuse and return them for the scheduler to queue again.++ // Calculate timeout. Check the timer queues only if timerfd is not in use.+ int timeout;+ if (usec == 0)+ timeout = 0;+ else+ {+ timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1);+ if (timer_fd_ == -1)+ {+ mutex::scoped_lock lock(mutex_);+ timeout = get_timeout(timeout);+ }+ }++ // Block on the epoll descriptor.+ epoll_event events[128];+ int num_events = epoll_wait(epoll_fd_, events, 128, timeout);++#if defined(ASIO_ENABLE_HANDLER_TRACKING)+ // Trace the waiting events.+ for (int i = 0; i < num_events; ++i)+ {+ void* ptr = events[i].data.ptr;+ if (ptr == &interrupter_)+ {+ // Ignore.+ }+# if defined(ASIO_HAS_TIMERFD)+ else if (ptr == &timer_fd_)+ {+ // Ignore.+ }+# endif // defined(ASIO_HAS_TIMERFD)+ else+ {+ unsigned event_mask = 0;+ if ((events[i].events & EPOLLIN) != 0)+ event_mask |= ASIO_HANDLER_REACTOR_READ_EVENT;+ if ((events[i].events & EPOLLOUT))+ event_mask |= ASIO_HANDLER_REACTOR_WRITE_EVENT;+ if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0)+ event_mask |= ASIO_HANDLER_REACTOR_ERROR_EVENT;+ ASIO_HANDLER_REACTOR_EVENTS((context(),+ reinterpret_cast<uintmax_t>(ptr), event_mask));+ }+ }+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)++#if defined(ASIO_HAS_TIMERFD)+ bool check_timers = (timer_fd_ == -1);+#else // defined(ASIO_HAS_TIMERFD)+ bool check_timers = true;+#endif // defined(ASIO_HAS_TIMERFD)++ // Dispatch the waiting events.+ for (int i = 0; i < num_events; ++i)+ {+ void* ptr = events[i].data.ptr;+ if (ptr == &interrupter_)+ {+ // No need to reset the interrupter since we're leaving the descriptor+ // in a ready-to-read state and relying on edge-triggered notifications+ // to make it so that we only get woken up when the descriptor's epoll+ // registration is updated.++#if defined(ASIO_HAS_TIMERFD)+ if (timer_fd_ == -1)+ check_timers = true;+#else // defined(ASIO_HAS_TIMERFD)+ check_timers = true;+#endif // defined(ASIO_HAS_TIMERFD)+ }+#if defined(ASIO_HAS_TIMERFD)+ else if (ptr == &timer_fd_)+ {+ check_timers = true;+ }+#endif // defined(ASIO_HAS_TIMERFD)+ else+ {+ // The descriptor operation doesn't count as work in and of itself, so we+ // don't call work_started() here. This still allows the scheduler to+ // stop if the only remaining operations are descriptor operations.+ descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);+ if (!ops.is_enqueued(descriptor_data))+ {+ descriptor_data->set_ready_events(events[i].events);+ ops.push(descriptor_data);+ }+ else+ {+ descriptor_data->add_ready_events(events[i].events);+ }+ }+ }++ if (check_timers)+ {+ mutex::scoped_lock common_lock(mutex_);+ timer_queues_.get_ready_timers(ops);++#if defined(ASIO_HAS_TIMERFD)+ if (timer_fd_ != -1)+ {+ itimerspec new_timeout;+ itimerspec old_timeout;+ int flags = get_timeout(new_timeout);+ timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);+ }+#endif // defined(ASIO_HAS_TIMERFD)+ }+}++void epoll_reactor::interrupt()+{+ epoll_event ev = { 0, { 0 } };+ ev.events = EPOLLIN | EPOLLERR | EPOLLET;+ ev.data.ptr = &interrupter_;+ epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev);+}++int epoll_reactor::do_epoll_create()+{+#if defined(EPOLL_CLOEXEC)+ int fd = epoll_create1(EPOLL_CLOEXEC);+#else // defined(EPOLL_CLOEXEC)+ int fd = -1;+ errno = EINVAL;+#endif // defined(EPOLL_CLOEXEC)++ if (fd == -1 && (errno == EINVAL || errno == ENOSYS))+ {+ fd = epoll_create(epoll_size);+ if (fd != -1)+ ::fcntl(fd, F_SETFD, FD_CLOEXEC);+ }++ if (fd == -1)+ {+ asio::error_code ec(errno,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "epoll");+ }++ return fd;+}++int epoll_reactor::do_timerfd_create()+{+#if defined(ASIO_HAS_TIMERFD)+# if defined(TFD_CLOEXEC)+ int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);+# else // defined(TFD_CLOEXEC)+ int fd = -1;+ errno = EINVAL;+# endif // defined(TFD_CLOEXEC)++ if (fd == -1 && errno == EINVAL)+ {+ fd = timerfd_create(CLOCK_MONOTONIC, 0);+ if (fd != -1)+ ::fcntl(fd, F_SETFD, FD_CLOEXEC);+ }++ return fd;+#else // defined(ASIO_HAS_TIMERFD)+ return -1;+#endif // defined(ASIO_HAS_TIMERFD)+}++epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state()+{+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);+ return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING(+ REACTOR_IO, scheduler_.concurrency_hint()));+}++void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s)+{+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);+ registered_descriptors_.free(s);+}++void epoll_reactor::do_add_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(mutex_);+ timer_queues_.insert(&queue);+}++void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(mutex_);+ timer_queues_.erase(&queue);+}++void epoll_reactor::update_timeout()+{+#if defined(ASIO_HAS_TIMERFD)+ if (timer_fd_ != -1)+ {+ itimerspec new_timeout;+ itimerspec old_timeout;+ int flags = get_timeout(new_timeout);+ timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);+ return;+ }+#endif // defined(ASIO_HAS_TIMERFD)+ interrupt();+}++int epoll_reactor::get_timeout(int msec)+{+ // By default we will wait no longer than 5 minutes. This will ensure that+ // any changes to the system clock are detected after no longer than this.+ const int max_msec = 5 * 60 * 1000;+ return timer_queues_.wait_duration_msec(+ (msec < 0 || max_msec < msec) ? max_msec : msec);+}++#if defined(ASIO_HAS_TIMERFD)+int epoll_reactor::get_timeout(itimerspec& ts)+{+ ts.it_interval.tv_sec = 0;+ ts.it_interval.tv_nsec = 0;++ long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);+ ts.it_value.tv_sec = usec / 1000000;+ ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;++ return usec ? 0 : TFD_TIMER_ABSTIME;+}+#endif // defined(ASIO_HAS_TIMERFD)++struct epoll_reactor::perform_io_cleanup_on_block_exit+{+ explicit perform_io_cleanup_on_block_exit(epoll_reactor* r)+ : reactor_(r), first_op_(0)+ {+ }++ ~perform_io_cleanup_on_block_exit()+ {+ if (first_op_)+ {+ // Post the remaining completed operations for invocation.+ if (!ops_.empty())+ reactor_->scheduler_.post_deferred_completions(ops_);++ // A user-initiated operation has completed, but there's no need to+ // explicitly call work_finished() here. Instead, we'll take advantage of+ // the fact that the scheduler will call work_finished() once we return.+ }+ else+ {+ // No user-initiated operations have completed, so we need to compensate+ // for the work_finished() call that the scheduler will make once this+ // operation returns.+ reactor_->scheduler_.compensating_work_started();+ }+ }++ epoll_reactor* reactor_;+ op_queue<operation> ops_;+ operation* first_op_;+};++epoll_reactor::descriptor_state::descriptor_state(bool locking)+ : operation(&epoll_reactor::descriptor_state::do_complete),+ mutex_(locking)+{+}++operation* epoll_reactor::descriptor_state::perform_io(uint32_t events)+{+ mutex_.lock();+ perform_io_cleanup_on_block_exit io_cleanup(reactor_);+ mutex::scoped_lock descriptor_lock(mutex_, mutex::scoped_lock::adopt_lock);++ // Exception operations must be processed first to ensure that any+ // out-of-band data is read before normal data.+ static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };+ for (int j = max_ops - 1; j >= 0; --j)+ {+ if (events & (flag[j] | EPOLLERR | EPOLLHUP))+ {+ try_speculative_[j] = true;+ while (reactor_op* op = op_queue_[j].front())+ {+ if (reactor_op::status status = op->perform())+ {+ op_queue_[j].pop();+ io_cleanup.ops_.push(op);+ if (status == reactor_op::done_and_exhausted)+ {+ try_speculative_[j] = false;+ break;+ }+ }+ else+ break;+ }+ }+ }++ // The first operation will be returned for completion now. The others will+ // be posted for later by the io_cleanup object's destructor.+ io_cleanup.first_op_ = io_cleanup.ops_.front();+ io_cleanup.ops_.pop();+ return io_cleanup.first_op_;+}++void epoll_reactor::descriptor_state::do_complete(+ void* owner, operation* base,+ const asio::error_code& ec, std::size_t bytes_transferred)+{+ if (owner)+ {+ descriptor_state* descriptor_data = static_cast<descriptor_state*>(base);+ uint32_t events = static_cast<uint32_t>(bytes_transferred);+ if (operation* op = descriptor_data->perform_io(events))+ {+ op->complete(owner, ec, 0);+ }+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_EPOLL)++#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/eventfd_select_interrupter.ipp view
@@ -0,0 +1,169 @@+//+// detail/impl/eventfd_select_interrupter.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail 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_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP+#define ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP++#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_EVENTFD)++#include <sys/stat.h>+#include <sys/types.h>+#include <fcntl.h>+#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8+# include <asm/unistd.h>+#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8+# include <sys/eventfd.h>+#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8+#include "asio/detail/cstdint.hpp"+#include "asio/detail/eventfd_select_interrupter.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++eventfd_select_interrupter::eventfd_select_interrupter()+{+ open_descriptors();+}++void eventfd_select_interrupter::open_descriptors()+{+#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8+ write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);+ if (read_descriptor_ != -1)+ {+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);+ ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);+ }+#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8+# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)+ write_descriptor_ = read_descriptor_ =+ ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);+# else // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)+ errno = EINVAL;+ write_descriptor_ = read_descriptor_ = -1;+# endif // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)+ if (read_descriptor_ == -1 && errno == EINVAL)+ {+ write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);+ if (read_descriptor_ != -1)+ {+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);+ ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);+ }+ }+#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8++ if (read_descriptor_ == -1)+ {+ int pipe_fds[2];+ if (pipe(pipe_fds) == 0)+ {+ read_descriptor_ = pipe_fds[0];+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);+ ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);+ write_descriptor_ = pipe_fds[1];+ ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);+ ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC);+ }+ else+ {+ asio::error_code ec(errno,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "eventfd_select_interrupter");+ }+ }+}++eventfd_select_interrupter::~eventfd_select_interrupter()+{+ close_descriptors();+}++void eventfd_select_interrupter::close_descriptors()+{+ if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)+ ::close(write_descriptor_);+ if (read_descriptor_ != -1)+ ::close(read_descriptor_);+}++void eventfd_select_interrupter::recreate()+{+ close_descriptors();++ write_descriptor_ = -1;+ read_descriptor_ = -1;++ open_descriptors();+}++void eventfd_select_interrupter::interrupt()+{+ uint64_t counter(1UL);+ int result = ::write(write_descriptor_, &counter, sizeof(uint64_t));+ (void)result;+}++bool eventfd_select_interrupter::reset()+{+ if (write_descriptor_ == read_descriptor_)+ {+ for (;;)+ {+ // Only perform one read. The kernel maintains an atomic counter.+ uint64_t counter(0);+ errno = 0;+ int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));+ if (bytes_read < 0 && errno == EINTR)+ continue;+ return true;+ }+ }+ else+ {+ for (;;)+ {+ // Clear all data from the pipe.+ char data[1024];+ int bytes_read = ::read(read_descriptor_, data, sizeof(data));+ if (bytes_read == sizeof(data))+ continue;+ if (bytes_read > 0)+ return true;+ if (bytes_read == 0)+ return false;+ if (errno == EINTR)+ continue;+ if (errno == EWOULDBLOCK || errno == EAGAIN)+ return true;+ return false;+ }+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_EVENTFD)++#endif // ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/handler_tracking.ipp view
@@ -0,0 +1,396 @@+//+// detail/impl/handler_tracking.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_HANDLER_TRACKING_IPP+#define ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(ASIO_CUSTOM_HANDLER_TRACKING)++// The handler tracking implementation is provided by the user-specified header.++#elif defined(ASIO_ENABLE_HANDLER_TRACKING)++#include <cstdarg>+#include <cstdio>+#include "asio/detail/handler_tracking.hpp"++#if defined(ASIO_HAS_BOOST_DATE_TIME)+# include "asio/time_traits.hpp"+#elif defined(ASIO_HAS_CHRONO)+# include "asio/detail/chrono.hpp"+# include "asio/detail/chrono_time_traits.hpp"+# include "asio/wait_traits.hpp"+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)++#if defined(ASIO_WINDOWS_RUNTIME)+# include "asio/detail/socket_types.hpp"+#elif !defined(ASIO_WINDOWS)+# include <unistd.h>+#endif // !defined(ASIO_WINDOWS)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++struct handler_tracking_timestamp+{+ uint64_t seconds;+ uint64_t microseconds;++ handler_tracking_timestamp()+ {+#if defined(ASIO_HAS_BOOST_DATE_TIME)+ boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));+ boost::posix_time::time_duration now =+ boost::posix_time::microsec_clock::universal_time() - epoch;+#elif defined(ASIO_HAS_CHRONO)+ typedef chrono_time_traits<chrono::system_clock,+ asio::wait_traits<chrono::system_clock> > traits_helper;+ traits_helper::posix_time_duration now(+ chrono::system_clock::now().time_since_epoch());+#endif+ seconds = static_cast<uint64_t>(now.total_seconds());+ microseconds = static_cast<uint64_t>(now.total_microseconds() % 1000000);+ }+};++struct handler_tracking::tracking_state+{+ static_mutex mutex_;+ uint64_t next_id_;+ tss_ptr<completion>* current_completion_;+ tss_ptr<location>* current_location_;+};++handler_tracking::tracking_state* handler_tracking::get_state()+{+ static tracking_state state = { ASIO_STATIC_MUTEX_INIT, 1, 0, 0 };+ return &state;+}++void handler_tracking::init()+{+ static tracking_state* state = get_state();++ state->mutex_.init();++ static_mutex::scoped_lock lock(state->mutex_);+ if (state->current_completion_ == 0)+ state->current_completion_ = new tss_ptr<completion>;+ if (state->current_location_ == 0)+ state->current_location_ = new tss_ptr<location>;+}++handler_tracking::location::location(+ const char* file, int line, const char* func)+ : file_(file),+ line_(line),+ func_(func),+ next_(*get_state()->current_location_)+{+ if (file_)+ *get_state()->current_location_ = this;+}++handler_tracking::location::~location()+{+ if (file_)+ *get_state()->current_location_ = next_;+}++void handler_tracking::creation(execution_context&,+ handler_tracking::tracked_handler& h,+ const char* object_type, void* object,+ uintmax_t /*native_handle*/, const char* op_name)+{+ static tracking_state* state = get_state();++ static_mutex::scoped_lock lock(state->mutex_);+ h.id_ = state->next_id_++;+ lock.unlock();++ handler_tracking_timestamp timestamp;++ uint64_t current_id = 0;+ if (completion* current_completion = *state->current_completion_)+ current_id = current_completion->id_;++ for (location* current_location = *state->current_location_;+ current_location; current_location = current_location->next_)+ {+ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|%I64u^%I64u|%s%s%.80s%s(%.80s:%d)\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|%llu^%llu|%s%s%.80s%s(%.80s:%d)\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds,+ current_id, h.id_,+ current_location == *state->current_location_ ? "in " : "called from ",+ current_location->func_ ? "'" : "",+ current_location->func_ ? current_location->func_ : "",+ current_location->func_ ? "' " : "",+ current_location->file_, current_location->line_);+ }++ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|%llu*%llu|%.20s@%p.%.50s\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds,+ current_id, h.id_, object_type, object, op_name);+}++handler_tracking::completion::completion(+ const handler_tracking::tracked_handler& h)+ : id_(h.id_),+ invoked_(false),+ next_(*get_state()->current_completion_)+{+ *get_state()->current_completion_ = this;+}++handler_tracking::completion::~completion()+{+ if (id_)+ {+ handler_tracking_timestamp timestamp;++ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|%c%I64u|\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|%c%llu|\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds,+ invoked_ ? '!' : '~', id_);+ }++ *get_state()->current_completion_ = next_;+}++void handler_tracking::completion::invocation_begin()+{+ handler_tracking_timestamp timestamp;++ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|>%I64u|\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|>%llu|\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds, id_);++ invoked_ = true;+}++void handler_tracking::completion::invocation_begin(+ const asio::error_code& ec)+{+ handler_tracking_timestamp timestamp;++ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|>%llu|ec=%.20s:%d\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds,+ id_, ec.category().name(), ec.value());++ invoked_ = true;+}++void handler_tracking::completion::invocation_begin(+ const asio::error_code& ec, std::size_t bytes_transferred)+{+ handler_tracking_timestamp timestamp;++ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,bytes_transferred=%I64u\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,bytes_transferred=%llu\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds,+ id_, ec.category().name(), ec.value(),+ static_cast<uint64_t>(bytes_transferred));++ invoked_ = true;+}++void handler_tracking::completion::invocation_begin(+ const asio::error_code& ec, int signal_number)+{+ handler_tracking_timestamp timestamp;++ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,signal_number=%d\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,signal_number=%d\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds,+ id_, ec.category().name(), ec.value(), signal_number);++ invoked_ = true;+}++void handler_tracking::completion::invocation_begin(+ const asio::error_code& ec, const char* arg)+{+ handler_tracking_timestamp timestamp;++ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,%.50s\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,%.50s\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds,+ id_, ec.category().name(), ec.value(), arg);++ invoked_ = true;+}++void handler_tracking::completion::invocation_end()+{+ if (id_)+ {+ handler_tracking_timestamp timestamp;++ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|<%I64u|\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|<%llu|\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds, id_);++ id_ = 0;+ }+}++void handler_tracking::operation(execution_context&,+ const char* object_type, void* object,+ uintmax_t /*native_handle*/, const char* op_name)+{+ static tracking_state* state = get_state();++ handler_tracking_timestamp timestamp;++ unsigned long long current_id = 0;+ if (completion* current_completion = *state->current_completion_)+ current_id = current_completion->id_;++ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|%I64u|%.20s@%p.%.50s\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|%llu|%.20s@%p.%.50s\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds,+ current_id, object_type, object, op_name);+}++void handler_tracking::reactor_registration(execution_context& /*context*/,+ uintmax_t /*native_handle*/, uintmax_t /*registration*/)+{+}++void handler_tracking::reactor_deregistration(execution_context& /*context*/,+ uintmax_t /*native_handle*/, uintmax_t /*registration*/)+{+}++void handler_tracking::reactor_events(execution_context& /*context*/,+ uintmax_t /*native_handle*/, unsigned /*events*/)+{+}++void handler_tracking::reactor_operation(+ const tracked_handler& h, const char* op_name,+ const asio::error_code& ec)+{+ handler_tracking_timestamp timestamp;++ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds,+ h.id_, op_name, ec.category().name(), ec.value());+}++void handler_tracking::reactor_operation(+ const tracked_handler& h, const char* op_name,+ const asio::error_code& ec, std::size_t bytes_transferred)+{+ handler_tracking_timestamp timestamp;++ write_line(+#if defined(ASIO_WINDOWS)+ "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d,bytes_transferred=%I64u\n",+#else // defined(ASIO_WINDOWS)+ "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d,bytes_transferred=%llu\n",+#endif // defined(ASIO_WINDOWS)+ timestamp.seconds, timestamp.microseconds,+ h.id_, op_name, ec.category().name(), ec.value(),+ static_cast<uint64_t>(bytes_transferred));+}++void handler_tracking::write_line(const char* format, ...)+{+ using namespace std; // For sprintf (or equivalent).++ va_list args;+ va_start(args, format);++ char line[256] = "";+#if defined(ASIO_HAS_SECURE_RTL)+ int length = vsprintf_s(line, sizeof(line), format, args);+#else // defined(ASIO_HAS_SECURE_RTL)+ int length = vsprintf(line, format, args);+#endif // defined(ASIO_HAS_SECURE_RTL)++ va_end(args);++#if defined(ASIO_WINDOWS_RUNTIME)+ wchar_t wline[256] = L"";+ mbstowcs_s(0, wline, sizeof(wline) / sizeof(wchar_t), line, length);+ ::OutputDebugStringW(wline);+#elif defined(ASIO_WINDOWS)+ HANDLE stderr_handle = ::GetStdHandle(STD_ERROR_HANDLE);+ DWORD bytes_written = 0;+ ::WriteFile(stderr_handle, line, length, &bytes_written, 0);+#else // defined(ASIO_WINDOWS)+ ::write(STDERR_FILENO, line, length);+#endif // defined(ASIO_WINDOWS)+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)++#endif // ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/kqueue_reactor.hpp view
@@ -0,0 +1,93 @@+//+// detail/impl/kqueue_reactor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2005 Stefan Arentz (stefan at soze 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_IMPL_KQUEUE_REACTOR_HPP+#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_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_KQUEUE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Time_Traits>+void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)+{+ do_add_timer_queue(queue);+}++// Remove a timer queue from the reactor.+template <typename Time_Traits>+void kqueue_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)+{+ do_remove_timer_queue(queue);+}++template <typename Time_Traits>+void kqueue_reactor::schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)+{+ mutex::scoped_lock lock(mutex_);++ if (shutdown_)+ {+ scheduler_.post_immediate_completion(op, false);+ return;+ }++ bool earliest = queue.enqueue_timer(time, timer, op);+ scheduler_.work_started();+ if (earliest)+ interrupt();+}++template <typename Time_Traits>+std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled)+{+ mutex::scoped_lock lock(mutex_);+ op_queue<operation> ops;+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);+ lock.unlock();+ scheduler_.post_deferred_completions(ops);+ return n;+}++template <typename Time_Traits>+void kqueue_reactor::move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& target,+ typename timer_queue<Time_Traits>::per_timer_data& source)+{+ mutex::scoped_lock lock(mutex_);+ op_queue<operation> ops;+ queue.cancel_timer(target, ops);+ queue.move_timer(target, source);+ lock.unlock();+ scheduler_.post_deferred_completions(ops);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_KQUEUE)++#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/kqueue_reactor.ipp view
@@ -0,0 +1,570 @@+//+// detail/impl/kqueue_reactor.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2005 Stefan Arentz (stefan at soze 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_IMPL_KQUEUE_REACTOR_IPP+#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP++#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_KQUEUE)++#include "asio/detail/kqueue_reactor.hpp"+#include "asio/detail/scheduler.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#if defined(__NetBSD__)+# include <sys/param.h>+#endif++#include "asio/detail/push_options.hpp"++#if defined(__NetBSD__) && __NetBSD_Version__ < 999001500+# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \+ EV_SET(ev, ident, filt, flags, fflags, data, \+ reinterpret_cast<intptr_t>(static_cast<void*>(udata)))+#else+# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \+ EV_SET(ev, ident, filt, flags, fflags, data, udata)+#endif++namespace asio {+namespace detail {++kqueue_reactor::kqueue_reactor(asio::execution_context& ctx)+ : execution_context_service_base<kqueue_reactor>(ctx),+ scheduler_(use_service<scheduler>(ctx)),+ mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(+ REACTOR_REGISTRATION, scheduler_.concurrency_hint())),+ kqueue_fd_(do_kqueue_create()),+ interrupter_(),+ shutdown_(false),+ registered_descriptors_mutex_(mutex_.enabled())+{+ struct kevent events[1];+ ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(),+ EVFILT_READ, EV_ADD, 0, 0, &interrupter_);+ if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1)+ {+ asio::error_code error(errno,+ asio::error::get_system_category());+ asio::detail::throw_error(error);+ }+}++kqueue_reactor::~kqueue_reactor()+{+ close(kqueue_fd_);+}++void kqueue_reactor::shutdown()+{+ mutex::scoped_lock lock(mutex_);+ shutdown_ = true;+ lock.unlock();++ op_queue<operation> ops;++ while (descriptor_state* state = registered_descriptors_.first())+ {+ for (int i = 0; i < max_ops; ++i)+ ops.push(state->op_queue_[i]);+ state->shutdown_ = true;+ registered_descriptors_.free(state);+ }++ timer_queues_.get_all_timers(ops);++ scheduler_.abandon_operations(ops);+}++void kqueue_reactor::notify_fork(+ asio::execution_context::fork_event fork_ev)+{+ if (fork_ev == asio::execution_context::fork_child)+ {+ // The kqueue descriptor is automatically closed in the child.+ kqueue_fd_ = -1;+ kqueue_fd_ = do_kqueue_create();++ interrupter_.recreate();++ struct kevent events[2];+ ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(),+ EVFILT_READ, EV_ADD, 0, 0, &interrupter_);+ if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1)+ {+ asio::error_code ec(errno,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "kqueue interrupter registration");+ }++ // Re-register all descriptors with kqueue.+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);+ for (descriptor_state* state = registered_descriptors_.first();+ state != 0; state = state->next_)+ {+ if (state->num_kevents_ > 0)+ {+ ASIO_KQUEUE_EV_SET(&events[0], state->descriptor_,+ EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, state);+ ASIO_KQUEUE_EV_SET(&events[1], state->descriptor_,+ EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, state);+ if (::kevent(kqueue_fd_, events, state->num_kevents_, 0, 0, 0) == -1)+ {+ asio::error_code ec(errno,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "kqueue re-registration");+ }+ }+ }+ }+}++void kqueue_reactor::init_task()+{+ scheduler_.init_task();+}++int kqueue_reactor::register_descriptor(socket_type descriptor,+ kqueue_reactor::per_descriptor_data& descriptor_data)+{+ descriptor_data = allocate_descriptor_state();++ ASIO_HANDLER_REACTOR_REGISTRATION((+ context(), static_cast<uintmax_t>(descriptor),+ reinterpret_cast<uintmax_t>(descriptor_data)));++ mutex::scoped_lock lock(descriptor_data->mutex_);++ descriptor_data->descriptor_ = descriptor;+ descriptor_data->num_kevents_ = 0;+ descriptor_data->shutdown_ = false;++ return 0;+}++int kqueue_reactor::register_internal_descriptor(+ int op_type, socket_type descriptor,+ kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op)+{+ descriptor_data = allocate_descriptor_state();++ ASIO_HANDLER_REACTOR_REGISTRATION((+ context(), static_cast<uintmax_t>(descriptor),+ reinterpret_cast<uintmax_t>(descriptor_data)));++ mutex::scoped_lock lock(descriptor_data->mutex_);++ descriptor_data->descriptor_ = descriptor;+ descriptor_data->num_kevents_ = 1;+ descriptor_data->shutdown_ = false;+ descriptor_data->op_queue_[op_type].push(op);++ struct kevent events[1];+ ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ,+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);+ if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1)+ return errno;++ return 0;+}++void kqueue_reactor::move_descriptor(socket_type,+ kqueue_reactor::per_descriptor_data& target_descriptor_data,+ kqueue_reactor::per_descriptor_data& source_descriptor_data)+{+ target_descriptor_data = source_descriptor_data;+ source_descriptor_data = 0;+}++void kqueue_reactor::start_op(int op_type, socket_type descriptor,+ kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op,+ bool is_continuation, bool allow_speculative)+{+ if (!descriptor_data)+ {+ op->ec_ = asio::error::bad_descriptor;+ post_immediate_completion(op, is_continuation);+ return;+ }++ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);++ if (descriptor_data->shutdown_)+ {+ post_immediate_completion(op, is_continuation);+ return;+ }++ if (descriptor_data->op_queue_[op_type].empty())+ {+ static const int num_kevents[max_ops] = { 1, 2, 1 };++ if (allow_speculative+ && (op_type != read_op+ || descriptor_data->op_queue_[except_op].empty()))+ {+ if (op->perform())+ {+ descriptor_lock.unlock();+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }++ if (descriptor_data->num_kevents_ < num_kevents[op_type])+ {+ struct kevent events[2];+ ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ,+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);+ ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE,+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);+ if (::kevent(kqueue_fd_, events, num_kevents[op_type], 0, 0, 0) != -1)+ {+ descriptor_data->num_kevents_ = num_kevents[op_type];+ }+ else+ {+ op->ec_ = asio::error_code(errno,+ asio::error::get_system_category());+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }+ }+ }+ else+ {+ if (descriptor_data->num_kevents_ < num_kevents[op_type])+ descriptor_data->num_kevents_ = num_kevents[op_type];++ struct kevent events[2];+ ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ,+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);+ ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE,+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);+ ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0);+ }+ }++ descriptor_data->op_queue_[op_type].push(op);+ scheduler_.work_started();+}++void kqueue_reactor::cancel_ops(socket_type,+ kqueue_reactor::per_descriptor_data& descriptor_data)+{+ if (!descriptor_data)+ return;++ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);++ op_queue<operation> ops;+ for (int i = 0; i < max_ops; ++i)+ {+ while (reactor_op* op = descriptor_data->op_queue_[i].front())+ {+ op->ec_ = asio::error::operation_aborted;+ descriptor_data->op_queue_[i].pop();+ ops.push(op);+ }+ }++ descriptor_lock.unlock();++ scheduler_.post_deferred_completions(ops);+}++void kqueue_reactor::deregister_descriptor(socket_type descriptor,+ kqueue_reactor::per_descriptor_data& descriptor_data, bool closing)+{+ if (!descriptor_data)+ return;++ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);++ if (!descriptor_data->shutdown_)+ {+ if (closing)+ {+ // The descriptor will be automatically removed from the kqueue when it+ // is closed.+ }+ else+ {+ struct kevent events[2];+ ASIO_KQUEUE_EV_SET(&events[0], descriptor,+ EVFILT_READ, EV_DELETE, 0, 0, 0);+ ASIO_KQUEUE_EV_SET(&events[1], descriptor,+ EVFILT_WRITE, EV_DELETE, 0, 0, 0);+ ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0);+ }++ op_queue<operation> ops;+ for (int i = 0; i < max_ops; ++i)+ {+ while (reactor_op* op = descriptor_data->op_queue_[i].front())+ {+ op->ec_ = asio::error::operation_aborted;+ descriptor_data->op_queue_[i].pop();+ ops.push(op);+ }+ }++ descriptor_data->descriptor_ = -1;+ descriptor_data->shutdown_ = true;++ descriptor_lock.unlock();++ ASIO_HANDLER_REACTOR_DEREGISTRATION((+ context(), static_cast<uintmax_t>(descriptor),+ reinterpret_cast<uintmax_t>(descriptor_data)));++ scheduler_.post_deferred_completions(ops);++ // Leave descriptor_data set so that it will be freed by the subsequent+ // call to cleanup_descriptor_data.+ }+ else+ {+ // We are shutting down, so prevent cleanup_descriptor_data from freeing+ // the descriptor_data object and let the destructor free it instead.+ descriptor_data = 0;+ }+}++void kqueue_reactor::deregister_internal_descriptor(socket_type descriptor,+ kqueue_reactor::per_descriptor_data& descriptor_data)+{+ if (!descriptor_data)+ return;++ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);++ if (!descriptor_data->shutdown_)+ {+ struct kevent events[2];+ ASIO_KQUEUE_EV_SET(&events[0], descriptor,+ EVFILT_READ, EV_DELETE, 0, 0, 0);+ ASIO_KQUEUE_EV_SET(&events[1], descriptor,+ EVFILT_WRITE, EV_DELETE, 0, 0, 0);+ ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0);++ op_queue<operation> ops;+ for (int i = 0; i < max_ops; ++i)+ ops.push(descriptor_data->op_queue_[i]);++ descriptor_data->descriptor_ = -1;+ descriptor_data->shutdown_ = true;++ descriptor_lock.unlock();++ ASIO_HANDLER_REACTOR_DEREGISTRATION((+ context(), static_cast<uintmax_t>(descriptor),+ reinterpret_cast<uintmax_t>(descriptor_data)));++ // Leave descriptor_data set so that it will be freed by the subsequent+ // call to cleanup_descriptor_data.+ }+ else+ {+ // We are shutting down, so prevent cleanup_descriptor_data from freeing+ // the descriptor_data object and let the destructor free it instead.+ descriptor_data = 0;+ }+}++void kqueue_reactor::cleanup_descriptor_data(+ per_descriptor_data& descriptor_data)+{+ if (descriptor_data)+ {+ free_descriptor_state(descriptor_data);+ descriptor_data = 0;+ }+}++void kqueue_reactor::run(long usec, op_queue<operation>& ops)+{+ mutex::scoped_lock lock(mutex_);++ // Determine how long to block while waiting for events.+ timespec timeout_buf = { 0, 0 };+ timespec* timeout = usec ? get_timeout(usec, timeout_buf) : &timeout_buf;++ lock.unlock();++ // Block on the kqueue descriptor.+ struct kevent events[128];+ int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout);++#if defined(ASIO_ENABLE_HANDLER_TRACKING)+ // Trace the waiting events.+ for (int i = 0; i < num_events; ++i)+ {+ void* ptr = reinterpret_cast<void*>(events[i].udata);+ if (ptr != &interrupter_)+ {+ unsigned event_mask = 0;+ switch (events[i].filter)+ {+ case EVFILT_READ:+ event_mask |= ASIO_HANDLER_REACTOR_READ_EVENT;+ break;+ case EVFILT_WRITE:+ event_mask |= ASIO_HANDLER_REACTOR_WRITE_EVENT;+ break;+ }+ if ((events[i].flags & (EV_ERROR | EV_OOBAND)) != 0)+ event_mask |= ASIO_HANDLER_REACTOR_ERROR_EVENT;+ ASIO_HANDLER_REACTOR_EVENTS((context(),+ reinterpret_cast<uintmax_t>(ptr), event_mask));+ }+ }+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)++ // Dispatch the waiting events.+ for (int i = 0; i < num_events; ++i)+ {+ void* ptr = reinterpret_cast<void*>(events[i].udata);+ if (ptr == &interrupter_)+ {+ interrupter_.reset();+ }+ else+ {+ descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);++ if (events[i].filter == EVFILT_WRITE+ && descriptor_data->num_kevents_ == 2+ && descriptor_data->op_queue_[write_op].empty())+ {+ // Some descriptor types, like serial ports, don't seem to support+ // EV_CLEAR with EVFILT_WRITE. Since we have no pending write+ // operations we'll remove the EVFILT_WRITE registration here so that+ // we don't end up in a tight spin.+ struct kevent delete_events[1];+ ASIO_KQUEUE_EV_SET(&delete_events[0],+ descriptor_data->descriptor_, EVFILT_WRITE, EV_DELETE, 0, 0, 0);+ ::kevent(kqueue_fd_, delete_events, 1, 0, 0, 0);+ descriptor_data->num_kevents_ = 1;+ }++ // Exception operations must be processed first to ensure that any+ // out-of-band data is read before normal data.+#if defined(__NetBSD__)+ static const unsigned int filter[max_ops] =+#else+ static const int filter[max_ops] =+#endif+ { EVFILT_READ, EVFILT_WRITE, EVFILT_READ };+ for (int j = max_ops - 1; j >= 0; --j)+ {+ if (events[i].filter == filter[j])+ {+ if (j != except_op || events[i].flags & EV_OOBAND)+ {+ while (reactor_op* op = descriptor_data->op_queue_[j].front())+ {+ if (events[i].flags & EV_ERROR)+ {+ op->ec_ = asio::error_code(+ static_cast<int>(events[i].data),+ asio::error::get_system_category());+ descriptor_data->op_queue_[j].pop();+ ops.push(op);+ }+ if (op->perform())+ {+ descriptor_data->op_queue_[j].pop();+ ops.push(op);+ }+ else+ break;+ }+ }+ }+ }+ }+ }++ lock.lock();+ timer_queues_.get_ready_timers(ops);+}++void kqueue_reactor::interrupt()+{+ interrupter_.interrupt();+}++int kqueue_reactor::do_kqueue_create()+{+ int fd = ::kqueue();+ if (fd == -1)+ {+ asio::error_code ec(errno,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "kqueue");+ }+ return fd;+}++kqueue_reactor::descriptor_state* kqueue_reactor::allocate_descriptor_state()+{+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);+ return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING(+ REACTOR_IO, scheduler_.concurrency_hint()));+}++void kqueue_reactor::free_descriptor_state(kqueue_reactor::descriptor_state* s)+{+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);+ registered_descriptors_.free(s);+}++void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(mutex_);+ timer_queues_.insert(&queue);+}++void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(mutex_);+ timer_queues_.erase(&queue);+}++timespec* kqueue_reactor::get_timeout(long usec, timespec& ts)+{+ // By default we will wait no longer than 5 minutes. This will ensure that+ // any changes to the system clock are detected after no longer than this.+ const long max_usec = 5 * 60 * 1000 * 1000;+ usec = timer_queues_.wait_duration_usec(+ (usec < 0 || max_usec < usec) ? max_usec : usec);+ ts.tv_sec = usec / 1000000;+ ts.tv_nsec = (usec % 1000000) * 1000;+ return &ts;+}++} // namespace detail+} // namespace asio++#undef ASIO_KQUEUE_EV_SET++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_KQUEUE)++#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/null_event.ipp view
@@ -0,0 +1,74 @@+//+// detail/impl/null_event.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_NULL_EVENT_IPP+#define ASIO_DETAIL_IMPL_NULL_EVENT_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(ASIO_WINDOWS_RUNTIME)+# include <thread>+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# include "asio/detail/socket_types.hpp"+#else+# include <unistd.h>+# if defined(__hpux)+# include <sys/time.h>+# endif+# if !defined(__hpux) || defined(__SELECT)+# include <sys/select.h>+# endif+#endif++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++void null_event::do_wait()+{+#if defined(ASIO_WINDOWS_RUNTIME)+ std::this_thread::sleep_until((std::chrono::steady_clock::time_point::max)());+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ::Sleep(INFINITE);+#else+ ::pause();+#endif+}++void null_event::do_wait_for_usec(long usec)+{+#if defined(ASIO_WINDOWS_RUNTIME)+ std::this_thread::sleep_for(std::chrono::microseconds(usec));+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ::Sleep(usec / 1000);+#elif defined(__hpux) && defined(__SELECT)+ timespec ts;+ ts.tv_sec = usec / 1000000;+ ts.tv_nsec = (usec % 1000000) * 1000;+ ::pselect(0, 0, 0, 0, &ts, 0);+#else+ timeval tv;+ tv.tv_sec = usec / 1000000;+ tv.tv_usec = usec % 1000000;+ ::select(0, 0, 0, 0, &tv);+#endif+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_NULL_EVENT_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/pipe_select_interrupter.ipp view
@@ -0,0 +1,129 @@+//+// detail/impl/pipe_select_interrupter.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_PIPE_SELECT_INTERRUPTER_IPP+#define ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if !defined(ASIO_WINDOWS_RUNTIME)+#if !defined(ASIO_WINDOWS)+#if !defined(__CYGWIN__)+#if !defined(__SYMBIAN32__)+#if !defined(ASIO_HAS_EVENTFD)++#include <fcntl.h>+#include <sys/stat.h>+#include <sys/types.h>+#include <unistd.h>+#include "asio/detail/pipe_select_interrupter.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++pipe_select_interrupter::pipe_select_interrupter()+{+ open_descriptors();+}++void pipe_select_interrupter::open_descriptors()+{+ int pipe_fds[2];+ if (pipe(pipe_fds) == 0)+ {+ read_descriptor_ = pipe_fds[0];+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);+ write_descriptor_ = pipe_fds[1];+ ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);++#if defined(FD_CLOEXEC)+ ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);+ ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC);+#endif // defined(FD_CLOEXEC)+ }+ else+ {+ asio::error_code ec(errno,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "pipe_select_interrupter");+ }+}++pipe_select_interrupter::~pipe_select_interrupter()+{+ close_descriptors();+}++void pipe_select_interrupter::close_descriptors()+{+ if (read_descriptor_ != -1)+ ::close(read_descriptor_);+ if (write_descriptor_ != -1)+ ::close(write_descriptor_);+}++void pipe_select_interrupter::recreate()+{+ close_descriptors();++ write_descriptor_ = -1;+ read_descriptor_ = -1;++ open_descriptors();+}++void pipe_select_interrupter::interrupt()+{+ char byte = 0;+ signed_size_type result = ::write(write_descriptor_, &byte, 1);+ (void)result;+}++bool pipe_select_interrupter::reset()+{+ for (;;)+ {+ char data[1024];+ signed_size_type bytes_read = ::read(read_descriptor_, data, sizeof(data));+ if (bytes_read == sizeof(data))+ continue;+ if (bytes_read > 0)+ return true;+ if (bytes_read == 0)+ return false;+ if (errno == EINTR)+ continue;+ if (errno == EWOULDBLOCK || errno == EAGAIN)+ return true;+ return false;+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_HAS_EVENTFD)+#endif // !defined(__SYMBIAN32__)+#endif // !defined(__CYGWIN__)+#endif // !defined(ASIO_WINDOWS)+#endif // !defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/posix_event.ipp view
@@ -0,0 +1,59 @@+//+// detail/impl/posix_event.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_POSIX_EVENT_IPP+#define ASIO_DETAIL_IMPL_POSIX_EVENT_IPP++#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_PTHREADS)++#include "asio/detail/posix_event.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++posix_event::posix_event()+ : state_(0)+{+#if (defined(__MACH__) && defined(__APPLE__)) \+ || (defined(__ANDROID__) && (__ANDROID_API__ < 21))+ int error = ::pthread_cond_init(&cond_, 0);+#else // (defined(__MACH__) && defined(__APPLE__))+ // || (defined(__ANDROID__) && (__ANDROID_API__ < 21))+ ::pthread_condattr_t attr;+ ::pthread_condattr_init(&attr);+ int error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);+ if (error == 0)+ error = ::pthread_cond_init(&cond_, &attr);+#endif // (defined(__MACH__) && defined(__APPLE__))+ // || (defined(__ANDROID__) && (__ANDROID_API__ < 21))++ asio::error_code ec(error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "event");+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_PTHREADS)++#endif // ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/posix_mutex.ipp view
@@ -0,0 +1,46 @@+//+// detail/impl/posix_mutex.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_POSIX_MUTEX_IPP+#define ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP++#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_PTHREADS)++#include "asio/detail/posix_mutex.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++posix_mutex::posix_mutex()+{+ int error = ::pthread_mutex_init(&mutex_, 0);+ asio::error_code ec(error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "mutex");+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_PTHREADS)++#endif // ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/posix_thread.ipp view
@@ -0,0 +1,84 @@+//+// detail/impl/posix_thread.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_POSIX_THREAD_IPP+#define ASIO_DETAIL_IMPL_POSIX_THREAD_IPP++#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_PTHREADS)++#include "asio/detail/posix_thread.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++posix_thread::~posix_thread()+{+ if (!joined_)+ ::pthread_detach(thread_);+}++void posix_thread::join()+{+ if (!joined_)+ {+ ::pthread_join(thread_, 0);+ joined_ = true;+ }+}++std::size_t posix_thread::hardware_concurrency()+{+#if defined(_SC_NPROCESSORS_ONLN)+ long result = sysconf(_SC_NPROCESSORS_ONLN);+ if (result > 0)+ return result;+#endif // defined(_SC_NPROCESSORS_ONLN)+ return 0;+}++void posix_thread::start_thread(func_base* arg)+{+ int error = ::pthread_create(&thread_, 0,+ asio_detail_posix_thread_function, arg);+ if (error != 0)+ {+ delete arg;+ asio::error_code ec(error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "thread");+ }+}++void* asio_detail_posix_thread_function(void* arg)+{+ posix_thread::auto_func_base_ptr func = {+ static_cast<posix_thread::func_base*>(arg) };+ func.ptr->run();+ return 0;+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_PTHREADS)++#endif // ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/posix_tss_ptr.ipp view
@@ -0,0 +1,46 @@+//+// detail/impl/posix_tss_ptr.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_POSIX_TSS_PTR_IPP+#define ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP++#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_PTHREADS)++#include "asio/detail/posix_tss_ptr.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++void posix_tss_ptr_create(pthread_key_t& key)+{+ int error = ::pthread_key_create(&key, 0);+ asio::error_code ec(error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "tss");+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_PTHREADS)++#endif // ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_descriptor_service.ipp view
@@ -0,0 +1,223 @@+//+// detail/impl/reactive_descriptor_service.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP+#define ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)++#include "asio/error.hpp"+#include "asio/detail/reactive_descriptor_service.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++reactive_descriptor_service::reactive_descriptor_service(+ execution_context& context)+ : execution_context_service_base<reactive_descriptor_service>(context),+ reactor_(asio::use_service<reactor>(context))+{+ reactor_.init_task();+}++void reactive_descriptor_service::shutdown()+{+}++void reactive_descriptor_service::construct(+ reactive_descriptor_service::implementation_type& impl)+{+ impl.descriptor_ = -1;+ impl.state_ = 0;+}++void reactive_descriptor_service::move_construct(+ reactive_descriptor_service::implementation_type& impl,+ reactive_descriptor_service::implementation_type& other_impl)+ ASIO_NOEXCEPT+{+ impl.descriptor_ = other_impl.descriptor_;+ other_impl.descriptor_ = -1;++ impl.state_ = other_impl.state_;+ other_impl.state_ = 0;++ reactor_.move_descriptor(impl.descriptor_,+ impl.reactor_data_, other_impl.reactor_data_);+}++void reactive_descriptor_service::move_assign(+ reactive_descriptor_service::implementation_type& impl,+ reactive_descriptor_service& other_service,+ reactive_descriptor_service::implementation_type& other_impl)+{+ destroy(impl);++ impl.descriptor_ = other_impl.descriptor_;+ other_impl.descriptor_ = -1;++ impl.state_ = other_impl.state_;+ other_impl.state_ = 0;++ other_service.reactor_.move_descriptor(impl.descriptor_,+ impl.reactor_data_, other_impl.reactor_data_);+}++void reactive_descriptor_service::destroy(+ reactive_descriptor_service::implementation_type& impl)+{+ if (is_open(impl))+ {+ ASIO_HANDLER_OPERATION((reactor_.context(),+ "descriptor", &impl, impl.descriptor_, "close"));++ reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_,+ (impl.state_ & descriptor_ops::possible_dup) == 0);++ asio::error_code ignored_ec;+ descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec);++ reactor_.cleanup_descriptor_data(impl.reactor_data_);+ }+}++asio::error_code reactive_descriptor_service::assign(+ reactive_descriptor_service::implementation_type& impl,+ const native_handle_type& native_descriptor, asio::error_code& ec)+{+ if (is_open(impl))+ {+ ec = asio::error::already_open;+ return ec;+ }++ if (int err = reactor_.register_descriptor(+ native_descriptor, impl.reactor_data_))+ {+ ec = asio::error_code(err,+ asio::error::get_system_category());+ return ec;+ }++ impl.descriptor_ = native_descriptor;+ impl.state_ = descriptor_ops::possible_dup;+ ec = asio::error_code();+ return ec;+}++asio::error_code reactive_descriptor_service::close(+ reactive_descriptor_service::implementation_type& impl,+ asio::error_code& ec)+{+ if (is_open(impl))+ {+ ASIO_HANDLER_OPERATION((reactor_.context(),+ "descriptor", &impl, impl.descriptor_, "close"));++ reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_,+ (impl.state_ & descriptor_ops::possible_dup) == 0);++ descriptor_ops::close(impl.descriptor_, impl.state_, ec);++ reactor_.cleanup_descriptor_data(impl.reactor_data_);+ }+ else+ {+ ec = asio::error_code();+ }++ // The descriptor is closed by the OS even if close() returns an error.+ //+ // (Actually, POSIX says the state of the descriptor is unspecified. On+ // Linux the descriptor is apparently closed anyway; e.g. see+ // http://lkml.org/lkml/2005/9/10/129+ // We'll just have to assume that other OSes follow the same behaviour.)+ construct(impl);++ return ec;+}++reactive_descriptor_service::native_handle_type+reactive_descriptor_service::release(+ reactive_descriptor_service::implementation_type& impl)+{+ native_handle_type descriptor = impl.descriptor_;++ if (is_open(impl))+ {+ ASIO_HANDLER_OPERATION((reactor_.context(),+ "descriptor", &impl, impl.descriptor_, "release"));++ reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, false);+ reactor_.cleanup_descriptor_data(impl.reactor_data_);+ construct(impl);+ }++ return descriptor;+}++asio::error_code reactive_descriptor_service::cancel(+ reactive_descriptor_service::implementation_type& impl,+ asio::error_code& ec)+{+ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return ec;+ }++ ASIO_HANDLER_OPERATION((reactor_.context(),+ "descriptor", &impl, impl.descriptor_, "cancel"));++ reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);+ ec = asio::error_code();+ return ec;+}++void reactive_descriptor_service::start_op(+ reactive_descriptor_service::implementation_type& impl,+ int op_type, reactor_op* op, bool is_continuation,+ bool is_non_blocking, bool noop)+{+ if (!noop)+ {+ if ((impl.state_ & descriptor_ops::non_blocking) ||+ descriptor_ops::set_internal_non_blocking(+ impl.descriptor_, impl.state_, true, op->ec_))+ {+ reactor_.start_op(op_type, impl.descriptor_,+ impl.reactor_data_, op, is_continuation, is_non_blocking);+ return;+ }+ }++ reactor_.post_immediate_completion(op, is_continuation);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)++#endif // ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_serial_port_service.ipp view
@@ -0,0 +1,149 @@+//+// detail/impl/reactive_serial_port_service.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP+#define ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP++#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_SERIAL_PORT)+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++#include <cstring>+#include "asio/detail/reactive_serial_port_service.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++reactive_serial_port_service::reactive_serial_port_service(+ execution_context& context)+ : execution_context_service_base<reactive_serial_port_service>(context),+ descriptor_service_(context)+{+}++void reactive_serial_port_service::shutdown()+{+ descriptor_service_.shutdown();+}++asio::error_code reactive_serial_port_service::open(+ reactive_serial_port_service::implementation_type& impl,+ const std::string& device, asio::error_code& ec)+{+ if (is_open(impl))+ {+ ec = asio::error::already_open;+ return ec;+ }++ descriptor_ops::state_type state = 0;+ int fd = descriptor_ops::open(device.c_str(),+ O_RDWR | O_NONBLOCK | O_NOCTTY, ec);+ if (fd < 0)+ return ec;++ int s = descriptor_ops::fcntl(fd, F_GETFL, ec);+ if (s >= 0)+ s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec);+ if (s < 0)+ {+ asio::error_code ignored_ec;+ descriptor_ops::close(fd, state, ignored_ec);+ return ec;+ }++ // Set up default serial port options.+ termios ios;+ s = ::tcgetattr(fd, &ios);+ descriptor_ops::get_last_error(ec, s < 0);+ if (s >= 0)+ {+#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)+ ::cfmakeraw(&ios);+#else+ ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK+ | ISTRIP | INLCR | IGNCR | ICRNL | IXON);+ ios.c_oflag &= ~OPOST;+ ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);+ ios.c_cflag &= ~(CSIZE | PARENB);+ ios.c_cflag |= CS8;+#endif+ ios.c_iflag |= IGNPAR;+ ios.c_cflag |= CREAD | CLOCAL;+ s = ::tcsetattr(fd, TCSANOW, &ios);+ descriptor_ops::get_last_error(ec, s < 0);+ }+ if (s < 0)+ {+ asio::error_code ignored_ec;+ descriptor_ops::close(fd, state, ignored_ec);+ return ec;+ }++ // We're done. Take ownership of the serial port descriptor.+ if (descriptor_service_.assign(impl, fd, ec))+ {+ asio::error_code ignored_ec;+ descriptor_ops::close(fd, state, ignored_ec);+ }++ return ec;+}++asio::error_code reactive_serial_port_service::do_set_option(+ reactive_serial_port_service::implementation_type& impl,+ reactive_serial_port_service::store_function_type store,+ const void* option, asio::error_code& ec)+{+ termios ios;+ int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios);+ descriptor_ops::get_last_error(ec, s < 0);+ if (s < 0)+ return ec;++ if (store(option, ios, ec))+ return ec;++ s = ::tcsetattr(descriptor_service_.native_handle(impl), TCSANOW, &ios);+ descriptor_ops::get_last_error(ec, s < 0);+ return ec;+}++asio::error_code reactive_serial_port_service::do_get_option(+ const reactive_serial_port_service::implementation_type& impl,+ reactive_serial_port_service::load_function_type load,+ void* option, asio::error_code& ec) const+{+ termios ios;+ int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios);+ descriptor_ops::get_last_error(ec, s < 0);+ if (s < 0)+ return ec;++ return load(option, ios, ec);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)+#endif // defined(ASIO_HAS_SERIAL_PORT)++#endif // ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/reactive_socket_service_base.ipp view
@@ -0,0 +1,300 @@+//+// detail/reactive_socket_service_base.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP+#define ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP++#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_IOCP) \+ && !defined(ASIO_WINDOWS_RUNTIME)++#include "asio/detail/reactive_socket_service_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++reactive_socket_service_base::reactive_socket_service_base(+ execution_context& context)+ : reactor_(use_service<reactor>(context))+{+ reactor_.init_task();+}++void reactive_socket_service_base::base_shutdown()+{+}++void reactive_socket_service_base::construct(+ reactive_socket_service_base::base_implementation_type& impl)+{+ impl.socket_ = invalid_socket;+ impl.state_ = 0;+}++void reactive_socket_service_base::base_move_construct(+ reactive_socket_service_base::base_implementation_type& impl,+ reactive_socket_service_base::base_implementation_type& other_impl)+ ASIO_NOEXCEPT+{+ impl.socket_ = other_impl.socket_;+ other_impl.socket_ = invalid_socket;++ impl.state_ = other_impl.state_;+ other_impl.state_ = 0;++ reactor_.move_descriptor(impl.socket_,+ impl.reactor_data_, other_impl.reactor_data_);+}++void reactive_socket_service_base::base_move_assign(+ reactive_socket_service_base::base_implementation_type& impl,+ reactive_socket_service_base& other_service,+ reactive_socket_service_base::base_implementation_type& other_impl)+{+ destroy(impl);++ impl.socket_ = other_impl.socket_;+ other_impl.socket_ = invalid_socket;++ impl.state_ = other_impl.state_;+ other_impl.state_ = 0;++ other_service.reactor_.move_descriptor(impl.socket_,+ impl.reactor_data_, other_impl.reactor_data_);+}++void reactive_socket_service_base::destroy(+ reactive_socket_service_base::base_implementation_type& impl)+{+ if (impl.socket_ != invalid_socket)+ {+ ASIO_HANDLER_OPERATION((reactor_.context(),+ "socket", &impl, impl.socket_, "close"));++ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,+ (impl.state_ & socket_ops::possible_dup) == 0);++ asio::error_code ignored_ec;+ socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);++ reactor_.cleanup_descriptor_data(impl.reactor_data_);+ }+}++asio::error_code reactive_socket_service_base::close(+ reactive_socket_service_base::base_implementation_type& impl,+ asio::error_code& ec)+{+ if (is_open(impl))+ {+ ASIO_HANDLER_OPERATION((reactor_.context(),+ "socket", &impl, impl.socket_, "close"));++ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,+ (impl.state_ & socket_ops::possible_dup) == 0);++ socket_ops::close(impl.socket_, impl.state_, false, ec);++ reactor_.cleanup_descriptor_data(impl.reactor_data_);+ }+ else+ {+ ec = asio::error_code();+ }++ // The descriptor is closed by the OS even if close() returns an error.+ //+ // (Actually, POSIX says the state of the descriptor is unspecified. On+ // Linux the descriptor is apparently closed anyway; e.g. see+ // http://lkml.org/lkml/2005/9/10/129+ // We'll just have to assume that other OSes follow the same behaviour. The+ // known exception is when Windows's closesocket() function fails with+ // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close().+ construct(impl);++ return ec;+}++socket_type reactive_socket_service_base::release(+ reactive_socket_service_base::base_implementation_type& impl,+ asio::error_code& ec)+{+ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return invalid_socket;+ }++ ASIO_HANDLER_OPERATION((reactor_.context(),+ "socket", &impl, impl.socket_, "release"));++ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false);+ reactor_.cleanup_descriptor_data(impl.reactor_data_);+ socket_type sock = impl.socket_;+ construct(impl);+ ec = asio::error_code();+ return sock;+}++asio::error_code reactive_socket_service_base::cancel(+ reactive_socket_service_base::base_implementation_type& impl,+ asio::error_code& ec)+{+ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return ec;+ }++ ASIO_HANDLER_OPERATION((reactor_.context(),+ "socket", &impl, impl.socket_, "cancel"));++ reactor_.cancel_ops(impl.socket_, impl.reactor_data_);+ ec = asio::error_code();+ return ec;+}++asio::error_code reactive_socket_service_base::do_open(+ reactive_socket_service_base::base_implementation_type& impl,+ int af, int type, int protocol, asio::error_code& ec)+{+ if (is_open(impl))+ {+ ec = asio::error::already_open;+ return ec;+ }++ socket_holder sock(socket_ops::socket(af, type, protocol, ec));+ if (sock.get() == invalid_socket)+ return ec;++ if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))+ {+ ec = asio::error_code(err,+ asio::error::get_system_category());+ return ec;+ }++ impl.socket_ = sock.release();+ switch (type)+ {+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;+ default: impl.state_ = 0; break;+ }+ ec = asio::error_code();+ return ec;+}++asio::error_code reactive_socket_service_base::do_assign(+ reactive_socket_service_base::base_implementation_type& impl, int type,+ const reactive_socket_service_base::native_handle_type& native_socket,+ asio::error_code& ec)+{+ if (is_open(impl))+ {+ ec = asio::error::already_open;+ return ec;+ }++ if (int err = reactor_.register_descriptor(+ native_socket, impl.reactor_data_))+ {+ ec = asio::error_code(err,+ asio::error::get_system_category());+ return ec;+ }++ impl.socket_ = native_socket;+ switch (type)+ {+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;+ default: impl.state_ = 0; break;+ }+ impl.state_ |= socket_ops::possible_dup;+ ec = asio::error_code();+ return ec;+}++void reactive_socket_service_base::start_op(+ reactive_socket_service_base::base_implementation_type& impl,+ int op_type, reactor_op* op, bool is_continuation,+ bool is_non_blocking, bool noop)+{+ if (!noop)+ {+ if ((impl.state_ & socket_ops::non_blocking)+ || socket_ops::set_internal_non_blocking(+ impl.socket_, impl.state_, true, op->ec_))+ {+ reactor_.start_op(op_type, impl.socket_,+ impl.reactor_data_, op, is_continuation, is_non_blocking);+ return;+ }+ }++ reactor_.post_immediate_completion(op, is_continuation);+}++void reactive_socket_service_base::start_accept_op(+ reactive_socket_service_base::base_implementation_type& impl,+ reactor_op* op, bool is_continuation, bool peer_is_open)+{+ if (!peer_is_open)+ start_op(impl, reactor::read_op, op, is_continuation, true, false);+ else+ {+ op->ec_ = asio::error::already_open;+ reactor_.post_immediate_completion(op, is_continuation);+ }+}++void reactive_socket_service_base::start_connect_op(+ reactive_socket_service_base::base_implementation_type& impl,+ reactor_op* op, bool is_continuation,+ const socket_addr_type* addr, size_t addrlen)+{+ if ((impl.state_ & socket_ops::non_blocking)+ || socket_ops::set_internal_non_blocking(+ impl.socket_, impl.state_, true, op->ec_))+ {+ if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)+ {+ if (op->ec_ == asio::error::in_progress+ || op->ec_ == asio::error::would_block)+ {+ op->ec_ = asio::error_code();+ reactor_.start_op(reactor::connect_op, impl.socket_,+ impl.reactor_data_, op, is_continuation, false);+ return;+ }+ }+ }++ reactor_.post_immediate_completion(op, is_continuation);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_HAS_IOCP)+ // && !defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/resolver_service_base.ipp view
@@ -0,0 +1,158 @@+//+// detail/impl/resolver_service_base.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_RESOLVER_SERVICE_BASE_IPP+#define ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/detail/resolver_service_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class resolver_service_base::work_scheduler_runner+{+public:+ work_scheduler_runner(scheduler_impl& work_scheduler)+ : work_scheduler_(work_scheduler)+ {+ }++ void operator()()+ {+ asio::error_code ec;+ work_scheduler_.run(ec);+ }++private:+ scheduler_impl& work_scheduler_;+};++resolver_service_base::resolver_service_base(execution_context& context)+ : scheduler_(asio::use_service<scheduler_impl>(context)),+ work_scheduler_(new scheduler_impl(context, -1, false)),+ work_thread_(0)+{+ work_scheduler_->work_started();+}++resolver_service_base::~resolver_service_base()+{+ base_shutdown();+}++void resolver_service_base::base_shutdown()+{+ if (work_scheduler_.get())+ {+ work_scheduler_->work_finished();+ work_scheduler_->stop();+ if (work_thread_.get())+ {+ work_thread_->join();+ work_thread_.reset();+ }+ work_scheduler_.reset();+ }+}++void resolver_service_base::base_notify_fork(+ execution_context::fork_event fork_ev)+{+ if (work_thread_.get())+ {+ if (fork_ev == execution_context::fork_prepare)+ {+ work_scheduler_->stop();+ work_thread_->join();+ work_thread_.reset();+ }+ }+ else if (fork_ev != execution_context::fork_prepare)+ {+ work_scheduler_->restart();+ }+}++void resolver_service_base::construct(+ resolver_service_base::implementation_type& impl)+{+ impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());+}++void resolver_service_base::destroy(+ resolver_service_base::implementation_type& impl)+{+ ASIO_HANDLER_OPERATION((scheduler_.context(),+ "resolver", &impl, 0, "cancel"));++ impl.reset();+}++void resolver_service_base::move_construct(implementation_type& impl,+ implementation_type& other_impl)+{+ impl = ASIO_MOVE_CAST(implementation_type)(other_impl);+}++void resolver_service_base::move_assign(implementation_type& impl,+ resolver_service_base&, implementation_type& other_impl)+{+ destroy(impl);+ impl = ASIO_MOVE_CAST(implementation_type)(other_impl);+}++void resolver_service_base::cancel(+ resolver_service_base::implementation_type& impl)+{+ ASIO_HANDLER_OPERATION((scheduler_.context(),+ "resolver", &impl, 0, "cancel"));++ impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());+}++void resolver_service_base::start_resolve_op(resolve_op* op)+{+ if (ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,+ scheduler_.concurrency_hint()))+ {+ start_work_thread();+ scheduler_.work_started();+ work_scheduler_->post_immediate_completion(op, false);+ }+ else+ {+ op->ec_ = asio::error::operation_not_supported;+ scheduler_.post_immediate_completion(op, false);+ }+}++void resolver_service_base::start_work_thread()+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ if (!work_thread_.get())+ {+ work_thread_.reset(new asio::detail::thread(+ work_scheduler_runner(*work_scheduler_)));+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/scheduler.ipp view
@@ -0,0 +1,654 @@+//+// detail/impl/scheduler.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SCHEDULER_IPP+#define ASIO_DETAIL_IMPL_SCHEDULER_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include "asio/detail/concurrency_hint.hpp"+#include "asio/detail/event.hpp"+#include "asio/detail/limits.hpp"+#include "asio/detail/reactor.hpp"+#include "asio/detail/scheduler.hpp"+#include "asio/detail/scheduler_thread_info.hpp"+#include "asio/detail/signal_blocker.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class scheduler::thread_function+{+public:+ explicit thread_function(scheduler* s)+ : this_(s)+ {+ }++ void operator()()+ {+ asio::error_code ec;+ this_->run(ec);+ }++private:+ scheduler* this_;+};++struct scheduler::task_cleanup+{+ ~task_cleanup()+ {+ if (this_thread_->private_outstanding_work > 0)+ {+ asio::detail::increment(+ scheduler_->outstanding_work_,+ this_thread_->private_outstanding_work);+ }+ this_thread_->private_outstanding_work = 0;++ // Enqueue the completed operations and reinsert the task at the end of+ // the operation queue.+ lock_->lock();+ scheduler_->task_interrupted_ = true;+ scheduler_->op_queue_.push(this_thread_->private_op_queue);+ scheduler_->op_queue_.push(&scheduler_->task_operation_);+ }++ scheduler* scheduler_;+ mutex::scoped_lock* lock_;+ thread_info* this_thread_;+};++struct scheduler::work_cleanup+{+ ~work_cleanup()+ {+ if (this_thread_->private_outstanding_work > 1)+ {+ asio::detail::increment(+ scheduler_->outstanding_work_,+ this_thread_->private_outstanding_work - 1);+ }+ else if (this_thread_->private_outstanding_work < 1)+ {+ scheduler_->work_finished();+ }+ this_thread_->private_outstanding_work = 0;++#if defined(ASIO_HAS_THREADS)+ if (!this_thread_->private_op_queue.empty())+ {+ lock_->lock();+ scheduler_->op_queue_.push(this_thread_->private_op_queue);+ }+#endif // defined(ASIO_HAS_THREADS)+ }++ scheduler* scheduler_;+ mutex::scoped_lock* lock_;+ thread_info* this_thread_;+};++scheduler::scheduler(asio::execution_context& ctx,+ int concurrency_hint, bool own_thread)+ : asio::detail::execution_context_service_base<scheduler>(ctx),+ one_thread_(concurrency_hint == 1+ || !ASIO_CONCURRENCY_HINT_IS_LOCKING(+ SCHEDULER, concurrency_hint)+ || !ASIO_CONCURRENCY_HINT_IS_LOCKING(+ REACTOR_IO, concurrency_hint)),+ mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(+ SCHEDULER, concurrency_hint)),+ task_(0),+ task_interrupted_(true),+ outstanding_work_(0),+ stopped_(false),+ shutdown_(false),+ concurrency_hint_(concurrency_hint),+ thread_(0)+{+ ASIO_HANDLER_TRACKING_INIT;++ if (own_thread)+ {+ ++outstanding_work_;+ asio::detail::signal_blocker sb;+ thread_ = new asio::detail::thread(thread_function(this));+ }+}++scheduler::~scheduler()+{+ if (thread_)+ {+ mutex::scoped_lock lock(mutex_);+ shutdown_ = true;+ stop_all_threads(lock);+ lock.unlock();+ thread_->join();+ delete thread_;+ }+}++void scheduler::shutdown()+{+ mutex::scoped_lock lock(mutex_);+ shutdown_ = true;+ if (thread_)+ stop_all_threads(lock);+ lock.unlock();++ // Join thread to ensure task operation is returned to queue.+ if (thread_)+ {+ thread_->join();+ delete thread_;+ thread_ = 0;+ }++ // Destroy handler objects.+ while (!op_queue_.empty())+ {+ operation* o = op_queue_.front();+ op_queue_.pop();+ if (o != &task_operation_)+ o->destroy();+ }++ // Reset to initial state.+ task_ = 0;+}++void scheduler::init_task()+{+ mutex::scoped_lock lock(mutex_);+ if (!shutdown_ && !task_)+ {+ task_ = &use_service<reactor>(this->context());+ op_queue_.push(&task_operation_);+ wake_one_thread_and_unlock(lock);+ }+}++std::size_t scheduler::run(asio::error_code& ec)+{+ ec = asio::error_code();+ if (outstanding_work_ == 0)+ {+ stop();+ return 0;+ }++ thread_info this_thread;+ this_thread.private_outstanding_work = 0;+ thread_call_stack::context ctx(this, this_thread);++ mutex::scoped_lock lock(mutex_);++ std::size_t n = 0;+ for (; do_run_one(lock, this_thread, ec); lock.lock())+ if (n != (std::numeric_limits<std::size_t>::max)())+ ++n;+ return n;+}++std::size_t scheduler::run_one(asio::error_code& ec)+{+ ec = asio::error_code();+ if (outstanding_work_ == 0)+ {+ stop();+ return 0;+ }++ thread_info this_thread;+ this_thread.private_outstanding_work = 0;+ thread_call_stack::context ctx(this, this_thread);++ mutex::scoped_lock lock(mutex_);++ return do_run_one(lock, this_thread, ec);+}++std::size_t scheduler::wait_one(long usec, asio::error_code& ec)+{+ ec = asio::error_code();+ if (outstanding_work_ == 0)+ {+ stop();+ return 0;+ }++ thread_info this_thread;+ this_thread.private_outstanding_work = 0;+ thread_call_stack::context ctx(this, this_thread);++ mutex::scoped_lock lock(mutex_);++ return do_wait_one(lock, this_thread, usec, ec);+}++std::size_t scheduler::poll(asio::error_code& ec)+{+ ec = asio::error_code();+ if (outstanding_work_ == 0)+ {+ stop();+ return 0;+ }++ thread_info this_thread;+ this_thread.private_outstanding_work = 0;+ thread_call_stack::context ctx(this, this_thread);++ mutex::scoped_lock lock(mutex_);++#if defined(ASIO_HAS_THREADS)+ // We want to support nested calls to poll() and poll_one(), so any handlers+ // that are already on a thread-private queue need to be put on to the main+ // queue now.+ if (one_thread_)+ if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key()))+ op_queue_.push(outer_info->private_op_queue);+#endif // defined(ASIO_HAS_THREADS)++ std::size_t n = 0;+ for (; do_poll_one(lock, this_thread, ec); lock.lock())+ if (n != (std::numeric_limits<std::size_t>::max)())+ ++n;+ return n;+}++std::size_t scheduler::poll_one(asio::error_code& ec)+{+ ec = asio::error_code();+ if (outstanding_work_ == 0)+ {+ stop();+ return 0;+ }++ thread_info this_thread;+ this_thread.private_outstanding_work = 0;+ thread_call_stack::context ctx(this, this_thread);++ mutex::scoped_lock lock(mutex_);++#if defined(ASIO_HAS_THREADS)+ // We want to support nested calls to poll() and poll_one(), so any handlers+ // that are already on a thread-private queue need to be put on to the main+ // queue now.+ if (one_thread_)+ if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key()))+ op_queue_.push(outer_info->private_op_queue);+#endif // defined(ASIO_HAS_THREADS)++ return do_poll_one(lock, this_thread, ec);+}++void scheduler::stop()+{+ mutex::scoped_lock lock(mutex_);+ stop_all_threads(lock);+}++bool scheduler::stopped() const+{+ mutex::scoped_lock lock(mutex_);+ return stopped_;+}++void scheduler::restart()+{+ mutex::scoped_lock lock(mutex_);+ stopped_ = false;+}++void scheduler::compensating_work_started()+{+ thread_info_base* this_thread = thread_call_stack::contains(this);+ ++static_cast<thread_info*>(this_thread)->private_outstanding_work;+}++void scheduler::capture_current_exception()+{+ if (thread_info_base* this_thread = thread_call_stack::contains(this))+ this_thread->capture_current_exception();+}++void scheduler::post_immediate_completion(+ scheduler::operation* op, bool is_continuation)+{+#if defined(ASIO_HAS_THREADS)+ if (one_thread_ || is_continuation)+ {+ if (thread_info_base* this_thread = thread_call_stack::contains(this))+ {+ ++static_cast<thread_info*>(this_thread)->private_outstanding_work;+ static_cast<thread_info*>(this_thread)->private_op_queue.push(op);+ return;+ }+ }+#else // defined(ASIO_HAS_THREADS)+ (void)is_continuation;+#endif // defined(ASIO_HAS_THREADS)++ work_started();+ mutex::scoped_lock lock(mutex_);+ op_queue_.push(op);+ wake_one_thread_and_unlock(lock);+}++void scheduler::post_immediate_completions(std::size_t n,+ op_queue<scheduler::operation>& ops, bool is_continuation)+{+#if defined(ASIO_HAS_THREADS)+ if (one_thread_ || is_continuation)+ {+ if (thread_info_base* this_thread = thread_call_stack::contains(this))+ {+ static_cast<thread_info*>(this_thread)->private_outstanding_work+ += static_cast<long>(n);+ static_cast<thread_info*>(this_thread)->private_op_queue.push(ops);+ return;+ }+ }+#else // defined(ASIO_HAS_THREADS)+ (void)is_continuation;+#endif // defined(ASIO_HAS_THREADS)++ increment(outstanding_work_, static_cast<long>(n));+ mutex::scoped_lock lock(mutex_);+ op_queue_.push(ops);+ wake_one_thread_and_unlock(lock);+}++void scheduler::post_deferred_completion(scheduler::operation* op)+{+#if defined(ASIO_HAS_THREADS)+ if (one_thread_)+ {+ if (thread_info_base* this_thread = thread_call_stack::contains(this))+ {+ static_cast<thread_info*>(this_thread)->private_op_queue.push(op);+ return;+ }+ }+#endif // defined(ASIO_HAS_THREADS)++ mutex::scoped_lock lock(mutex_);+ op_queue_.push(op);+ wake_one_thread_and_unlock(lock);+}++void scheduler::post_deferred_completions(+ op_queue<scheduler::operation>& ops)+{+ if (!ops.empty())+ {+#if defined(ASIO_HAS_THREADS)+ if (one_thread_)+ {+ if (thread_info_base* this_thread = thread_call_stack::contains(this))+ {+ static_cast<thread_info*>(this_thread)->private_op_queue.push(ops);+ return;+ }+ }+#endif // defined(ASIO_HAS_THREADS)++ mutex::scoped_lock lock(mutex_);+ op_queue_.push(ops);+ wake_one_thread_and_unlock(lock);+ }+}++void scheduler::do_dispatch(+ scheduler::operation* op)+{+ work_started();+ mutex::scoped_lock lock(mutex_);+ op_queue_.push(op);+ wake_one_thread_and_unlock(lock);+}++void scheduler::abandon_operations(+ op_queue<scheduler::operation>& ops)+{+ op_queue<scheduler::operation> ops2;+ ops2.push(ops);+}++std::size_t scheduler::do_run_one(mutex::scoped_lock& lock,+ scheduler::thread_info& this_thread,+ const asio::error_code& ec)+{+ while (!stopped_)+ {+ if (!op_queue_.empty())+ {+ // Prepare to execute first handler from queue.+ operation* o = op_queue_.front();+ op_queue_.pop();+ bool more_handlers = (!op_queue_.empty());++ if (o == &task_operation_)+ {+ task_interrupted_ = more_handlers;++ if (more_handlers && !one_thread_)+ wakeup_event_.unlock_and_signal_one(lock);+ else+ lock.unlock();++ task_cleanup on_exit = { this, &lock, &this_thread };+ (void)on_exit;++ // Run the task. May throw an exception. Only block if the operation+ // queue is empty and we're not polling, otherwise we want to return+ // as soon as possible.+ task_->run(more_handlers ? 0 : -1, this_thread.private_op_queue);+ }+ else+ {+ std::size_t task_result = o->task_result_;++ if (more_handlers && !one_thread_)+ wake_one_thread_and_unlock(lock);+ else+ lock.unlock();++ // Ensure the count of outstanding work is decremented on block exit.+ work_cleanup on_exit = { this, &lock, &this_thread };+ (void)on_exit;++ // Complete the operation. May throw an exception. Deletes the object.+ o->complete(this, ec, task_result);+ this_thread.rethrow_pending_exception();++ return 1;+ }+ }+ else+ {+ wakeup_event_.clear(lock);+ wakeup_event_.wait(lock);+ }+ }++ return 0;+}++std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock,+ scheduler::thread_info& this_thread, long usec,+ const asio::error_code& ec)+{+ if (stopped_)+ return 0;++ operation* o = op_queue_.front();+ if (o == 0)+ {+ wakeup_event_.clear(lock);+ wakeup_event_.wait_for_usec(lock, usec);+ usec = 0; // Wait at most once.+ o = op_queue_.front();+ }++ if (o == &task_operation_)+ {+ op_queue_.pop();+ bool more_handlers = (!op_queue_.empty());++ task_interrupted_ = more_handlers;++ if (more_handlers && !one_thread_)+ wakeup_event_.unlock_and_signal_one(lock);+ else+ lock.unlock();++ {+ task_cleanup on_exit = { this, &lock, &this_thread };+ (void)on_exit;++ // Run the task. May throw an exception. Only block if the operation+ // queue is empty and we're not polling, otherwise we want to return+ // as soon as possible.+ task_->run(more_handlers ? 0 : usec, this_thread.private_op_queue);+ }++ o = op_queue_.front();+ if (o == &task_operation_)+ {+ if (!one_thread_)+ wakeup_event_.maybe_unlock_and_signal_one(lock);+ return 0;+ }+ }++ if (o == 0)+ return 0;++ op_queue_.pop();+ bool more_handlers = (!op_queue_.empty());++ std::size_t task_result = o->task_result_;++ if (more_handlers && !one_thread_)+ wake_one_thread_and_unlock(lock);+ else+ lock.unlock();++ // Ensure the count of outstanding work is decremented on block exit.+ work_cleanup on_exit = { this, &lock, &this_thread };+ (void)on_exit;++ // Complete the operation. May throw an exception. Deletes the object.+ o->complete(this, ec, task_result);+ this_thread.rethrow_pending_exception();++ return 1;+}++std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock,+ scheduler::thread_info& this_thread,+ const asio::error_code& ec)+{+ if (stopped_)+ return 0;++ operation* o = op_queue_.front();+ if (o == &task_operation_)+ {+ op_queue_.pop();+ lock.unlock();++ {+ task_cleanup c = { this, &lock, &this_thread };+ (void)c;++ // Run the task. May throw an exception. Only block if the operation+ // queue is empty and we're not polling, otherwise we want to return+ // as soon as possible.+ task_->run(0, this_thread.private_op_queue);+ }++ o = op_queue_.front();+ if (o == &task_operation_)+ {+ wakeup_event_.maybe_unlock_and_signal_one(lock);+ return 0;+ }+ }++ if (o == 0)+ return 0;++ op_queue_.pop();+ bool more_handlers = (!op_queue_.empty());++ std::size_t task_result = o->task_result_;++ if (more_handlers && !one_thread_)+ wake_one_thread_and_unlock(lock);+ else+ lock.unlock();++ // Ensure the count of outstanding work is decremented on block exit.+ work_cleanup on_exit = { this, &lock, &this_thread };+ (void)on_exit;++ // Complete the operation. May throw an exception. Deletes the object.+ o->complete(this, ec, task_result);+ this_thread.rethrow_pending_exception();++ return 1;+}++void scheduler::stop_all_threads(+ mutex::scoped_lock& lock)+{+ stopped_ = true;+ wakeup_event_.signal_all(lock);++ if (!task_interrupted_ && task_)+ {+ task_interrupted_ = true;+ task_->interrupt();+ }+}++void scheduler::wake_one_thread_and_unlock(+ mutex::scoped_lock& lock)+{+ if (!wakeup_event_.maybe_unlock_and_signal_one(lock))+ {+ if (!task_interrupted_ && task_)+ {+ task_interrupted_ = true;+ task_->interrupt();+ }+ lock.unlock();+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_SCHEDULER_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/select_reactor.hpp view
@@ -0,0 +1,100 @@+//+// detail/impl/select_reactor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SELECT_REACTOR_HPP+#define ASIO_DETAIL_IMPL_SELECT_REACTOR_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_IOCP) \+ || (!defined(ASIO_HAS_DEV_POLL) \+ && !defined(ASIO_HAS_EPOLL) \+ && !defined(ASIO_HAS_KQUEUE) \+ && !defined(ASIO_WINDOWS_RUNTIME))++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Time_Traits>+void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)+{+ do_add_timer_queue(queue);+}++// Remove a timer queue from the reactor.+template <typename Time_Traits>+void select_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)+{+ do_remove_timer_queue(queue);+}++template <typename Time_Traits>+void select_reactor::schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ if (shutdown_)+ {+ scheduler_.post_immediate_completion(op, false);+ return;+ }++ bool earliest = queue.enqueue_timer(time, timer, op);+ scheduler_.work_started();+ if (earliest)+ interrupter_.interrupt();+}++template <typename Time_Traits>+std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled)+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ op_queue<operation> ops;+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);+ lock.unlock();+ scheduler_.post_deferred_completions(ops);+ return n;+}++template <typename Time_Traits>+void select_reactor::move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& target,+ typename timer_queue<Time_Traits>::per_timer_data& source)+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ op_queue<operation> ops;+ queue.cancel_timer(target, ops);+ queue.move_timer(target, source);+ lock.unlock();+ scheduler_.post_deferred_completions(ops);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)+ // || (!defined(ASIO_HAS_DEV_POLL)+ // && !defined(ASIO_HAS_EPOLL)+ // && !defined(ASIO_HAS_KQUEUE)+ // && !defined(ASIO_WINDOWS_RUNTIME))++#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/select_reactor.ipp view
@@ -0,0 +1,338 @@+//+// detail/impl/select_reactor.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SELECT_REACTOR_IPP+#define ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP++#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_IOCP) \+ || (!defined(ASIO_HAS_DEV_POLL) \+ && !defined(ASIO_HAS_EPOLL) \+ && !defined(ASIO_HAS_KQUEUE) \+ && !defined(ASIO_WINDOWS_RUNTIME))++#include "asio/detail/fd_set_adapter.hpp"+#include "asio/detail/select_reactor.hpp"+#include "asio/detail/signal_blocker.hpp"+#include "asio/detail/socket_ops.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++#if defined(ASIO_HAS_IOCP)+class select_reactor::thread_function+{+public:+ explicit thread_function(select_reactor* r)+ : this_(r)+ {+ }++ void operator()()+ {+ this_->run_thread();+ }++private:+ select_reactor* this_;+};+#endif // defined(ASIO_HAS_IOCP)++select_reactor::select_reactor(asio::execution_context& ctx)+ : execution_context_service_base<select_reactor>(ctx),+ scheduler_(use_service<scheduler_type>(ctx)),+ mutex_(),+ interrupter_(),+#if defined(ASIO_HAS_IOCP)+ stop_thread_(false),+ thread_(0),+#endif // defined(ASIO_HAS_IOCP)+ shutdown_(false)+{+#if defined(ASIO_HAS_IOCP)+ asio::detail::signal_blocker sb;+ thread_ = new asio::detail::thread(thread_function(this));+#endif // defined(ASIO_HAS_IOCP)+}++select_reactor::~select_reactor()+{+ shutdown();+}++void select_reactor::shutdown()+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ shutdown_ = true;+#if defined(ASIO_HAS_IOCP)+ stop_thread_ = true;+ if (thread_)+ interrupter_.interrupt();+#endif // defined(ASIO_HAS_IOCP)+ lock.unlock();++#if defined(ASIO_HAS_IOCP)+ if (thread_)+ {+ thread_->join();+ delete thread_;+ thread_ = 0;+ }+#endif // defined(ASIO_HAS_IOCP)++ op_queue<operation> ops;++ for (int i = 0; i < max_ops; ++i)+ op_queue_[i].get_all_operations(ops);++ timer_queues_.get_all_timers(ops);++ scheduler_.abandon_operations(ops);+}++void select_reactor::notify_fork(+ asio::execution_context::fork_event fork_ev)+{+ if (fork_ev == asio::execution_context::fork_child)+ interrupter_.recreate();+}++void select_reactor::init_task()+{+ scheduler_.init_task();+}++int select_reactor::register_descriptor(socket_type,+ select_reactor::per_descriptor_data&)+{+ return 0;+}++int select_reactor::register_internal_descriptor(+ int op_type, socket_type descriptor,+ select_reactor::per_descriptor_data&, reactor_op* op)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ op_queue_[op_type].enqueue_operation(descriptor, op);+ interrupter_.interrupt();++ return 0;+}++void select_reactor::move_descriptor(socket_type,+ select_reactor::per_descriptor_data&,+ select_reactor::per_descriptor_data&)+{+}++void select_reactor::start_op(int op_type, socket_type descriptor,+ select_reactor::per_descriptor_data&, reactor_op* op,+ bool is_continuation, bool)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ if (shutdown_)+ {+ post_immediate_completion(op, is_continuation);+ return;+ }++ bool first = op_queue_[op_type].enqueue_operation(descriptor, op);+ scheduler_.work_started();+ if (first)+ interrupter_.interrupt();+}++void select_reactor::cancel_ops(socket_type descriptor,+ select_reactor::per_descriptor_data&)+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);+}++void select_reactor::deregister_descriptor(socket_type descriptor,+ select_reactor::per_descriptor_data&, bool)+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);+}++void select_reactor::deregister_internal_descriptor(+ socket_type descriptor, select_reactor::per_descriptor_data&)+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ op_queue<operation> ops;+ for (int i = 0; i < max_ops; ++i)+ op_queue_[i].cancel_operations(descriptor, ops);+}++void select_reactor::cleanup_descriptor_data(+ select_reactor::per_descriptor_data&)+{+}++void select_reactor::run(long usec, op_queue<operation>& ops)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++#if defined(ASIO_HAS_IOCP)+ // Check if the thread is supposed to stop.+ if (stop_thread_)+ return;+#endif // defined(ASIO_HAS_IOCP)++ // Set up the descriptor sets.+ for (int i = 0; i < max_select_ops; ++i)+ fd_sets_[i].reset();+ fd_sets_[read_op].set(interrupter_.read_descriptor());+ socket_type max_fd = 0;+ bool have_work_to_do = !timer_queues_.all_empty();+ for (int i = 0; i < max_select_ops; ++i)+ {+ have_work_to_do = have_work_to_do || !op_queue_[i].empty();+ fd_sets_[i].set(op_queue_[i], ops);+ if (fd_sets_[i].max_descriptor() > max_fd)+ max_fd = fd_sets_[i].max_descriptor();+ }++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ // Connection operations on Windows use both except and write fd_sets.+ have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty();+ fd_sets_[write_op].set(op_queue_[connect_op], ops);+ if (fd_sets_[write_op].max_descriptor() > max_fd)+ max_fd = fd_sets_[write_op].max_descriptor();+ fd_sets_[except_op].set(op_queue_[connect_op], ops);+ if (fd_sets_[except_op].max_descriptor() > max_fd)+ max_fd = fd_sets_[except_op].max_descriptor();+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++ // We can return immediately if there's no work to do and the reactor is+ // not supposed to block.+ if (!usec && !have_work_to_do)+ return;++ // Determine how long to block while waiting for events.+ timeval tv_buf = { 0, 0 };+ timeval* tv = usec ? get_timeout(usec, tv_buf) : &tv_buf;++ lock.unlock();++ // Block on the select call until descriptors become ready.+ asio::error_code ec;+ int retval = socket_ops::select(static_cast<int>(max_fd + 1),+ fd_sets_[read_op], fd_sets_[write_op], fd_sets_[except_op], tv, ec);++ // Reset the interrupter.+ if (retval > 0 && fd_sets_[read_op].is_set(interrupter_.read_descriptor()))+ {+ if (!interrupter_.reset())+ {+ lock.lock();+ interrupter_.recreate();+ }+ --retval;+ }++ lock.lock();++ // Dispatch all ready operations.+ if (retval > 0)+ {+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ // Connection operations on Windows use both except and write fd_sets.+ fd_sets_[except_op].perform(op_queue_[connect_op], ops);+ fd_sets_[write_op].perform(op_queue_[connect_op], ops);+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++ // Exception operations must be processed first to ensure that any+ // out-of-band data is read before normal data.+ for (int i = max_select_ops - 1; i >= 0; --i)+ fd_sets_[i].perform(op_queue_[i], ops);+ }+ timer_queues_.get_ready_timers(ops);+}++void select_reactor::interrupt()+{+ interrupter_.interrupt();+}++#if defined(ASIO_HAS_IOCP)+void select_reactor::run_thread()+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ while (!stop_thread_)+ {+ lock.unlock();+ op_queue<operation> ops;+ run(true, ops);+ scheduler_.post_deferred_completions(ops);+ lock.lock();+ }+}+#endif // defined(ASIO_HAS_IOCP)++void select_reactor::do_add_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(mutex_);+ timer_queues_.insert(&queue);+}++void select_reactor::do_remove_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(mutex_);+ timer_queues_.erase(&queue);+}++timeval* select_reactor::get_timeout(long usec, timeval& tv)+{+ // By default we will wait no longer than 5 minutes. This will ensure that+ // any changes to the system clock are detected after no longer than this.+ const long max_usec = 5 * 60 * 1000 * 1000;+ usec = timer_queues_.wait_duration_usec(+ (usec < 0 || max_usec < usec) ? max_usec : usec);+ tv.tv_sec = usec / 1000000;+ tv.tv_usec = usec % 1000000;+ return &tv;+}++void select_reactor::cancel_ops_unlocked(socket_type descriptor,+ const asio::error_code& ec)+{+ bool need_interrupt = false;+ op_queue<operation> ops;+ for (int i = 0; i < max_ops; ++i)+ need_interrupt = op_queue_[i].cancel_operations(+ descriptor, ops, ec) || need_interrupt;+ scheduler_.post_deferred_completions(ops);+ if (need_interrupt)+ interrupter_.interrupt();+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)+ // || (!defined(ASIO_HAS_DEV_POLL)+ // && !defined(ASIO_HAS_EPOLL)+ // && !defined(ASIO_HAS_KQUEUE))+ // && !defined(ASIO_WINDOWS_RUNTIME))++#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/service_registry.hpp view
@@ -0,0 +1,94 @@+//+// detail/impl/service_registry.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SERVICE_REGISTRY_HPP+#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Service>+Service& service_registry::use_service()+{+ execution_context::service::key key;+ init_key<Service>(key, 0);+ factory_type factory = &service_registry::create<Service, execution_context>;+ return *static_cast<Service*>(do_use_service(key, factory, &owner_));+}++template <typename Service>+Service& service_registry::use_service(io_context& owner)+{+ execution_context::service::key key;+ init_key<Service>(key, 0);+ factory_type factory = &service_registry::create<Service, io_context>;+ return *static_cast<Service*>(do_use_service(key, factory, &owner));+}++template <typename Service>+void service_registry::add_service(Service* new_service)+{+ execution_context::service::key key;+ init_key<Service>(key, 0);+ return do_add_service(key, new_service);+}++template <typename Service>+bool service_registry::has_service() const+{+ execution_context::service::key key;+ init_key<Service>(key, 0);+ return do_has_service(key);+}++template <typename Service>+inline void service_registry::init_key(+ execution_context::service::key& key, ...)+{+ init_key_from_id(key, Service::id);+}++#if !defined(ASIO_NO_TYPEID)+template <typename Service>+void service_registry::init_key(execution_context::service::key& key,+ typename enable_if<+ is_base_of<typename Service::key_type, Service>::value>::type*)+{+ key.type_info_ = &typeid(typeid_wrapper<Service>);+ key.id_ = 0;+}++template <typename Service>+void service_registry::init_key_from_id(execution_context::service::key& key,+ const service_id<Service>& /*id*/)+{+ key.type_info_ = &typeid(typeid_wrapper<Service>);+ key.id_ = 0;+}+#endif // !defined(ASIO_NO_TYPEID)++template <typename Service, typename Owner>+execution_context::service* service_registry::create(void* owner)+{+ return new Service(*static_cast<Owner*>(owner));+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/service_registry.ipp view
@@ -0,0 +1,197 @@+//+// detail/impl/service_registry.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SERVICE_REGISTRY_IPP+#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <vector>+#include "asio/detail/service_registry.hpp"+#include "asio/detail/throw_exception.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++service_registry::service_registry(execution_context& owner)+ : owner_(owner),+ first_service_(0)+{+}++service_registry::~service_registry()+{+}++void service_registry::shutdown_services()+{+ execution_context::service* service = first_service_;+ while (service)+ {+ service->shutdown();+ service = service->next_;+ }+}++void service_registry::destroy_services()+{+ while (first_service_)+ {+ execution_context::service* next_service = first_service_->next_;+ destroy(first_service_);+ first_service_ = next_service;+ }+}++void service_registry::notify_fork(execution_context::fork_event fork_ev)+{+ // Make a copy of all of the services while holding the lock. We don't want+ // to hold the lock while calling into each service, as it may try to call+ // back into this class.+ std::vector<execution_context::service*> services;+ {+ asio::detail::mutex::scoped_lock lock(mutex_);+ execution_context::service* service = first_service_;+ while (service)+ {+ services.push_back(service);+ service = service->next_;+ }+ }++ // If processing the fork_prepare event, we want to go in reverse order of+ // service registration, which happens to be the existing order of the+ // services in the vector. For the other events we want to go in the other+ // direction.+ std::size_t num_services = services.size();+ if (fork_ev == execution_context::fork_prepare)+ for (std::size_t i = 0; i < num_services; ++i)+ services[i]->notify_fork(fork_ev);+ else+ for (std::size_t i = num_services; i > 0; --i)+ services[i - 1]->notify_fork(fork_ev);+}++void service_registry::init_key_from_id(execution_context::service::key& key,+ const execution_context::id& id)+{+ key.type_info_ = 0;+ key.id_ = &id;+}++bool service_registry::keys_match(+ const execution_context::service::key& key1,+ const execution_context::service::key& key2)+{+ if (key1.id_ && key2.id_)+ if (key1.id_ == key2.id_)+ return true;+ if (key1.type_info_ && key2.type_info_)+ if (*key1.type_info_ == *key2.type_info_)+ return true;+ return false;+}++void service_registry::destroy(execution_context::service* service)+{+ delete service;+}++execution_context::service* service_registry::do_use_service(+ const execution_context::service::key& key,+ factory_type factory, void* owner)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ // First see if there is an existing service object with the given key.+ execution_context::service* service = first_service_;+ while (service)+ {+ if (keys_match(service->key_, key))+ return service;+ service = service->next_;+ }++ // Create a new service object. The service registry's mutex is not locked+ // at this time to allow for nested calls into this function from the new+ // service's constructor.+ lock.unlock();+ auto_service_ptr new_service = { factory(owner) };+ new_service.ptr_->key_ = key;+ lock.lock();++ // Check that nobody else created another service object of the same type+ // while the lock was released.+ service = first_service_;+ while (service)+ {+ if (keys_match(service->key_, key))+ return service;+ service = service->next_;+ }++ // Service was successfully initialised, pass ownership to registry.+ new_service.ptr_->next_ = first_service_;+ first_service_ = new_service.ptr_;+ new_service.ptr_ = 0;+ return first_service_;+}++void service_registry::do_add_service(+ const execution_context::service::key& key,+ execution_context::service* new_service)+{+ if (&owner_ != &new_service->context())+ asio::detail::throw_exception(invalid_service_owner());++ asio::detail::mutex::scoped_lock lock(mutex_);++ // Check if there is an existing service object with the given key.+ execution_context::service* service = first_service_;+ while (service)+ {+ if (keys_match(service->key_, key))+ asio::detail::throw_exception(service_already_exists());+ service = service->next_;+ }++ // Take ownership of the service object.+ new_service->key_ = key;+ new_service->next_ = first_service_;+ first_service_ = new_service;+}++bool service_registry::do_has_service(+ const execution_context::service::key& key) const+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ execution_context::service* service = first_service_;+ while (service)+ {+ if (keys_match(service->key_, key))+ return true;+ service = service->next_;+ }++ return false;+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/signal_set_service.ipp view
@@ -0,0 +1,668 @@+//+// detail/impl/signal_set_service.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SIGNAL_SET_SERVICE_IPP+#define ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <cstring>+#include <stdexcept>+#include "asio/detail/reactor.hpp"+#include "asio/detail/signal_blocker.hpp"+#include "asio/detail/signal_set_service.hpp"+#include "asio/detail/static_mutex.hpp"+#include "asio/detail/throw_exception.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++struct signal_state+{+ // Mutex used for protecting global state.+ static_mutex mutex_;++ // The read end of the pipe used for signal notifications.+ int read_descriptor_;++ // The write end of the pipe used for signal notifications.+ int write_descriptor_;++ // Whether the signal state has been prepared for a fork.+ bool fork_prepared_;++ // The head of a linked list of all signal_set_service instances.+ class signal_set_service* service_list_;++ // A count of the number of objects that are registered for each signal.+ std::size_t registration_count_[max_signal_number];+};++signal_state* get_signal_state()+{+ static signal_state state = {+ ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } };+ return &state;+}++void asio_signal_handler(int signal_number)+{+#if defined(ASIO_WINDOWS) \+ || defined(ASIO_WINDOWS_RUNTIME) \+ || defined(__CYGWIN__)+ signal_set_service::deliver_signal(signal_number);+#else // defined(ASIO_WINDOWS)+ // || defined(ASIO_WINDOWS_RUNTIME)+ // || defined(__CYGWIN__)+ int saved_errno = errno;+ signal_state* state = get_signal_state();+ signed_size_type result = ::write(state->write_descriptor_,+ &signal_number, sizeof(signal_number));+ (void)result;+ errno = saved_errno;+#endif // defined(ASIO_WINDOWS)+ // || defined(ASIO_WINDOWS_RUNTIME)+ // || defined(__CYGWIN__)++#if defined(ASIO_HAS_SIGNAL) && !defined(ASIO_HAS_SIGACTION)+ ::signal(signal_number, asio_signal_handler);+#endif // defined(ASIO_HAS_SIGNAL) && !defined(ASIO_HAS_SIGACTION)+}++#if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+class signal_set_service::pipe_read_op : public reactor_op+{+public:+ pipe_read_op()+ : reactor_op(asio::error_code(),+ &pipe_read_op::do_perform, pipe_read_op::do_complete)+ {+ }++ static status do_perform(reactor_op*)+ {+ signal_state* state = get_signal_state();++ int fd = state->read_descriptor_;+ int signal_number = 0;+ while (::read(fd, &signal_number, sizeof(int)) == sizeof(int))+ if (signal_number >= 0 && signal_number < max_signal_number)+ signal_set_service::deliver_signal(signal_number);++ return not_done;+ }++ static void do_complete(void* /*owner*/, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ pipe_read_op* o(static_cast<pipe_read_op*>(base));+ delete o;+ }+};+#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)++signal_set_service::signal_set_service(execution_context& context)+ : execution_context_service_base<signal_set_service>(context),+ scheduler_(asio::use_service<scheduler_impl>(context)),+#if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+ reactor_(asio::use_service<reactor>(context)),+#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)+ next_(0),+ prev_(0)+{+ get_signal_state()->mutex_.init();++#if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+ reactor_.init_task();+#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)++ for (int i = 0; i < max_signal_number; ++i)+ registrations_[i] = 0;++ add_service(this);+}++signal_set_service::~signal_set_service()+{+ remove_service(this);+}++void signal_set_service::shutdown()+{+ remove_service(this);++ op_queue<operation> ops;++ for (int i = 0; i < max_signal_number; ++i)+ {+ registration* reg = registrations_[i];+ while (reg)+ {+ ops.push(*reg->queue_);+ reg = reg->next_in_table_;+ }+ }++ scheduler_.abandon_operations(ops);+}++void signal_set_service::notify_fork(execution_context::fork_event fork_ev)+{+#if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+ signal_state* state = get_signal_state();+ static_mutex::scoped_lock lock(state->mutex_);++ switch (fork_ev)+ {+ case execution_context::fork_prepare:+ {+ int read_descriptor = state->read_descriptor_;+ state->fork_prepared_ = true;+ lock.unlock();+ reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_);+ reactor_.cleanup_descriptor_data(reactor_data_);+ }+ break;+ case execution_context::fork_parent:+ if (state->fork_prepared_)+ {+ int read_descriptor = state->read_descriptor_;+ state->fork_prepared_ = false;+ lock.unlock();+ reactor_.register_internal_descriptor(reactor::read_op,+ read_descriptor, reactor_data_, new pipe_read_op);+ }+ break;+ case execution_context::fork_child:+ if (state->fork_prepared_)+ {+ asio::detail::signal_blocker blocker;+ close_descriptors();+ open_descriptors();+ int read_descriptor = state->read_descriptor_;+ state->fork_prepared_ = false;+ lock.unlock();+ reactor_.register_internal_descriptor(reactor::read_op,+ read_descriptor, reactor_data_, new pipe_read_op);+ }+ break;+ default:+ break;+ }+#else // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)+ (void)fork_ev;+#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)+}++void signal_set_service::construct(+ signal_set_service::implementation_type& impl)+{+ impl.signals_ = 0;+}++void signal_set_service::destroy(+ signal_set_service::implementation_type& impl)+{+ asio::error_code ignored_ec;+ clear(impl, ignored_ec);+ cancel(impl, ignored_ec);+}++asio::error_code signal_set_service::add(+ signal_set_service::implementation_type& impl,+ int signal_number, asio::error_code& ec)+{+ // Check that the signal number is valid.+ if (signal_number < 0 || signal_number >= max_signal_number)+ {+ ec = asio::error::invalid_argument;+ return ec;+ }++ signal_state* state = get_signal_state();+ static_mutex::scoped_lock lock(state->mutex_);++ // Find the appropriate place to insert the registration.+ registration** insertion_point = &impl.signals_;+ registration* next = impl.signals_;+ while (next && next->signal_number_ < signal_number)+ {+ insertion_point = &next->next_in_set_;+ next = next->next_in_set_;+ }++ // Only do something if the signal is not already registered.+ if (next == 0 || next->signal_number_ != signal_number)+ {+ registration* new_registration = new registration;++#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)+ // Register for the signal if we're the first.+ if (state->registration_count_[signal_number] == 0)+ {+# if defined(ASIO_HAS_SIGACTION)+ using namespace std; // For memset.+ struct sigaction sa;+ memset(&sa, 0, sizeof(sa));+ sa.sa_handler = asio_signal_handler;+ sigfillset(&sa.sa_mask);+ if (::sigaction(signal_number, &sa, 0) == -1)+# else // defined(ASIO_HAS_SIGACTION)+ if (::signal(signal_number, asio_signal_handler) == SIG_ERR)+# endif // defined(ASIO_HAS_SIGACTION)+ {+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ec = asio::error::invalid_argument;+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ec = asio::error_code(errno,+ asio::error::get_system_category());+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ delete new_registration;+ return ec;+ }+ }+#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)++ // Record the new registration in the set.+ new_registration->signal_number_ = signal_number;+ new_registration->queue_ = &impl.queue_;+ new_registration->next_in_set_ = next;+ *insertion_point = new_registration;++ // Insert registration into the registration table.+ new_registration->next_in_table_ = registrations_[signal_number];+ if (registrations_[signal_number])+ registrations_[signal_number]->prev_in_table_ = new_registration;+ registrations_[signal_number] = new_registration;++ ++state->registration_count_[signal_number];+ }++ ec = asio::error_code();+ return ec;+}++asio::error_code signal_set_service::remove(+ signal_set_service::implementation_type& impl,+ int signal_number, asio::error_code& ec)+{+ // Check that the signal number is valid.+ if (signal_number < 0 || signal_number >= max_signal_number)+ {+ ec = asio::error::invalid_argument;+ return ec;+ }++ signal_state* state = get_signal_state();+ static_mutex::scoped_lock lock(state->mutex_);++ // Find the signal number in the list of registrations.+ registration** deletion_point = &impl.signals_;+ registration* reg = impl.signals_;+ while (reg && reg->signal_number_ < signal_number)+ {+ deletion_point = ®->next_in_set_;+ reg = reg->next_in_set_;+ }++ if (reg != 0 && reg->signal_number_ == signal_number)+ {+#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)+ // Set signal handler back to the default if we're the last.+ if (state->registration_count_[signal_number] == 1)+ {+# if defined(ASIO_HAS_SIGACTION)+ using namespace std; // For memset.+ struct sigaction sa;+ memset(&sa, 0, sizeof(sa));+ sa.sa_handler = SIG_DFL;+ if (::sigaction(signal_number, &sa, 0) == -1)+# else // defined(ASIO_HAS_SIGACTION)+ if (::signal(signal_number, SIG_DFL) == SIG_ERR)+# endif // defined(ASIO_HAS_SIGACTION)+ {+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ec = asio::error::invalid_argument;+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ec = asio::error_code(errno,+ asio::error::get_system_category());+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ return ec;+ }+ }+#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)++ // Remove the registration from the set.+ *deletion_point = reg->next_in_set_;++ // Remove the registration from the registration table.+ if (registrations_[signal_number] == reg)+ registrations_[signal_number] = reg->next_in_table_;+ if (reg->prev_in_table_)+ reg->prev_in_table_->next_in_table_ = reg->next_in_table_;+ if (reg->next_in_table_)+ reg->next_in_table_->prev_in_table_ = reg->prev_in_table_;++ --state->registration_count_[signal_number];++ delete reg;+ }++ ec = asio::error_code();+ return ec;+}++asio::error_code signal_set_service::clear(+ signal_set_service::implementation_type& impl,+ asio::error_code& ec)+{+ signal_state* state = get_signal_state();+ static_mutex::scoped_lock lock(state->mutex_);++ while (registration* reg = impl.signals_)+ {+#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)+ // Set signal handler back to the default if we're the last.+ if (state->registration_count_[reg->signal_number_] == 1)+ {+# if defined(ASIO_HAS_SIGACTION)+ using namespace std; // For memset.+ struct sigaction sa;+ memset(&sa, 0, sizeof(sa));+ sa.sa_handler = SIG_DFL;+ if (::sigaction(reg->signal_number_, &sa, 0) == -1)+# else // defined(ASIO_HAS_SIGACTION)+ if (::signal(reg->signal_number_, SIG_DFL) == SIG_ERR)+# endif // defined(ASIO_HAS_SIGACTION)+ {+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ec = asio::error::invalid_argument;+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ec = asio::error_code(errno,+ asio::error::get_system_category());+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ return ec;+ }+ }+#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)++ // Remove the registration from the registration table.+ if (registrations_[reg->signal_number_] == reg)+ registrations_[reg->signal_number_] = reg->next_in_table_;+ if (reg->prev_in_table_)+ reg->prev_in_table_->next_in_table_ = reg->next_in_table_;+ if (reg->next_in_table_)+ reg->next_in_table_->prev_in_table_ = reg->prev_in_table_;++ --state->registration_count_[reg->signal_number_];++ impl.signals_ = reg->next_in_set_;+ delete reg;+ }++ ec = asio::error_code();+ return ec;+}++asio::error_code signal_set_service::cancel(+ signal_set_service::implementation_type& impl,+ asio::error_code& ec)+{+ ASIO_HANDLER_OPERATION((scheduler_.context(),+ "signal_set", &impl, 0, "cancel"));++ op_queue<operation> ops;+ {+ signal_state* state = get_signal_state();+ static_mutex::scoped_lock lock(state->mutex_);++ while (signal_op* op = impl.queue_.front())+ {+ op->ec_ = asio::error::operation_aborted;+ impl.queue_.pop();+ ops.push(op);+ }+ }++ scheduler_.post_deferred_completions(ops);++ ec = asio::error_code();+ return ec;+}++void signal_set_service::deliver_signal(int signal_number)+{+ signal_state* state = get_signal_state();+ static_mutex::scoped_lock lock(state->mutex_);++ signal_set_service* service = state->service_list_;+ while (service)+ {+ op_queue<operation> ops;++ registration* reg = service->registrations_[signal_number];+ while (reg)+ {+ if (reg->queue_->empty())+ {+ ++reg->undelivered_;+ }+ else+ {+ while (signal_op* op = reg->queue_->front())+ {+ op->signal_number_ = signal_number;+ reg->queue_->pop();+ ops.push(op);+ }+ }++ reg = reg->next_in_table_;+ }++ service->scheduler_.post_deferred_completions(ops);++ service = service->next_;+ }+}++void signal_set_service::add_service(signal_set_service* service)+{+ signal_state* state = get_signal_state();+ static_mutex::scoped_lock lock(state->mutex_);++#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)+ // If this is the first service to be created, open a new pipe.+ if (state->service_list_ == 0)+ open_descriptors();+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++ // If a scheduler_ object is thread-unsafe then it must be the only+ // scheduler used to create signal_set objects.+ if (state->service_list_ != 0)+ {+ if (!ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,+ service->scheduler_.concurrency_hint())+ || !ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,+ state->service_list_->scheduler_.concurrency_hint()))+ {+ std::logic_error ex(+ "Thread-unsafe execution context objects require "+ "exclusive access to signal handling.");+ asio::detail::throw_exception(ex);+ }+ }++ // Insert service into linked list of all services.+ service->next_ = state->service_list_;+ service->prev_ = 0;+ if (state->service_list_)+ state->service_list_->prev_ = service;+ state->service_list_ = service;++#if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+ // Register for pipe readiness notifications.+ int read_descriptor = state->read_descriptor_;+ lock.unlock();+ service->reactor_.register_internal_descriptor(reactor::read_op,+ read_descriptor, service->reactor_data_, new pipe_read_op);+#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)+}++void signal_set_service::remove_service(signal_set_service* service)+{+ signal_state* state = get_signal_state();+ static_mutex::scoped_lock lock(state->mutex_);++ if (service->next_ || service->prev_ || state->service_list_ == service)+ {+#if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+ // Disable the pipe readiness notifications.+ int read_descriptor = state->read_descriptor_;+ lock.unlock();+ service->reactor_.deregister_internal_descriptor(+ read_descriptor, service->reactor_data_);+ service->reactor_.cleanup_descriptor_data(service->reactor_data_);+ lock.lock();+#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)++ // Remove service from linked list of all services.+ if (state->service_list_ == service)+ state->service_list_ = service->next_;+ if (service->prev_)+ service->prev_->next_ = service->next_;+ if (service->next_)+ service->next_->prev_= service->prev_;+ service->next_ = 0;+ service->prev_ = 0;++#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)+ // If this is the last service to be removed, close the pipe.+ if (state->service_list_ == 0)+ close_descriptors();+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)+ }+}++void signal_set_service::open_descriptors()+{+#if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+ signal_state* state = get_signal_state();++ int pipe_fds[2];+ if (::pipe(pipe_fds) == 0)+ {+ state->read_descriptor_ = pipe_fds[0];+ ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK);++ state->write_descriptor_ = pipe_fds[1];+ ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK);++#if defined(FD_CLOEXEC)+ ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC);+ ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC);+#endif // defined(FD_CLOEXEC)+ }+ else+ {+ asio::error_code ec(errno,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "signal_set_service pipe");+ }+#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)+}++void signal_set_service::close_descriptors()+{+#if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+ signal_state* state = get_signal_state();++ if (state->read_descriptor_ != -1)+ ::close(state->read_descriptor_);+ state->read_descriptor_ = -1;++ if (state->write_descriptor_ != -1)+ ::close(state->write_descriptor_);+ state->write_descriptor_ = -1;+#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)+}++void signal_set_service::start_wait_op(+ signal_set_service::implementation_type& impl, signal_op* op)+{+ scheduler_.work_started();++ signal_state* state = get_signal_state();+ static_mutex::scoped_lock lock(state->mutex_);++ registration* reg = impl.signals_;+ while (reg)+ {+ if (reg->undelivered_ > 0)+ {+ --reg->undelivered_;+ op->signal_number_ = reg->signal_number_;+ scheduler_.post_deferred_completion(op);+ return;+ }++ reg = reg->next_in_set_;+ }++ impl.queue_.push(op);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/socket_ops.ipp view
@@ -0,0 +1,3962 @@+//+// detail/impl/socket_ops.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_OPS_IPP+#define ASIO_DETAIL_SOCKET_OPS_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <cctype>+#include <cstdio>+#include <cstdlib>+#include <cstring>+#include <cerrno>+#include <new>+#include "asio/detail/assert.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/error.hpp"++#if defined(ASIO_WINDOWS_RUNTIME)+# include <codecvt>+# include <locale>+# include <string>+#endif // defined(ASIO_WINDOWS_RUNTIME)++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) \+ || defined(__MACH__) && defined(__APPLE__)+# if defined(ASIO_HAS_PTHREADS)+# include <pthread.h>+# endif // defined(ASIO_HAS_PTHREADS)+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ // || defined(__MACH__) && defined(__APPLE__)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {+namespace socket_ops {++#if !defined(ASIO_WINDOWS_RUNTIME)++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+struct msghdr { int msg_namelen; };+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++#if defined(__hpux)+// HP-UX doesn't declare these functions extern "C", so they are declared again+// here to avoid linker errors about undefined symbols.+extern "C" char* if_indextoname(unsigned int, char*);+extern "C" unsigned int if_nametoindex(const char*);+#endif // defined(__hpux)++#endif // !defined(ASIO_WINDOWS_RUNTIME)++inline void clear_last_error()+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ WSASetLastError(0);+#else+ errno = 0;+#endif+}++#if !defined(ASIO_WINDOWS_RUNTIME)++inline void get_last_error(+ asio::error_code& ec, bool is_error_condition)+{+ if (!is_error_condition)+ {+ ec.assign(0, ec.category());+ }+ else+ {+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ec = asio::error_code(WSAGetLastError(),+ asio::error::get_system_category());+#else+ ec = asio::error_code(errno,+ asio::error::get_system_category());+#endif+ }+}++template <typename SockLenType>+inline socket_type call_accept(SockLenType msghdr::*,+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)+{+ SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;+ socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);+ if (addrlen)+ *addrlen = (std::size_t)tmp_addrlen;+ return result;+}++socket_type accept(socket_type s, socket_addr_type* addr,+ std::size_t* addrlen, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return invalid_socket;+ }++ socket_type new_s = call_accept(&msghdr::msg_namelen, s, addr, addrlen);+ get_last_error(ec, new_s == invalid_socket);+ if (new_s == invalid_socket)+ return new_s;++#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)+ int optval = 1;+ int result = ::setsockopt(new_s, SOL_SOCKET,+ SO_NOSIGPIPE, &optval, sizeof(optval));+ get_last_error(ec, result != 0);+ if (result != 0)+ {+ ::close(new_s);+ return invalid_socket;+ }+#endif++ ec.assign(0, ec.category());+ return new_s;+}++socket_type sync_accept(socket_type s, state_type state,+ socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec)+{+ // Accept a socket.+ for (;;)+ {+ // Try to complete the operation without blocking.+ socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec);++ // Check if operation succeeded.+ if (new_socket != invalid_socket)+ return new_socket;++ // Operation failed.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ {+ if (state & user_set_non_blocking)+ return invalid_socket;+ // Fall through to retry operation.+ }+ else if (ec == asio::error::connection_aborted)+ {+ if (state & enable_connection_aborted)+ return invalid_socket;+ // Fall through to retry operation.+ }+#if defined(EPROTO)+ else if (ec.value() == EPROTO)+ {+ if (state & enable_connection_aborted)+ return invalid_socket;+ // Fall through to retry operation.+ }+#endif // defined(EPROTO)+ else+ return invalid_socket;++ // Wait for socket to become ready.+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)+ return invalid_socket;+ }+}++#if defined(ASIO_HAS_IOCP)++void complete_iocp_accept(socket_type s,+ void* output_buffer, DWORD address_length,+ socket_addr_type* addr, std::size_t* addrlen,+ socket_type new_socket, asio::error_code& ec)+{+ // Map non-portable errors to their portable counterparts.+ if (ec.value() == ERROR_NETNAME_DELETED)+ ec = asio::error::connection_aborted;++ if (!ec)+ {+ // Get the address of the peer.+ if (addr && addrlen)+ {+ LPSOCKADDR local_addr = 0;+ int local_addr_length = 0;+ LPSOCKADDR remote_addr = 0;+ int remote_addr_length = 0;+ GetAcceptExSockaddrs(output_buffer, 0, address_length,+ address_length, &local_addr, &local_addr_length,+ &remote_addr, &remote_addr_length);+ if (static_cast<std::size_t>(remote_addr_length) > *addrlen)+ {+ ec = asio::error::invalid_argument;+ }+ else+ {+ using namespace std; // For memcpy.+ memcpy(addr, remote_addr, remote_addr_length);+ *addrlen = static_cast<std::size_t>(remote_addr_length);+ }+ }++ // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname+ // and getpeername will work on the accepted socket.+ SOCKET update_ctx_param = s;+ socket_ops::state_type state = 0;+ socket_ops::setsockopt(new_socket, state,+ SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,+ &update_ctx_param, sizeof(SOCKET), ec);+ }+}++#else // defined(ASIO_HAS_IOCP)++bool non_blocking_accept(socket_type s,+ state_type state, socket_addr_type* addr, std::size_t* addrlen,+ asio::error_code& ec, socket_type& new_socket)+{+ for (;;)+ {+ // Accept the waiting connection.+ new_socket = socket_ops::accept(s, addr, addrlen, ec);++ // Check if operation succeeded.+ if (new_socket != invalid_socket)+ return true;++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Operation failed.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ {+ // Fall through to retry operation.+ }+ else if (ec == asio::error::connection_aborted)+ {+ if (state & enable_connection_aborted)+ return true;+ // Fall through to retry operation.+ }+#if defined(EPROTO)+ else if (ec.value() == EPROTO)+ {+ if (state & enable_connection_aborted)+ return true;+ // Fall through to retry operation.+ }+#endif // defined(EPROTO)+ else+ return true;++ return false;+ }+}++#endif // defined(ASIO_HAS_IOCP)++template <typename SockLenType>+inline int call_bind(SockLenType msghdr::*,+ socket_type s, const socket_addr_type* addr, std::size_t addrlen)+{+ return ::bind(s, addr, (SockLenType)addrlen);+}++int bind(socket_type s, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++ int result = call_bind(&msghdr::msg_namelen, s, addr, addrlen);+ get_last_error(ec, result != 0);+ return result;+}++int close(socket_type s, state_type& state,+ bool destruction, asio::error_code& ec)+{+ int result = 0;+ if (s != invalid_socket)+ {+ // We don't want the destructor to block, so set the socket to linger in+ // the background. If the user doesn't like this behaviour then they need+ // to explicitly close the socket.+ if (destruction && (state & user_set_linger))+ {+ ::linger opt;+ opt.l_onoff = 0;+ opt.l_linger = 0;+ asio::error_code ignored_ec;+ socket_ops::setsockopt(s, state, SOL_SOCKET,+ SO_LINGER, &opt, sizeof(opt), ignored_ec);+ }++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ result = ::closesocket(s);+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ result = ::close(s);+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ get_last_error(ec, result != 0);++ if (result != 0+ && (ec == asio::error::would_block+ || ec == asio::error::try_again))+ {+ // According to UNIX Network Programming Vol. 1, it is possible for+ // close() to fail with EWOULDBLOCK under certain circumstances. What+ // isn't clear is the state of the descriptor after this error. The one+ // current OS where this behaviour is seen, Windows, says that the socket+ // remains open. Therefore we'll put the descriptor back into blocking+ // mode and have another attempt at closing it.+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ioctl_arg_type arg = 0;+ ::ioctlsocket(s, FIONBIO, &arg);+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+ int flags = ::fcntl(s, F_GETFL, 0);+ if (flags >= 0)+ ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK);+# else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+ ioctl_arg_type arg = 0;+ ::ioctl(s, FIONBIO, &arg);+# endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ state &= ~non_blocking;++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ result = ::closesocket(s);+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ result = ::close(s);+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ get_last_error(ec, result != 0);+ }+ }++ return result;+}++bool set_user_non_blocking(socket_type s,+ state_type& state, bool value, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return false;+ }++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ioctl_arg_type arg = (value ? 1 : 0);+ int result = ::ioctlsocket(s, FIONBIO, &arg);+ get_last_error(ec, result < 0);+#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+ int result = ::fcntl(s, F_GETFL, 0);+ get_last_error(ec, result < 0);+ if (result >= 0)+ {+ int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));+ result = ::fcntl(s, F_SETFL, flag);+ get_last_error(ec, result < 0);+ }+#else+ ioctl_arg_type arg = (value ? 1 : 0);+ int result = ::ioctl(s, FIONBIO, &arg);+ get_last_error(ec, result < 0);+#endif++ if (result >= 0)+ {+ if (value)+ state |= user_set_non_blocking;+ else+ {+ // Clearing the user-set non-blocking mode always overrides any+ // internally-set non-blocking flag. Any subsequent asynchronous+ // operations will need to re-enable non-blocking I/O.+ state &= ~(user_set_non_blocking | internal_non_blocking);+ }+ return true;+ }++ return false;+}++bool set_internal_non_blocking(socket_type s,+ state_type& state, bool value, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return false;+ }++ if (!value && (state & user_set_non_blocking))+ {+ // It does not make sense to clear the internal non-blocking flag if the+ // user still wants non-blocking behaviour. Return an error and let the+ // caller figure out whether to update the user-set non-blocking flag.+ ec = asio::error::invalid_argument;+ return false;+ }++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ ioctl_arg_type arg = (value ? 1 : 0);+ int result = ::ioctlsocket(s, FIONBIO, &arg);+ get_last_error(ec, result < 0);+#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)+ int result = ::fcntl(s, F_GETFL, 0);+ get_last_error(ec, result < 0);+ if (result >= 0)+ {+ int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));+ result = ::fcntl(s, F_SETFL, flag);+ get_last_error(ec, result < 0);+ }+#else+ ioctl_arg_type arg = (value ? 1 : 0);+ int result = ::ioctl(s, FIONBIO, &arg);+ get_last_error(ec, result < 0);+#endif++ if (result >= 0)+ {+ if (value)+ state |= internal_non_blocking;+ else+ state &= ~internal_non_blocking;+ return true;+ }++ return false;+}++int shutdown(socket_type s, int what, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++ int result = ::shutdown(s, what);+ get_last_error(ec, result != 0);+ return result;+}++template <typename SockLenType>+inline int call_connect(SockLenType msghdr::*,+ socket_type s, const socket_addr_type* addr, std::size_t addrlen)+{+ return ::connect(s, addr, (SockLenType)addrlen);+}++int connect(socket_type s, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++ int result = call_connect(&msghdr::msg_namelen, s, addr, addrlen);+ get_last_error(ec, result != 0);+#if defined(__linux__)+ if (result != 0 && ec == asio::error::try_again)+ ec = asio::error::no_buffer_space;+#endif // defined(__linux__)+ return result;+}++void sync_connect(socket_type s, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec)+{+ // Perform the connect operation.+ socket_ops::connect(s, addr, addrlen, ec);+ if (ec != asio::error::in_progress+ && ec != asio::error::would_block)+ {+ // The connect operation finished immediately.+ return;+ }++ // Wait for socket to become ready.+ if (socket_ops::poll_connect(s, -1, ec) < 0)+ return;++ // Get the error code from the connect operation.+ int connect_error = 0;+ size_t connect_error_len = sizeof(connect_error);+ if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,+ &connect_error, &connect_error_len, ec) == socket_error_retval)+ return;++ // Return the result of the connect operation.+ ec = asio::error_code(connect_error,+ asio::error::get_system_category());+}++#if defined(ASIO_HAS_IOCP)++void complete_iocp_connect(socket_type s, asio::error_code& ec)+{+ // Map non-portable errors to their portable counterparts.+ switch (ec.value())+ {+ case ERROR_CONNECTION_REFUSED:+ ec = asio::error::connection_refused;+ break;+ case ERROR_NETWORK_UNREACHABLE:+ ec = asio::error::network_unreachable;+ break;+ case ERROR_HOST_UNREACHABLE:+ ec = asio::error::host_unreachable;+ break;+ case ERROR_SEM_TIMEOUT:+ ec = asio::error::timed_out;+ break;+ default:+ break;+ }++ if (!ec)+ {+ // Need to set the SO_UPDATE_CONNECT_CONTEXT option so that getsockname+ // and getpeername will work on the connected socket.+ socket_ops::state_type state = 0;+ const int so_update_connect_context = 0x7010;+ socket_ops::setsockopt(s, state, SOL_SOCKET,+ so_update_connect_context, 0, 0, ec);+ }+}++#endif // defined(ASIO_HAS_IOCP)++bool non_blocking_connect(socket_type s, asio::error_code& ec)+{+ // Check if the connect operation has finished. This is required since we may+ // get spurious readiness notifications from the reactor.+#if defined(ASIO_WINDOWS) \+ || defined(__CYGWIN__) \+ || defined(__SYMBIAN32__)+ fd_set write_fds;+ FD_ZERO(&write_fds);+ FD_SET(s, &write_fds);+ fd_set except_fds;+ FD_ZERO(&except_fds);+ FD_SET(s, &except_fds);+ timeval zero_timeout;+ zero_timeout.tv_sec = 0;+ zero_timeout.tv_usec = 0;+ int ready = ::select(s + 1, 0, &write_fds, &except_fds, &zero_timeout);+#else // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)+ pollfd fds;+ fds.fd = s;+ fds.events = POLLOUT;+ fds.revents = 0;+ int ready = ::poll(&fds, 1, 0);+#endif // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)+ if (ready == 0)+ {+ // The asynchronous connect operation is still in progress.+ return false;+ }++ // Get the error code from the connect operation.+ int connect_error = 0;+ size_t connect_error_len = sizeof(connect_error);+ if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,+ &connect_error, &connect_error_len, ec) == 0)+ {+ if (connect_error)+ {+ ec = asio::error_code(connect_error,+ asio::error::get_system_category());+ }+ else+ ec.assign(0, ec.category());+ }++ return true;+}++int socketpair(int af, int type, int protocol,+ socket_type sv[2], asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ (void)(af);+ (void)(type);+ (void)(protocol);+ (void)(sv);+ ec = asio::error::operation_not_supported;+ return socket_error_retval;+#else+ int result = ::socketpair(af, type, protocol, sv);+ get_last_error(ec, result != 0);+ return result;+#endif+}++bool sockatmark(socket_type s, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return false;+ }++#if defined(SIOCATMARK)+ ioctl_arg_type value = 0;+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ int result = ::ioctlsocket(s, SIOCATMARK, &value);+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ int result = ::ioctl(s, SIOCATMARK, &value);+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ get_last_error(ec, result < 0);+# if defined(ENOTTY)+ if (ec.value() == ENOTTY)+ ec = asio::error::not_socket;+# endif // defined(ENOTTY)+#else // defined(SIOCATMARK)+ int value = ::sockatmark(s);+ get_last_error(ec, result < 0);+#endif // defined(SIOCATMARK)++ return ec ? false : value != 0;+}++size_t available(socket_type s, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ ioctl_arg_type value = 0;+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ int result = ::ioctlsocket(s, FIONREAD, &value);+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ int result = ::ioctl(s, FIONREAD, &value);+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ get_last_error(ec, result < 0);+#if defined(ENOTTY)+ if (ec.value() == ENOTTY)+ ec = asio::error::not_socket;+#endif // defined(ENOTTY)++ return ec ? static_cast<size_t>(0) : static_cast<size_t>(value);+}++int listen(socket_type s, int backlog, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++ int result = ::listen(s, backlog);+ get_last_error(ec, result != 0);+ return result;+}++inline void init_buf_iov_base(void*& base, void* addr)+{+ base = addr;+}++template <typename T>+inline void init_buf_iov_base(T& base, void* addr)+{+ base = static_cast<T>(addr);+}++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+typedef WSABUF buf;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+typedef iovec buf;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++void init_buf(buf& b, void* data, size_t size)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ b.buf = static_cast<char*>(data);+ b.len = static_cast<u_long>(size);+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ init_buf_iov_base(b.iov_base, data);+ b.iov_len = size;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++void init_buf(buf& b, const void* data, size_t size)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ b.buf = static_cast<char*>(const_cast<void*>(data));+ b.len = static_cast<u_long>(size);+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ init_buf_iov_base(b.iov_base, const_cast<void*>(data));+ b.iov_len = size;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr)+{+ name = addr;+}++inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)+{+ name = const_cast<socket_addr_type*>(addr);+}++template <typename T>+inline void init_msghdr_msg_name(T& name, socket_addr_type* addr)+{+ name = reinterpret_cast<T>(addr);+}++template <typename T>+inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr)+{+ name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr));+}++signed_size_type recv(socket_type s, buf* bufs, size_t count,+ int flags, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ // Receive some data.+ DWORD recv_buf_count = static_cast<DWORD>(count);+ DWORD bytes_transferred = 0;+ DWORD recv_flags = flags;+ int result = ::WSARecv(s, bufs, recv_buf_count,+ &bytes_transferred, &recv_flags, 0, 0);+ get_last_error(ec, true);+ if (ec.value() == ERROR_NETNAME_DELETED)+ ec = asio::error::connection_reset;+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ ec = asio::error::connection_refused;+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)+ result = 0;+ if (result != 0)+ return socket_error_retval;+ ec.assign(0, ec.category());+ return bytes_transferred;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ msghdr msg = msghdr();+ msg.msg_iov = bufs;+ msg.msg_iovlen = static_cast<int>(count);+ signed_size_type result = ::recvmsg(s, &msg, flags);+ get_last_error(ec, result < 0);+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++signed_size_type recv1(socket_type s, void* data, size_t size,+ int flags, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ // Receive some data.+ WSABUF buf;+ buf.buf = const_cast<char*>(static_cast<const char*>(data));+ buf.len = static_cast<ULONG>(size);+ DWORD bytes_transferred = 0;+ DWORD recv_flags = flags;+ int result = ::WSARecv(s, &buf, 1,+ &bytes_transferred, &recv_flags, 0, 0);+ get_last_error(ec, true);+ if (ec.value() == ERROR_NETNAME_DELETED)+ ec = asio::error::connection_reset;+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ ec = asio::error::connection_refused;+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)+ result = 0;+ if (result != 0)+ return socket_error_retval;+ ec.assign(0, ec.category());+ return bytes_transferred;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ signed_size_type result = ::recv(s, static_cast<char*>(data), size, flags);+ get_last_error(ec, result < 0);+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++size_t sync_recv(socket_type s, state_type state, buf* bufs,+ size_t count, int flags, bool all_empty, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // A request to read 0 bytes on a stream is a no-op.+ if (all_empty && (state & stream_oriented))+ {+ ec.assign(0, ec.category());+ return 0;+ }++ // Read some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);++ // Check for EOF.+ if ((state & stream_oriented) && bytes == 0)+ {+ ec = asio::error::eof;+ return 0;+ }++ // Check if operation succeeded.+ if (bytes >= 0)+ return bytes;++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for socket to become ready.+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)+ return 0;+ }+}++size_t sync_recv1(socket_type s, state_type state, void* data,+ size_t size, int flags, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // A request to read 0 bytes on a stream is a no-op.+ if (size == 0 && (state & stream_oriented))+ {+ ec.assign(0, ec.category());+ return 0;+ }++ // Read some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec);++ // Check for EOF.+ if ((state & stream_oriented) && bytes == 0)+ {+ ec = asio::error::eof;+ return 0;+ }++ // Check if operation succeeded.+ if (bytes >= 0)+ return bytes;++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for socket to become ready.+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)+ return 0;+ }+}++#if defined(ASIO_HAS_IOCP)++void complete_iocp_recv(state_type state,+ const weak_cancel_token_type& cancel_token, bool all_empty,+ asio::error_code& ec, size_t bytes_transferred)+{+ // Map non-portable errors to their portable counterparts.+ if (ec.value() == ERROR_NETNAME_DELETED)+ {+ if (cancel_token.expired())+ ec = asio::error::operation_aborted;+ else+ ec = asio::error::connection_reset;+ }+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ {+ ec = asio::error::connection_refused;+ }+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)+ {+ ec.assign(0, ec.category());+ }++ // Check for connection closed.+ else if (!ec && bytes_transferred == 0+ && (state & stream_oriented) != 0+ && !all_empty)+ {+ ec = asio::error::eof;+ }+}++#else // defined(ASIO_HAS_IOCP)++bool non_blocking_recv(socket_type s,+ buf* bufs, size_t count, int flags, bool is_stream,+ asio::error_code& ec, size_t& bytes_transferred)+{+ for (;;)+ {+ // Read some data.+ signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);++ // Check for end of stream.+ if (is_stream && bytes == 0)+ {+ ec = asio::error::eof;+ return true;+ }++ // Check if operation succeeded.+ if (bytes >= 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++bool non_blocking_recv1(socket_type s,+ void* data, size_t size, int flags, bool is_stream,+ asio::error_code& ec, size_t& bytes_transferred)+{+ for (;;)+ {+ // Read some data.+ signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec);++ // Check for end of stream.+ if (is_stream && bytes == 0)+ {+ ec = asio::error::eof;+ return true;+ }++ // Check if operation succeeded.+ if (bytes >= 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++#endif // defined(ASIO_HAS_IOCP)++signed_size_type recvfrom(socket_type s, buf* bufs, size_t count,+ int flags, socket_addr_type* addr, std::size_t* addrlen,+ asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ // Receive some data.+ DWORD recv_buf_count = static_cast<DWORD>(count);+ DWORD bytes_transferred = 0;+ DWORD recv_flags = flags;+ int tmp_addrlen = (int)*addrlen;+ int result = ::WSARecvFrom(s, bufs, recv_buf_count,+ &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0);+ get_last_error(ec, true);+ *addrlen = (std::size_t)tmp_addrlen;+ if (ec.value() == ERROR_NETNAME_DELETED)+ ec = asio::error::connection_reset;+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ ec = asio::error::connection_refused;+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)+ result = 0;+ if (result != 0)+ return socket_error_retval;+ ec.assign(0, ec.category());+ return bytes_transferred;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ msghdr msg = msghdr();+ init_msghdr_msg_name(msg.msg_name, addr);+ msg.msg_namelen = static_cast<int>(*addrlen);+ msg.msg_iov = bufs;+ msg.msg_iovlen = static_cast<int>(count);+ signed_size_type result = ::recvmsg(s, &msg, flags);+ get_last_error(ec, result < 0);+ *addrlen = msg.msg_namelen;+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++template <typename SockLenType>+inline signed_size_type call_recvfrom(SockLenType msghdr::*,+ socket_type s, void* data, size_t size, int flags,+ socket_addr_type* addr, std::size_t* addrlen)+{+ SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;+ signed_size_type result = ::recvfrom(s, static_cast<char*>(data),+ size, flags, addr, addrlen ? &tmp_addrlen : 0);+ if (addrlen)+ *addrlen = (std::size_t)tmp_addrlen;+ return result;+}++signed_size_type recvfrom1(socket_type s, void* data, size_t size,+ int flags, socket_addr_type* addr, std::size_t* addrlen,+ asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ // Receive some data.+ WSABUF buf;+ buf.buf = static_cast<char*>(data);+ buf.len = static_cast<ULONG>(size);+ DWORD bytes_transferred = 0;+ DWORD recv_flags = flags;+ int tmp_addrlen = (int)*addrlen;+ int result = ::WSARecvFrom(s, &buf, 1, &bytes_transferred,+ &recv_flags, addr, &tmp_addrlen, 0, 0);+ get_last_error(ec, true);+ *addrlen = (std::size_t)tmp_addrlen;+ if (ec.value() == ERROR_NETNAME_DELETED)+ ec = asio::error::connection_reset;+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ ec = asio::error::connection_refused;+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)+ result = 0;+ if (result != 0)+ return socket_error_retval;+ ec.assign(0, ec.category());+ return bytes_transferred;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ signed_size_type result = call_recvfrom(&msghdr::msg_namelen,+ s, data, size, flags, addr, addrlen);+ get_last_error(ec, result < 0);+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,+ size_t count, int flags, socket_addr_type* addr,+ std::size_t* addrlen, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // Read some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = socket_ops::recvfrom(+ s, bufs, count, flags, addr, addrlen, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ return bytes;++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for socket to become ready.+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)+ return 0;+ }+}++size_t sync_recvfrom1(socket_type s, state_type state, void* data,+ size_t size, int flags, socket_addr_type* addr,+ std::size_t* addrlen, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // Read some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = socket_ops::recvfrom1(+ s, data, size, flags, addr, addrlen, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ return bytes;++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for socket to become ready.+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)+ return 0;+ }+}++#if defined(ASIO_HAS_IOCP)++void complete_iocp_recvfrom(+ const weak_cancel_token_type& cancel_token,+ asio::error_code& ec)+{+ // Map non-portable errors to their portable counterparts.+ if (ec.value() == ERROR_NETNAME_DELETED)+ {+ if (cancel_token.expired())+ ec = asio::error::operation_aborted;+ else+ ec = asio::error::connection_reset;+ }+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ {+ ec = asio::error::connection_refused;+ }+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)+ {+ ec.assign(0, ec.category());+ }+}++#else // defined(ASIO_HAS_IOCP)++bool non_blocking_recvfrom(socket_type s,+ buf* bufs, size_t count, int flags,+ socket_addr_type* addr, std::size_t* addrlen,+ asio::error_code& ec, size_t& bytes_transferred)+{+ for (;;)+ {+ // Read some data.+ signed_size_type bytes = socket_ops::recvfrom(+ s, bufs, count, flags, addr, addrlen, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++bool non_blocking_recvfrom1(socket_type s,+ void* data, size_t size, int flags,+ socket_addr_type* addr, std::size_t* addrlen,+ asio::error_code& ec, size_t& bytes_transferred)+{+ for (;;)+ {+ // Read some data.+ signed_size_type bytes = socket_ops::recvfrom1(+ s, data, size, flags, addr, addrlen, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++#endif // defined(ASIO_HAS_IOCP)++signed_size_type recvmsg(socket_type s, buf* bufs, size_t count,+ int in_flags, int& out_flags, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ out_flags = 0;+ return socket_ops::recv(s, bufs, count, in_flags, ec);+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ msghdr msg = msghdr();+ msg.msg_iov = bufs;+ msg.msg_iovlen = static_cast<int>(count);+ signed_size_type result = ::recvmsg(s, &msg, in_flags);+ get_last_error(ec, result < 0);+ if (result >= 0)+ out_flags = msg.msg_flags;+ else+ out_flags = 0;+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++size_t sync_recvmsg(socket_type s, state_type state,+ buf* bufs, size_t count, int in_flags, int& out_flags,+ asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // Read some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = socket_ops::recvmsg(+ s, bufs, count, in_flags, out_flags, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ return bytes;++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for socket to become ready.+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)+ return 0;+ }+}++#if defined(ASIO_HAS_IOCP)++void complete_iocp_recvmsg(+ const weak_cancel_token_type& cancel_token,+ asio::error_code& ec)+{+ // Map non-portable errors to their portable counterparts.+ if (ec.value() == ERROR_NETNAME_DELETED)+ {+ if (cancel_token.expired())+ ec = asio::error::operation_aborted;+ else+ ec = asio::error::connection_reset;+ }+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ {+ ec = asio::error::connection_refused;+ }+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)+ {+ ec.assign(0, ec.category());+ }+}++#else // defined(ASIO_HAS_IOCP)++bool non_blocking_recvmsg(socket_type s,+ buf* bufs, size_t count, int in_flags, int& out_flags,+ asio::error_code& ec, size_t& bytes_transferred)+{+ for (;;)+ {+ // Read some data.+ signed_size_type bytes = socket_ops::recvmsg(+ s, bufs, count, in_flags, out_flags, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++#endif // defined(ASIO_HAS_IOCP)++signed_size_type send(socket_type s, const buf* bufs, size_t count,+ int flags, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ // Send the data.+ DWORD send_buf_count = static_cast<DWORD>(count);+ DWORD bytes_transferred = 0;+ DWORD send_flags = flags;+ int result = ::WSASend(s, const_cast<buf*>(bufs),+ send_buf_count, &bytes_transferred, send_flags, 0, 0);+ get_last_error(ec, true);+ if (ec.value() == ERROR_NETNAME_DELETED)+ ec = asio::error::connection_reset;+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ ec = asio::error::connection_refused;+ if (result != 0)+ return socket_error_retval;+ ec.assign(0, ec.category());+ return bytes_transferred;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ msghdr msg = msghdr();+ msg.msg_iov = const_cast<buf*>(bufs);+ msg.msg_iovlen = static_cast<int>(count);+#if defined(__linux__)+ flags |= MSG_NOSIGNAL;+#endif // defined(__linux__)+ signed_size_type result = ::sendmsg(s, &msg, flags);+ get_last_error(ec, result < 0);+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++signed_size_type send1(socket_type s, const void* data, size_t size,+ int flags, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ // Send the data.+ WSABUF buf;+ buf.buf = const_cast<char*>(static_cast<const char*>(data));+ buf.len = static_cast<ULONG>(size);+ DWORD bytes_transferred = 0;+ DWORD send_flags = flags;+ int result = ::WSASend(s, &buf, 1,+ &bytes_transferred, send_flags, 0, 0);+ get_last_error(ec, true);+ if (ec.value() == ERROR_NETNAME_DELETED)+ ec = asio::error::connection_reset;+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ ec = asio::error::connection_refused;+ if (result != 0)+ return socket_error_retval;+ ec.assign(0, ec.category());+ return bytes_transferred;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+#if defined(__linux__)+ flags |= MSG_NOSIGNAL;+#endif // defined(__linux__)+ signed_size_type result = ::send(s,+ static_cast<const char*>(data), size, flags);+ get_last_error(ec, result < 0);+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++size_t sync_send(socket_type s, state_type state, const buf* bufs,+ size_t count, int flags, bool all_empty, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // A request to write 0 bytes to a stream is a no-op.+ if (all_empty && (state & stream_oriented))+ {+ ec.assign(0, ec.category());+ return 0;+ }++ // Read some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ return bytes;++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for socket to become ready.+ if (socket_ops::poll_write(s, 0, -1, ec) < 0)+ return 0;+ }+}++size_t sync_send1(socket_type s, state_type state, const void* data,+ size_t size, int flags, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // A request to write 0 bytes to a stream is a no-op.+ if (size == 0 && (state & stream_oriented))+ {+ ec.assign(0, ec.category());+ return 0;+ }++ // Read some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ return bytes;++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for socket to become ready.+ if (socket_ops::poll_write(s, 0, -1, ec) < 0)+ return 0;+ }+}++#if defined(ASIO_HAS_IOCP)++void complete_iocp_send(+ const weak_cancel_token_type& cancel_token,+ asio::error_code& ec)+{+ // Map non-portable errors to their portable counterparts.+ if (ec.value() == ERROR_NETNAME_DELETED)+ {+ if (cancel_token.expired())+ ec = asio::error::operation_aborted;+ else+ ec = asio::error::connection_reset;+ }+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ {+ ec = asio::error::connection_refused;+ }+}++#else // defined(ASIO_HAS_IOCP)++bool non_blocking_send(socket_type s,+ const buf* bufs, size_t count, int flags,+ asio::error_code& ec, size_t& bytes_transferred)+{+ for (;;)+ {+ // Write some data.+ signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++bool non_blocking_send1(socket_type s,+ const void* data, size_t size, int flags,+ asio::error_code& ec, size_t& bytes_transferred)+{+ for (;;)+ {+ // Write some data.+ signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++#endif // defined(ASIO_HAS_IOCP)++signed_size_type sendto(socket_type s, const buf* bufs, size_t count,+ int flags, const socket_addr_type* addr, std::size_t addrlen,+ asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ // Send the data.+ DWORD send_buf_count = static_cast<DWORD>(count);+ DWORD bytes_transferred = 0;+ int result = ::WSASendTo(s, const_cast<buf*>(bufs),+ send_buf_count, &bytes_transferred, flags, addr,+ static_cast<int>(addrlen), 0, 0);+ get_last_error(ec, true);+ if (ec.value() == ERROR_NETNAME_DELETED)+ ec = asio::error::connection_reset;+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ ec = asio::error::connection_refused;+ if (result != 0)+ return socket_error_retval;+ ec.assign(0, ec.category());+ return bytes_transferred;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ msghdr msg = msghdr();+ init_msghdr_msg_name(msg.msg_name, addr);+ msg.msg_namelen = static_cast<int>(addrlen);+ msg.msg_iov = const_cast<buf*>(bufs);+ msg.msg_iovlen = static_cast<int>(count);+#if defined(__linux__)+ flags |= MSG_NOSIGNAL;+#endif // defined(__linux__)+ signed_size_type result = ::sendmsg(s, &msg, flags);+ get_last_error(ec, result < 0);+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++template <typename SockLenType>+inline signed_size_type call_sendto(SockLenType msghdr::*,+ socket_type s, const void* data, size_t size, int flags,+ const socket_addr_type* addr, std::size_t addrlen)+{+ return ::sendto(s, static_cast<char*>(const_cast<void*>(data)),+ size, flags, addr, (SockLenType)addrlen);+}++signed_size_type sendto1(socket_type s, const void* data, size_t size,+ int flags, const socket_addr_type* addr, std::size_t addrlen,+ asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ // Send the data.+ WSABUF buf;+ buf.buf = const_cast<char*>(static_cast<const char*>(data));+ buf.len = static_cast<ULONG>(size);+ DWORD bytes_transferred = 0;+ int result = ::WSASendTo(s, &buf, 1, &bytes_transferred,+ flags, addr, static_cast<int>(addrlen), 0, 0);+ get_last_error(ec, true);+ if (ec.value() == ERROR_NETNAME_DELETED)+ ec = asio::error::connection_reset;+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ ec = asio::error::connection_refused;+ if (result != 0)+ return socket_error_retval;+ ec.assign(0, ec.category());+ return bytes_transferred;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+#if defined(__linux__)+ flags |= MSG_NOSIGNAL;+#endif // defined(__linux__)+ signed_size_type result = call_sendto(&msghdr::msg_namelen,+ s, data, size, flags, addr, addrlen);+ get_last_error(ec, result < 0);+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++size_t sync_sendto(socket_type s, state_type state, const buf* bufs,+ size_t count, int flags, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // Write some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = socket_ops::sendto(+ s, bufs, count, flags, addr, addrlen, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ return bytes;++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for socket to become ready.+ if (socket_ops::poll_write(s, 0, -1, ec) < 0)+ return 0;+ }+}++size_t sync_sendto1(socket_type s, state_type state, const void* data,+ size_t size, int flags, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // Write some data.+ for (;;)+ {+ // Try to complete the operation without blocking.+ signed_size_type bytes = socket_ops::sendto1(+ s, data, size, flags, addr, addrlen, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ return bytes;++ // Operation failed.+ if ((state & user_set_non_blocking)+ || (ec != asio::error::would_block+ && ec != asio::error::try_again))+ return 0;++ // Wait for socket to become ready.+ if (socket_ops::poll_write(s, 0, -1, ec) < 0)+ return 0;+ }+}++#if !defined(ASIO_HAS_IOCP)++bool non_blocking_sendto(socket_type s,+ const buf* bufs, size_t count, int flags,+ const socket_addr_type* addr, std::size_t addrlen,+ asio::error_code& ec, size_t& bytes_transferred)+{+ for (;;)+ {+ // Write some data.+ signed_size_type bytes = socket_ops::sendto(+ s, bufs, count, flags, addr, addrlen, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++bool non_blocking_sendto1(socket_type s,+ const void* data, size_t size, int flags,+ const socket_addr_type* addr, std::size_t addrlen,+ asio::error_code& ec, size_t& bytes_transferred)+{+ for (;;)+ {+ // Write some data.+ signed_size_type bytes = socket_ops::sendto1(+ s, data, size, flags, addr, addrlen, ec);++ // Check if operation succeeded.+ if (bytes >= 0)+ {+ bytes_transferred = bytes;+ return true;+ }++ // Retry operation if interrupted by signal.+ if (ec == asio::error::interrupted)+ continue;++ // Check if we need to run the operation again.+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return false;++ // Operation failed.+ bytes_transferred = 0;+ return true;+ }+}++#endif // !defined(ASIO_HAS_IOCP)++socket_type socket(int af, int type, int protocol,+ asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ socket_type s = ::WSASocketW(af, type, protocol, 0, 0, WSA_FLAG_OVERLAPPED);+ get_last_error(ec, s == invalid_socket);+ if (s == invalid_socket)+ return s;++ if (af == ASIO_OS_DEF(AF_INET6))+ {+ // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to+ // false. This will only succeed on Windows Vista and later versions of+ // Windows, where a dual-stack IPv4/v6 implementation is available.+ DWORD optval = 0;+ ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,+ reinterpret_cast<const char*>(&optval), sizeof(optval));+ }++ return s;+#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)+ socket_type s = ::socket(af, type, protocol);+ get_last_error(ec, s < 0);++ int optval = 1;+ int result = ::setsockopt(s, SOL_SOCKET,+ SO_NOSIGPIPE, &optval, sizeof(optval));+ get_last_error(ec, result != 0);+ if (result != 0)+ {+ ::close(s);+ return invalid_socket;+ }++ return s;+#else+ int s = ::socket(af, type, protocol);+ get_last_error(ec, s < 0);+ return s;+#endif+}++template <typename SockLenType>+inline int call_setsockopt(SockLenType msghdr::*,+ socket_type s, int level, int optname,+ const void* optval, std::size_t optlen)+{+ return ::setsockopt(s, level, optname,+ (const char*)optval, (SockLenType)optlen);+}++int setsockopt(socket_type s, state_type& state, int level, int optname,+ const void* optval, std::size_t optlen, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++ if (level == custom_socket_option_level && optname == always_fail_option)+ {+ ec = asio::error::invalid_argument;+ return socket_error_retval;+ }++ if (level == custom_socket_option_level+ && optname == enable_connection_aborted_option)+ {+ if (optlen != sizeof(int))+ {+ ec = asio::error::invalid_argument;+ return socket_error_retval;+ }++ if (*static_cast<const int*>(optval))+ state |= enable_connection_aborted;+ else+ state &= ~enable_connection_aborted;+ ec.assign(0, ec.category());+ return 0;+ }++ if (level == SOL_SOCKET && optname == SO_LINGER)+ state |= user_set_linger;++#if defined(__BORLANDC__)+ // Mysteriously, using the getsockopt and setsockopt functions directly with+ // Borland C++ results in incorrect values being set and read. The bug can be+ // worked around by using function addresses resolved with GetProcAddress.+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))+ {+ typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);+ if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))+ {+ int result = sso(s, level, optname,+ reinterpret_cast<const char*>(optval),+ static_cast<int>(optlen));+ get_last_error(ec, result != 0);+ return result;+ }+ }+ ec = asio::error::fault;+ return socket_error_retval;+#else // defined(__BORLANDC__)+ int result = call_setsockopt(&msghdr::msg_namelen,+ s, level, optname, optval, optlen);+ get_last_error(ec, result != 0);+ if (result == 0)+ {+#if defined(__MACH__) && defined(__APPLE__) \+ || defined(__NetBSD__) || defined(__FreeBSD__) \+ || defined(__OpenBSD__) || defined(__QNX__)+ // To implement portable behaviour for SO_REUSEADDR with UDP sockets we+ // need to also set SO_REUSEPORT on BSD-based platforms.+ if ((state & datagram_oriented)+ && level == SOL_SOCKET && optname == SO_REUSEADDR)+ {+ call_setsockopt(&msghdr::msg_namelen, s,+ SOL_SOCKET, SO_REUSEPORT, optval, optlen);+ }+#endif+ }++ return result;+#endif // defined(__BORLANDC__)+}++template <typename SockLenType>+inline int call_getsockopt(SockLenType msghdr::*,+ socket_type s, int level, int optname,+ void* optval, std::size_t* optlen)+{+ SockLenType tmp_optlen = (SockLenType)*optlen;+ int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);+ *optlen = (std::size_t)tmp_optlen;+ return result;+}++int getsockopt(socket_type s, state_type state, int level, int optname,+ void* optval, size_t* optlen, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++ if (level == custom_socket_option_level && optname == always_fail_option)+ {+ ec = asio::error::invalid_argument;+ return socket_error_retval;+ }++ if (level == custom_socket_option_level+ && optname == enable_connection_aborted_option)+ {+ if (*optlen != sizeof(int))+ {+ ec = asio::error::invalid_argument;+ return socket_error_retval;+ }++ *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0;+ ec.assign(0, ec.category());+ return 0;+ }++#if defined(__BORLANDC__)+ // Mysteriously, using the getsockopt and setsockopt functions directly with+ // Borland C++ results in incorrect values being set and read. The bug can be+ // worked around by using function addresses resolved with GetProcAddress.+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))+ {+ typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);+ if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))+ {+ int tmp_optlen = static_cast<int>(*optlen);+ int result = gso(s, level, optname,+ reinterpret_cast<char*>(optval), &tmp_optlen);+ get_last_error(ec, result != 0);+ *optlen = static_cast<size_t>(tmp_optlen);+ if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY+ && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))+ {+ // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are+ // only supported on Windows Vista and later. To simplify program logic+ // we will fake success of getting this option and specify that the+ // value is non-zero (i.e. true). This corresponds to the behavior of+ // IPv6 sockets on Windows platforms pre-Vista.+ *static_cast<DWORD*>(optval) = 1;+ ec.assign(0, ec.category());+ }+ return result;+ }+ }+ ec = asio::error::fault;+ return socket_error_retval;+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ int result = call_getsockopt(&msghdr::msg_namelen,+ s, level, optname, optval, optlen);+ get_last_error(ec, result != 0);+ if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY+ && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))+ {+ // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only+ // supported on Windows Vista and later. To simplify program logic we will+ // fake success of getting this option and specify that the value is+ // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets+ // on Windows platforms pre-Vista.+ *static_cast<DWORD*>(optval) = 1;+ ec.assign(0, ec.category());+ }+ return result;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ int result = call_getsockopt(&msghdr::msg_namelen,+ s, level, optname, optval, optlen);+ get_last_error(ec, result != 0);+#if defined(__linux__)+ if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)+ && (optname == SO_SNDBUF || optname == SO_RCVBUF))+ {+ // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel+ // to set the buffer size to N*2. Linux puts additional stuff into the+ // buffers so that only about half is actually available to the application.+ // The retrieved value is divided by 2 here to make it appear as though the+ // correct value has been set.+ *static_cast<int*>(optval) /= 2;+ }+#endif // defined(__linux__)+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++template <typename SockLenType>+inline int call_getpeername(SockLenType msghdr::*,+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)+{+ SockLenType tmp_addrlen = (SockLenType)*addrlen;+ int result = ::getpeername(s, addr, &tmp_addrlen);+ *addrlen = (std::size_t)tmp_addrlen;+ return result;+}++int getpeername(socket_type s, socket_addr_type* addr,+ std::size_t* addrlen, bool cached, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++#if defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) \+ || defined(__CYGWIN__)+ if (cached)+ {+ // Check if socket is still connected.+ DWORD connect_time = 0;+ size_t connect_time_len = sizeof(connect_time);+ if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME,+ &connect_time, &connect_time_len, ec) == socket_error_retval)+ {+ return socket_error_retval;+ }+ if (connect_time == 0xFFFFFFFF)+ {+ ec = asio::error::not_connected;+ return socket_error_retval;+ }++ // The cached value is still valid.+ ec.assign(0, ec.category());+ return 0;+ }+#else // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP)+ // || defined(__CYGWIN__)+ (void)cached;+#endif // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP)+ // || defined(__CYGWIN__)++ int result = call_getpeername(&msghdr::msg_namelen, s, addr, addrlen);+ get_last_error(ec, result != 0);+ return result;+}++template <typename SockLenType>+inline int call_getsockname(SockLenType msghdr::*,+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)+{+ SockLenType tmp_addrlen = (SockLenType)*addrlen;+ int result = ::getsockname(s, addr, &tmp_addrlen);+ *addrlen = (std::size_t)tmp_addrlen;+ return result;+}++int getsockname(socket_type s, socket_addr_type* addr,+ std::size_t* addrlen, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++ int result = call_getsockname(&msghdr::msg_namelen, s, addr, addrlen);+ get_last_error(ec, result != 0);+ return result;+}++int ioctl(socket_type s, state_type& state, int cmd,+ ioctl_arg_type* arg, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ int result = ::ioctlsocket(s, cmd, arg);+#elif defined(__MACH__) && defined(__APPLE__) \+ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)+ int result = ::ioctl(s, static_cast<unsigned int>(cmd), arg);+#else+ int result = ::ioctl(s, cmd, arg);+#endif+ get_last_error(ec, result < 0);+ if (result >= 0)+ {+ // When updating the non-blocking mode we always perform the ioctl syscall,+ // even if the flags would otherwise indicate that the socket is already in+ // the correct state. This ensures that the underlying socket is put into+ // the state that has been requested by the user. If the ioctl syscall was+ // successful then we need to update the flags to match.+ if (cmd == static_cast<int>(FIONBIO))+ {+ if (*arg)+ {+ state |= user_set_non_blocking;+ }+ else+ {+ // Clearing the non-blocking mode always overrides any internally-set+ // non-blocking flag. Any subsequent asynchronous operations will need+ // to re-enable non-blocking I/O.+ state &= ~(user_set_non_blocking | internal_non_blocking);+ }+ }+ }++ return result;+}++int select(int nfds, fd_set* readfds, fd_set* writefds,+ fd_set* exceptfds, timeval* timeout, asio::error_code& ec)+{+#if defined(__EMSCRIPTEN__)+ exceptfds = 0;+#endif // defined(__EMSCRIPTEN__)+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ if (!readfds && !writefds && !exceptfds && timeout)+ {+ DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;+ if (milliseconds == 0)+ milliseconds = 1; // Force context switch.+ ::Sleep(milliseconds);+ ec.assign(0, ec.category());+ return 0;+ }++ // The select() call allows timeout values measured in microseconds, but the+ // system clock (as wrapped by boost::posix_time::microsec_clock) typically+ // has a resolution of 10 milliseconds. This can lead to a spinning select+ // reactor, meaning increased CPU usage, when waiting for the earliest+ // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight+ // spin we'll use a minimum timeout of 1 millisecond.+ if (timeout && timeout->tv_sec == 0+ && timeout->tv_usec > 0 && timeout->tv_usec < 1000)+ timeout->tv_usec = 1000;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++#if defined(__hpux) && defined(__SELECT)+ timespec ts;+ ts.tv_sec = timeout ? timeout->tv_sec : 0;+ ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;+ int result = ::pselect(nfds, readfds,+ writefds, exceptfds, timeout ? &ts : 0, 0);+#else+ int result = ::select(nfds, readfds, writefds, exceptfds, timeout);+#endif+ get_last_error(ec, result < 0);+ return result;+}++int poll_read(socket_type s, state_type state,+ int msec, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++#if defined(ASIO_WINDOWS) \+ || defined(__CYGWIN__) \+ || defined(__SYMBIAN32__)+ fd_set fds;+ FD_ZERO(&fds);+ FD_SET(s, &fds);+ timeval timeout_obj;+ timeval* timeout;+ if (state & user_set_non_blocking)+ {+ timeout_obj.tv_sec = 0;+ timeout_obj.tv_usec = 0;+ timeout = &timeout_obj;+ }+ else if (msec >= 0)+ {+ timeout_obj.tv_sec = msec / 1000;+ timeout_obj.tv_usec = (msec % 1000) * 1000;+ timeout = &timeout_obj;+ }+ else+ timeout = 0;+ int result = ::select(s + 1, &fds, 0, 0, timeout);+ get_last_error(ec, result < 0);+#else // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)+ pollfd fds;+ fds.fd = s;+ fds.events = POLLIN;+ fds.revents = 0;+ int timeout = (state & user_set_non_blocking) ? 0 : msec;+ int result = ::poll(&fds, 1, timeout);+ get_last_error(ec, result < 0);+#endif // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)+ if (result == 0)+ if (state & user_set_non_blocking)+ ec = asio::error::would_block;+ return result;+}++int poll_write(socket_type s, state_type state,+ int msec, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++#if defined(ASIO_WINDOWS) \+ || defined(__CYGWIN__) \+ || defined(__SYMBIAN32__)+ fd_set fds;+ FD_ZERO(&fds);+ FD_SET(s, &fds);+ timeval timeout_obj;+ timeval* timeout;+ if (state & user_set_non_blocking)+ {+ timeout_obj.tv_sec = 0;+ timeout_obj.tv_usec = 0;+ timeout = &timeout_obj;+ }+ else if (msec >= 0)+ {+ timeout_obj.tv_sec = msec / 1000;+ timeout_obj.tv_usec = (msec % 1000) * 1000;+ timeout = &timeout_obj;+ }+ else+ timeout = 0;+ int result = ::select(s + 1, 0, &fds, 0, timeout);+ get_last_error(ec, result < 0);+#else // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)+ pollfd fds;+ fds.fd = s;+ fds.events = POLLOUT;+ fds.revents = 0;+ int timeout = (state & user_set_non_blocking) ? 0 : msec;+ int result = ::poll(&fds, 1, timeout);+ get_last_error(ec, result < 0);+#endif // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)+ if (result == 0)+ if (state & user_set_non_blocking)+ ec = asio::error::would_block;+ return result;+}++int poll_error(socket_type s, state_type state,+ int msec, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++#if defined(ASIO_WINDOWS) \+ || defined(__CYGWIN__) \+ || defined(__SYMBIAN32__)+ fd_set fds;+ FD_ZERO(&fds);+ FD_SET(s, &fds);+ timeval timeout_obj;+ timeval* timeout;+ if (state & user_set_non_blocking)+ {+ timeout_obj.tv_sec = 0;+ timeout_obj.tv_usec = 0;+ timeout = &timeout_obj;+ }+ else if (msec >= 0)+ {+ timeout_obj.tv_sec = msec / 1000;+ timeout_obj.tv_usec = (msec % 1000) * 1000;+ timeout = &timeout_obj;+ }+ else+ timeout = 0;+ int result = ::select(s + 1, 0, 0, &fds, timeout);+ get_last_error(ec, result < 0);+#else // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)+ pollfd fds;+ fds.fd = s;+ fds.events = POLLPRI | POLLERR | POLLHUP;+ fds.revents = 0;+ int timeout = (state & user_set_non_blocking) ? 0 : msec;+ int result = ::poll(&fds, 1, timeout);+ get_last_error(ec, result < 0);+#endif // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)+ if (result == 0)+ if (state & user_set_non_blocking)+ ec = asio::error::would_block;+ return result;+}++int poll_connect(socket_type s, int msec, asio::error_code& ec)+{+ if (s == invalid_socket)+ {+ ec = asio::error::bad_descriptor;+ return socket_error_retval;+ }++#if defined(ASIO_WINDOWS) \+ || defined(__CYGWIN__) \+ || defined(__SYMBIAN32__)+ fd_set write_fds;+ FD_ZERO(&write_fds);+ FD_SET(s, &write_fds);+ fd_set except_fds;+ FD_ZERO(&except_fds);+ FD_SET(s, &except_fds);+ timeval timeout_obj;+ timeval* timeout;+ if (msec >= 0)+ {+ timeout_obj.tv_sec = msec / 1000;+ timeout_obj.tv_usec = (msec % 1000) * 1000;+ timeout = &timeout_obj;+ }+ else+ timeout = 0;+ int result = ::select(s + 1, 0, &write_fds, &except_fds, timeout);+ get_last_error(ec, result < 0);+ return result;+#else // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)+ pollfd fds;+ fds.fd = s;+ fds.events = POLLOUT;+ fds.revents = 0;+ int result = ::poll(&fds, 1, msec);+ get_last_error(ec, result < 0);+ return result;+#endif // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)+}++#endif // !defined(ASIO_WINDOWS_RUNTIME)++const char* inet_ntop(int af, const void* src, char* dest, size_t length,+ unsigned long scope_id, asio::error_code& ec)+{+ clear_last_error();+#if defined(ASIO_WINDOWS_RUNTIME)+ using namespace std; // For sprintf.+ const unsigned char* bytes = static_cast<const unsigned char*>(src);+ if (af == ASIO_OS_DEF(AF_INET))+ {+ sprintf_s(dest, length, "%u.%u.%u.%u",+ bytes[0], bytes[1], bytes[2], bytes[3]);+ return dest;+ }+ else if (af == ASIO_OS_DEF(AF_INET6))+ {+ size_t n = 0, b = 0, z = 0;+ while (n < length && b < 16)+ {+ if (bytes[b] == 0 && bytes[b + 1] == 0 && z == 0)+ {+ do b += 2; while (b < 16 && bytes[b] == 0 && bytes[b + 1] == 0);+ n += sprintf_s(dest + n, length - n, ":%s", b < 16 ? "" : ":"), ++z;+ }+ else+ {+ n += sprintf_s(dest + n, length - n, "%s%x", b ? ":" : "",+ (static_cast<u_long_type>(bytes[b]) << 8) | bytes[b + 1]);+ b += 2;+ }+ }+ if (scope_id)+ n += sprintf_s(dest + n, length - n, "%%%lu", scope_id);+ return dest;+ }+ else+ {+ ec = asio::error::address_family_not_supported;+ return 0;+ }+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ using namespace std; // For memcpy.++ if (af != ASIO_OS_DEF(AF_INET) && af != ASIO_OS_DEF(AF_INET6))+ {+ ec = asio::error::address_family_not_supported;+ return 0;+ }++ union+ {+ socket_addr_type base;+ sockaddr_storage_type storage;+ sockaddr_in4_type v4;+ sockaddr_in6_type v6;+ } address;+ DWORD address_length;+ if (af == ASIO_OS_DEF(AF_INET))+ {+ address_length = sizeof(sockaddr_in4_type);+ address.v4.sin_family = ASIO_OS_DEF(AF_INET);+ address.v4.sin_port = 0;+ memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type));+ }+ else // AF_INET6+ {+ address_length = sizeof(sockaddr_in6_type);+ address.v6.sin6_family = ASIO_OS_DEF(AF_INET6);+ address.v6.sin6_port = 0;+ address.v6.sin6_flowinfo = 0;+ address.v6.sin6_scope_id = scope_id;+ memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type));+ }++ DWORD string_length = static_cast<DWORD>(length);+#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800))+ LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));+ int result = ::WSAAddressToStringW(&address.base,+ address_length, 0, string_buffer, &string_length);+ get_last_error(ec, true);+ ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1,+ dest, static_cast<int>(length), 0, 0);+#else+ int result = ::WSAAddressToStringA(&address.base,+ address_length, 0, dest, &string_length);+ get_last_error(ec, true);+#endif++ // Windows may set error code on success.+ if (result != socket_error_retval)+ ec.assign(0, ec.category());++ // Windows may not set an error code on failure.+ else if (result == socket_error_retval && !ec)+ ec = asio::error::invalid_argument;++ return result == socket_error_retval ? 0 : dest;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ const char* result = ::inet_ntop(af, src, dest, static_cast<int>(length));+ get_last_error(ec, true);+ if (result == 0 && !ec)+ ec = asio::error::invalid_argument;+ if (result != 0 && af == ASIO_OS_DEF(AF_INET6) && scope_id != 0)+ {+ using namespace std; // For strcat and sprintf.+ char if_name[(IF_NAMESIZE > 21 ? IF_NAMESIZE : 21) + 1] = "%";+ const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);+ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe)+ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80));+ bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff)+ && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02));+ if ((!is_link_local && !is_multicast_link_local)+ || if_indextoname(static_cast<unsigned>(scope_id), if_name + 1) == 0)+ sprintf(if_name + 1, "%lu", scope_id);+ strcat(dest, if_name);+ }+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++int inet_pton(int af, const char* src, void* dest,+ unsigned long* scope_id, asio::error_code& ec)+{+ clear_last_error();+#if defined(ASIO_WINDOWS_RUNTIME)+ using namespace std; // For sscanf.+ unsigned char* bytes = static_cast<unsigned char*>(dest);+ if (af == ASIO_OS_DEF(AF_INET))+ {+ unsigned int b0, b1, b2, b3;+ if (sscanf_s(src, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) != 4)+ {+ ec = asio::error::invalid_argument;+ return -1;+ }+ if (b0 > 255 || b1 > 255 || b2 > 255 || b3 > 255)+ {+ ec = asio::error::invalid_argument;+ return -1;+ }+ bytes[0] = static_cast<unsigned char>(b0);+ bytes[1] = static_cast<unsigned char>(b1);+ bytes[2] = static_cast<unsigned char>(b2);+ bytes[3] = static_cast<unsigned char>(b3);+ ec.assign(), ec.category());+ return 1;+ }+ else if (af == ASIO_OS_DEF(AF_INET6))+ {+ unsigned char* bytes = static_cast<unsigned char*>(dest);+ std::memset(bytes, 0, 16);+ unsigned char back_bytes[16] = { 0 };+ int num_front_bytes = 0, num_back_bytes = 0;+ const char* p = src;++ enum { fword, fcolon, bword, scope, done } state = fword;+ unsigned long current_word = 0;+ while (state != done)+ {+ if (current_word > 0xFFFF)+ {+ ec = asio::error::invalid_argument;+ return -1;+ }++ switch (state)+ {+ case fword:+ if (*p >= '0' && *p <= '9')+ current_word = current_word * 16 + *p++ - '0';+ else if (*p >= 'a' && *p <= 'f')+ current_word = current_word * 16 + *p++ - 'a' + 10;+ else if (*p >= 'A' && *p <= 'F')+ current_word = current_word * 16 + *p++ - 'A' + 10;+ else+ {+ if (num_front_bytes == 16)+ {+ ec = asio::error::invalid_argument;+ return -1;+ }++ bytes[num_front_bytes++] = (current_word >> 8) & 0xFF;+ bytes[num_front_bytes++] = current_word & 0xFF;+ current_word = 0;++ if (*p == ':')+ state = fcolon, ++p;+ else if (*p == '%')+ state = scope, ++p;+ else if (*p == 0)+ state = done;+ else+ {+ ec = asio::error::invalid_argument;+ return -1;+ }+ }+ break;++ case fcolon:+ if (*p == ':')+ state = bword, ++p;+ else+ state = fword;+ break;++ case bword:+ if (*p >= '0' && *p <= '9')+ current_word = current_word * 16 + *p++ - '0';+ else if (*p >= 'a' && *p <= 'f')+ current_word = current_word * 16 + *p++ - 'a' + 10;+ else if (*p >= 'A' && *p <= 'F')+ current_word = current_word * 16 + *p++ - 'A' + 10;+ else+ {+ if (num_front_bytes + num_back_bytes == 16)+ {+ ec = asio::error::invalid_argument;+ return -1;+ }++ back_bytes[num_back_bytes++] = (current_word >> 8) & 0xFF;+ back_bytes[num_back_bytes++] = current_word & 0xFF;+ current_word = 0;++ if (*p == ':')+ state = bword, ++p;+ else if (*p == '%')+ state = scope, ++p;+ else if (*p == 0)+ state = done;+ else+ {+ ec = asio::error::invalid_argument;+ return -1;+ }+ }+ break;++ case scope:+ if (*p >= '0' && *p <= '9')+ current_word = current_word * 10 + *p++ - '0';+ else if (*p == 0)+ *scope_id = current_word, state = done;+ else+ {+ ec = asio::error::invalid_argument;+ return -1;+ }+ break;++ default:+ break;+ }+ }++ for (int i = 0; i < num_back_bytes; ++i)+ bytes[16 - num_back_bytes + i] = back_bytes[i];++ ec.assign(0, ec.category());+ return 1;+ }+ else+ {+ ec = asio::error::address_family_not_supported;+ return -1;+ }+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ using namespace std; // For memcpy and strcmp.++ if (af != ASIO_OS_DEF(AF_INET) && af != ASIO_OS_DEF(AF_INET6))+ {+ ec = asio::error::address_family_not_supported;+ return -1;+ }++ union+ {+ socket_addr_type base;+ sockaddr_storage_type storage;+ sockaddr_in4_type v4;+ sockaddr_in6_type v6;+ } address;+ int address_length = sizeof(sockaddr_storage_type);+#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800))+ int num_wide_chars = static_cast<int>(strlen(src)) + 1;+ LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));+ ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);+ int result = ::WSAStringToAddressW(wide_buffer,+ af, 0, &address.base, &address_length);+ get_last_error(ec, true);+#else+ int result = ::WSAStringToAddressA(const_cast<char*>(src),+ af, 0, &address.base, &address_length);+ get_last_error(ec, true);+#endif++ if (af == ASIO_OS_DEF(AF_INET))+ {+ if (result != socket_error_retval)+ {+ memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));+ ec.assign(0, ec.category());+ }+ else if (strcmp(src, "255.255.255.255") == 0)+ {+ static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;+ ec.assign(0, ec.category());+ }+ }+ else // AF_INET6+ {+ if (result != socket_error_retval)+ {+ memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));+ if (scope_id)+ *scope_id = address.v6.sin6_scope_id;+ ec.assign(0, ec.category());+ }+ }++ // Windows may not set an error code on failure.+ if (result == socket_error_retval && !ec)+ ec = asio::error::invalid_argument;++ if (result != socket_error_retval)+ ec.assign(0, ec.category());++ return result == socket_error_retval ? -1 : 1;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ using namespace std; // For strchr, memcpy and atoi.++ // On some platforms, inet_pton fails if an address string contains a scope+ // id. Detect and remove the scope id before passing the string to inet_pton.+ const bool is_v6 = (af == ASIO_OS_DEF(AF_INET6));+ const char* if_name = is_v6 ? strchr(src, '%') : 0;+ char src_buf[max_addr_v6_str_len + 1];+ const char* src_ptr = src;+ if (if_name != 0)+ {+ if (if_name - src > max_addr_v6_str_len)+ {+ ec = asio::error::invalid_argument;+ return 0;+ }+ memcpy(src_buf, src, if_name - src);+ src_buf[if_name - src] = 0;+ src_ptr = src_buf;+ }++ int result = ::inet_pton(af, src_ptr, dest);+ get_last_error(ec, true);+ if (result <= 0 && !ec)+ ec = asio::error::invalid_argument;+ if (result > 0 && is_v6 && scope_id)+ {+ using namespace std; // For strchr and atoi.+ *scope_id = 0;+ if (if_name != 0)+ {+ in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);+ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe)+ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80));+ bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff)+ && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02));+ if (is_link_local || is_multicast_link_local)+ *scope_id = if_nametoindex(if_name + 1);+ if (*scope_id == 0)+ *scope_id = atoi(if_name + 1);+ }+ }+ return result;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+}++int gethostname(char* name, int namelen, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS_RUNTIME)+ try+ {+ using namespace Windows::Foundation::Collections;+ using namespace Windows::Networking;+ using namespace Windows::Networking::Connectivity;+ IVectorView<HostName^>^ hostnames = NetworkInformation::GetHostNames();+ for (unsigned i = 0; i < hostnames->Size; ++i)+ {+ HostName^ hostname = hostnames->GetAt(i);+ if (hostname->Type == HostNameType::DomainName)+ {+ std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;+ std::string raw_name = converter.to_bytes(hostname->RawName->Data());+ if (namelen > 0 && raw_name.size() < static_cast<std::size_t>(namelen))+ {+ strcpy_s(name, namelen, raw_name.c_str());+ return 0;+ }+ }+ }+ return -1;+ }+ catch (Platform::Exception^ e)+ {+ ec = asio::error_code(e->HResult,+ asio::system_category());+ return -1;+ }+#else // defined(ASIO_WINDOWS_RUNTIME)+ int result = ::gethostname(name, namelen);+ get_last_error(ec, result != 0);+ return result;+#endif // defined(ASIO_WINDOWS_RUNTIME)+}++#if !defined(ASIO_WINDOWS_RUNTIME)++#if !defined(ASIO_HAS_GETADDRINFO)++// The following functions are only needed for emulation of getaddrinfo and+// getnameinfo.++inline asio::error_code translate_netdb_error(int error)+{+ switch (error)+ {+ case 0:+ return asio::error_code();+ case HOST_NOT_FOUND:+ return asio::error::host_not_found;+ case TRY_AGAIN:+ return asio::error::host_not_found_try_again;+ case NO_RECOVERY:+ return asio::error::no_recovery;+ case NO_DATA:+ return asio::error::no_data;+ default:+ ASIO_ASSERT(false);+ return asio::error::invalid_argument;+ }+}++inline hostent* gethostbyaddr(const char* addr, int length, int af,+ hostent* result, char* buffer, int buflength, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ (void)(buffer);+ (void)(buflength);+ hostent* retval = ::gethostbyaddr(addr, length, af);+ get_last_error(ec, !retval);+ if (!retval)+ return 0;+ *result = *retval;+ return retval;+#elif defined(__sun) || defined(__QNX__)+ int error = 0;+ hostent* retval = ::gethostbyaddr_r(addr, length,+ af, result, buffer, buflength, &error);+ get_last_error(ec, !retval);+ if (error)+ ec = translate_netdb_error(error);+ return retval;+#elif defined(__MACH__) && defined(__APPLE__)+ (void)(buffer);+ (void)(buflength);+ int error = 0;+ hostent* retval = ::getipnodebyaddr(addr, length, af, &error);+ get_last_error(ec, !retval);+ if (error)+ ec = translate_netdb_error(error);+ if (!retval)+ return 0;+ *result = *retval;+ return retval;+#else+ hostent* retval = 0;+ int error = 0;+ clear_last_error();+ ::gethostbyaddr_r(addr, length, af, result,+ buffer, buflength, &retval, &error);+ get_last_error(ec, true);+ if (error)+ ec = translate_netdb_error(error);+ return retval;+#endif+}++inline hostent* gethostbyname(const char* name, int af, struct hostent* result,+ char* buffer, int buflength, int ai_flags, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ (void)(buffer);+ (void)(buflength);+ (void)(ai_flags);+ if (af != ASIO_OS_DEF(AF_INET))+ {+ ec = asio::error::address_family_not_supported;+ return 0;+ }+ hostent* retval = ::gethostbyname(name);+ get_last_error(ec, !retval);+ if (!retval)+ return 0;+ *result = *retval;+ return result;+#elif defined(__sun) || defined(__QNX__)+ (void)(ai_flags);+ if (af != ASIO_OS_DEF(AF_INET))+ {+ ec = asio::error::address_family_not_supported;+ return 0;+ }+ int error = 0;+ hostent* retval = ::gethostbyname_r(name, result, buffer, buflength, &error);+ get_last_error(ec, !retval);+ if (error)+ ec = translate_netdb_error(error);+ return retval;+#elif defined(__MACH__) && defined(__APPLE__)+ (void)(buffer);+ (void)(buflength);+ int error = 0;+ hostent* retval = ::getipnodebyname(name, af, ai_flags, &error);+ get_last_error(ec, !retval);+ if (error)+ ec = translate_netdb_error(error);+ if (!retval)+ return 0;+ *result = *retval;+ return retval;+#else+ (void)(ai_flags);+ if (af != ASIO_OS_DEF(AF_INET))+ {+ ec = asio::error::address_family_not_supported;+ return 0;+ }+ hostent* retval = 0;+ int error = 0;+ clear_last_error();+ ::gethostbyname_r(name, result, buffer, buflength, &retval, &error);+ get_last_error(ec, true);+ if (error)+ ec = translate_netdb_error(error);+ return retval;+#endif+}++inline void freehostent(hostent* h)+{+#if defined(__MACH__) && defined(__APPLE__)+ if (h)+ ::freehostent(h);+#else+ (void)(h);+#endif+}++// Emulation of getaddrinfo based on implementation in:+// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998.++struct gai_search+{+ const char* host;+ int family;+};++inline int gai_nsearch(const char* host,+ const addrinfo_type* hints, gai_search (&search)[2])+{+ int search_count = 0;+ if (host == 0 || host[0] == '\0')+ {+ if (hints->ai_flags & AI_PASSIVE)+ {+ // No host and AI_PASSIVE implies wildcard bind.+ switch (hints->ai_family)+ {+ case ASIO_OS_DEF(AF_INET):+ search[search_count].host = "0.0.0.0";+ search[search_count].family = ASIO_OS_DEF(AF_INET);+ ++search_count;+ break;+ case ASIO_OS_DEF(AF_INET6):+ search[search_count].host = "0::0";+ search[search_count].family = ASIO_OS_DEF(AF_INET6);+ ++search_count;+ break;+ case ASIO_OS_DEF(AF_UNSPEC):+ search[search_count].host = "0::0";+ search[search_count].family = ASIO_OS_DEF(AF_INET6);+ ++search_count;+ search[search_count].host = "0.0.0.0";+ search[search_count].family = ASIO_OS_DEF(AF_INET);+ ++search_count;+ break;+ default:+ break;+ }+ }+ else+ {+ // No host and not AI_PASSIVE means connect to local host.+ switch (hints->ai_family)+ {+ case ASIO_OS_DEF(AF_INET):+ search[search_count].host = "localhost";+ search[search_count].family = ASIO_OS_DEF(AF_INET);+ ++search_count;+ break;+ case ASIO_OS_DEF(AF_INET6):+ search[search_count].host = "localhost";+ search[search_count].family = ASIO_OS_DEF(AF_INET6);+ ++search_count;+ break;+ case ASIO_OS_DEF(AF_UNSPEC):+ search[search_count].host = "localhost";+ search[search_count].family = ASIO_OS_DEF(AF_INET6);+ ++search_count;+ search[search_count].host = "localhost";+ search[search_count].family = ASIO_OS_DEF(AF_INET);+ ++search_count;+ break;+ default:+ break;+ }+ }+ }+ else+ {+ // Host is specified.+ switch (hints->ai_family)+ {+ case ASIO_OS_DEF(AF_INET):+ search[search_count].host = host;+ search[search_count].family = ASIO_OS_DEF(AF_INET);+ ++search_count;+ break;+ case ASIO_OS_DEF(AF_INET6):+ search[search_count].host = host;+ search[search_count].family = ASIO_OS_DEF(AF_INET6);+ ++search_count;+ break;+ case ASIO_OS_DEF(AF_UNSPEC):+ search[search_count].host = host;+ search[search_count].family = ASIO_OS_DEF(AF_INET6);+ ++search_count;+ search[search_count].host = host;+ search[search_count].family = ASIO_OS_DEF(AF_INET);+ ++search_count;+ break;+ default:+ break;+ }+ }+ return search_count;+}++template <typename T>+inline T* gai_alloc(std::size_t size = sizeof(T))+{+ using namespace std;+ T* p = static_cast<T*>(::operator new(size, std::nothrow));+ if (p)+ memset(p, 0, size);+ return p;+}++inline void gai_free(void* p)+{+ ::operator delete(p);+}++inline void gai_strcpy(char* target, const char* source, std::size_t max_size)+{+ using namespace std;+#if defined(ASIO_HAS_SECURE_RTL)+ strcpy_s(target, max_size, source);+#else // defined(ASIO_HAS_SECURE_RTL)+ *target = 0;+ if (max_size > 0)+ strncat(target, source, max_size - 1);+#endif // defined(ASIO_HAS_SECURE_RTL)+}++enum { gai_clone_flag = 1 << 30 };++inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,+ const void* addr, int family)+{+ using namespace std;++ addrinfo_type* ai = gai_alloc<addrinfo_type>();+ if (ai == 0)+ return EAI_MEMORY;++ ai->ai_next = 0;+ **next = ai;+ *next = &ai->ai_next;++ ai->ai_canonname = 0;+ ai->ai_socktype = hints->ai_socktype;+ if (ai->ai_socktype == 0)+ ai->ai_flags |= gai_clone_flag;+ ai->ai_protocol = hints->ai_protocol;+ ai->ai_family = family;++ switch (ai->ai_family)+ {+ case ASIO_OS_DEF(AF_INET):+ {+ sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();+ if (sinptr == 0)+ return EAI_MEMORY;+ sinptr->sin_family = ASIO_OS_DEF(AF_INET);+ memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));+ ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);+ ai->ai_addrlen = sizeof(sockaddr_in4_type);+ break;+ }+ case ASIO_OS_DEF(AF_INET6):+ {+ sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();+ if (sin6ptr == 0)+ return EAI_MEMORY;+ sin6ptr->sin6_family = ASIO_OS_DEF(AF_INET6);+ memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));+ ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);+ ai->ai_addrlen = sizeof(sockaddr_in6_type);+ break;+ }+ default:+ break;+ }++ return 0;+}++inline addrinfo_type* gai_clone(addrinfo_type* ai)+{+ using namespace std;++ addrinfo_type* new_ai = gai_alloc<addrinfo_type>();+ if (new_ai == 0)+ return new_ai;++ new_ai->ai_next = ai->ai_next;+ ai->ai_next = new_ai;++ new_ai->ai_flags = 0;+ new_ai->ai_family = ai->ai_family;+ new_ai->ai_socktype = ai->ai_socktype;+ new_ai->ai_protocol = ai->ai_protocol;+ new_ai->ai_canonname = 0;+ new_ai->ai_addrlen = ai->ai_addrlen;+ new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);+ memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);++ return new_ai;+}++inline int gai_port(addrinfo_type* aihead, int port, int socktype)+{+ int num_found = 0;++ for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)+ {+ if (ai->ai_flags & gai_clone_flag)+ {+ if (ai->ai_socktype != 0)+ {+ ai = gai_clone(ai);+ if (ai == 0)+ return -1;+ // ai now points to newly cloned entry.+ }+ }+ else if (ai->ai_socktype != socktype)+ {+ // Ignore if mismatch on socket type.+ continue;+ }++ ai->ai_socktype = socktype;++ switch (ai->ai_family)+ {+ case ASIO_OS_DEF(AF_INET):+ {+ sockaddr_in4_type* sinptr =+ reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);+ sinptr->sin_port = port;+ ++num_found;+ break;+ }+ case ASIO_OS_DEF(AF_INET6):+ {+ sockaddr_in6_type* sin6ptr =+ reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);+ sin6ptr->sin6_port = port;+ ++num_found;+ break;+ }+ default:+ break;+ }+ }++ return num_found;+}++inline int gai_serv(addrinfo_type* aihead,+ const addrinfo_type* hints, const char* serv)+{+ using namespace std;++ int num_found = 0;++ if (+#if defined(AI_NUMERICSERV)+ (hints->ai_flags & AI_NUMERICSERV) ||+#endif+ isdigit(static_cast<unsigned char>(serv[0])))+ {+ int port = htons(atoi(serv));+ if (hints->ai_socktype)+ {+ // Caller specifies socket type.+ int rc = gai_port(aihead, port, hints->ai_socktype);+ if (rc < 0)+ return EAI_MEMORY;+ num_found += rc;+ }+ else+ {+ // Caller does not specify socket type.+ int rc = gai_port(aihead, port, SOCK_STREAM);+ if (rc < 0)+ return EAI_MEMORY;+ num_found += rc;+ rc = gai_port(aihead, port, SOCK_DGRAM);+ if (rc < 0)+ return EAI_MEMORY;+ num_found += rc;+ }+ }+ else+ {+ // Try service name with TCP first, then UDP.+ if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM)+ {+ servent* sptr = getservbyname(serv, "tcp");+ if (sptr != 0)+ {+ int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM);+ if (rc < 0)+ return EAI_MEMORY;+ num_found += rc;+ }+ }+ if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM)+ {+ servent* sptr = getservbyname(serv, "udp");+ if (sptr != 0)+ {+ int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM);+ if (rc < 0)+ return EAI_MEMORY;+ num_found += rc;+ }+ }+ }++ if (num_found == 0)+ {+ if (hints->ai_socktype == 0)+ {+ // All calls to getservbyname() failed.+ return EAI_NONAME;+ }+ else+ {+ // Service not supported for socket type.+ return EAI_SERVICE;+ }+ }++ return 0;+}++inline int gai_echeck(const char* host, const char* service,+ int flags, int family, int socktype, int protocol)+{+ (void)(flags);+ (void)(protocol);++ // Host or service must be specified.+ if (host == 0 || host[0] == '\0')+ if (service == 0 || service[0] == '\0')+ return EAI_NONAME;++ // Check combination of family and socket type.+ switch (family)+ {+ case ASIO_OS_DEF(AF_UNSPEC):+ break;+ case ASIO_OS_DEF(AF_INET):+ case ASIO_OS_DEF(AF_INET6):+ if (service != 0 && service[0] != '\0')+ if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)+ return EAI_SOCKTYPE;+ break;+ default:+ return EAI_FAMILY;+ }++ return 0;+}++inline void freeaddrinfo_emulation(addrinfo_type* aihead)+{+ addrinfo_type* ai = aihead;+ while (ai)+ {+ gai_free(ai->ai_addr);+ gai_free(ai->ai_canonname);+ addrinfo_type* ainext = ai->ai_next;+ gai_free(ai);+ ai = ainext;+ }+}++inline int getaddrinfo_emulation(const char* host, const char* service,+ const addrinfo_type* hintsp, addrinfo_type** result)+{+ // Set up linked list of addrinfo structures.+ addrinfo_type* aihead = 0;+ addrinfo_type** ainext = &aihead;+ char* canon = 0;++ // Supply default hints if not specified by caller.+ addrinfo_type hints = addrinfo_type();+ hints.ai_family = ASIO_OS_DEF(AF_UNSPEC);+ if (hintsp)+ hints = *hintsp;++ // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED+ // and AI_ALL flags.+#if defined(AI_V4MAPPED)+ if (hints.ai_family != ASIO_OS_DEF(AF_INET6))+ hints.ai_flags &= ~AI_V4MAPPED;+#endif+#if defined(AI_ALL)+ if (hints.ai_family != ASIO_OS_DEF(AF_INET6))+ hints.ai_flags &= ~AI_ALL;+#endif++ // Basic error checking.+ int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,+ hints.ai_socktype, hints.ai_protocol);+ if (rc != 0)+ {+ freeaddrinfo_emulation(aihead);+ return rc;+ }++ gai_search search[2];+ int search_count = gai_nsearch(host, &hints, search);+ for (gai_search* sptr = search; sptr < search + search_count; ++sptr)+ {+ // Check for IPv4 dotted decimal string.+ in4_addr_type inaddr;+ asio::error_code ec;+ if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET),+ sptr->host, &inaddr, 0, ec) == 1)+ {+ if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)+ && hints.ai_family != ASIO_OS_DEF(AF_INET))+ {+ freeaddrinfo_emulation(aihead);+ gai_free(canon);+ return EAI_FAMILY;+ }+ if (sptr->family == ASIO_OS_DEF(AF_INET))+ {+ rc = gai_aistruct(&ainext, &hints, &inaddr, ASIO_OS_DEF(AF_INET));+ if (rc != 0)+ {+ freeaddrinfo_emulation(aihead);+ gai_free(canon);+ return rc;+ }+ }+ continue;+ }++ // Check for IPv6 hex string.+ in6_addr_type in6addr;+ if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6),+ sptr->host, &in6addr, 0, ec) == 1)+ {+ if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)+ && hints.ai_family != ASIO_OS_DEF(AF_INET6))+ {+ freeaddrinfo_emulation(aihead);+ gai_free(canon);+ return EAI_FAMILY;+ }+ if (sptr->family == ASIO_OS_DEF(AF_INET6))+ {+ rc = gai_aistruct(&ainext, &hints, &in6addr,+ ASIO_OS_DEF(AF_INET6));+ if (rc != 0)+ {+ freeaddrinfo_emulation(aihead);+ gai_free(canon);+ return rc;+ }+ }+ continue;+ }++ // Look up hostname.+ hostent hent;+ char hbuf[8192] = "";+ hostent* hptr = socket_ops::gethostbyname(sptr->host,+ sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);+ if (hptr == 0)+ {+ if (search_count == 2)+ {+ // Failure is OK if there are multiple searches.+ continue;+ }+ freeaddrinfo_emulation(aihead);+ gai_free(canon);+ if (ec == asio::error::host_not_found)+ return EAI_NONAME;+ if (ec == asio::error::host_not_found_try_again)+ return EAI_AGAIN;+ if (ec == asio::error::no_recovery)+ return EAI_FAIL;+ if (ec == asio::error::no_data)+ return EAI_NONAME;+ return EAI_NONAME;+ }++ // Check for address family mismatch if one was specified.+ if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)+ && hints.ai_family != hptr->h_addrtype)+ {+ freeaddrinfo_emulation(aihead);+ gai_free(canon);+ socket_ops::freehostent(hptr);+ return EAI_FAMILY;+ }++ // Save canonical name first time.+ if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]+ && (hints.ai_flags & AI_CANONNAME) && canon == 0)+ {+ std::size_t canon_len = strlen(hptr->h_name) + 1;+ canon = gai_alloc<char>(canon_len);+ if (canon == 0)+ {+ freeaddrinfo_emulation(aihead);+ socket_ops::freehostent(hptr);+ return EAI_MEMORY;+ }+ gai_strcpy(canon, hptr->h_name, canon_len);+ }++ // Create an addrinfo structure for each returned address.+ for (char** ap = hptr->h_addr_list; *ap; ++ap)+ {+ rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);+ if (rc != 0)+ {+ freeaddrinfo_emulation(aihead);+ gai_free(canon);+ socket_ops::freehostent(hptr);+ return EAI_FAMILY;+ }+ }++ socket_ops::freehostent(hptr);+ }++ // Check if we found anything.+ if (aihead == 0)+ {+ gai_free(canon);+ return EAI_NONAME;+ }++ // Return canonical name in first entry.+ if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))+ {+ if (canon)+ {+ aihead->ai_canonname = canon;+ canon = 0;+ }+ else+ {+ std::size_t canonname_len = strlen(search[0].host) + 1;+ aihead->ai_canonname = gai_alloc<char>(canonname_len);+ if (aihead->ai_canonname == 0)+ {+ freeaddrinfo_emulation(aihead);+ return EAI_MEMORY;+ }+ gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);+ }+ }+ gai_free(canon);++ // Process the service name.+ if (service != 0 && service[0] != '\0')+ {+ rc = gai_serv(aihead, &hints, service);+ if (rc != 0)+ {+ freeaddrinfo_emulation(aihead);+ return rc;+ }+ }++ // Return result to caller.+ *result = aihead;+ return 0;+}++inline asio::error_code getnameinfo_emulation(+ const socket_addr_type* sa, std::size_t salen, char* host,+ std::size_t hostlen, char* serv, std::size_t servlen, int flags,+ asio::error_code& ec)+{+ using namespace std;++ const char* addr;+ size_t addr_len;+ unsigned short port;+ switch (sa->sa_family)+ {+ case ASIO_OS_DEF(AF_INET):+ if (salen != sizeof(sockaddr_in4_type))+ {+ return ec = asio::error::invalid_argument;+ }+ addr = reinterpret_cast<const char*>(+ &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);+ addr_len = sizeof(in4_addr_type);+ port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;+ break;+ case ASIO_OS_DEF(AF_INET6):+ if (salen != sizeof(sockaddr_in6_type))+ {+ return ec = asio::error::invalid_argument;+ }+ addr = reinterpret_cast<const char*>(+ &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);+ addr_len = sizeof(in6_addr_type);+ port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;+ break;+ default:+ return ec = asio::error::address_family_not_supported;+ }++ if (host && hostlen > 0)+ {+ if (flags & NI_NUMERICHOST)+ {+ if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)+ {+ return ec;+ }+ }+ else+ {+ hostent hent;+ char hbuf[8192] = "";+ hostent* hptr = socket_ops::gethostbyaddr(addr,+ static_cast<int>(addr_len), sa->sa_family,+ &hent, hbuf, sizeof(hbuf), ec);+ if (hptr && hptr->h_name && hptr->h_name[0] != '\0')+ {+ if (flags & NI_NOFQDN)+ {+ char* dot = strchr(hptr->h_name, '.');+ if (dot)+ {+ *dot = 0;+ }+ }+ gai_strcpy(host, hptr->h_name, hostlen);+ socket_ops::freehostent(hptr);+ }+ else+ {+ socket_ops::freehostent(hptr);+ if (flags & NI_NAMEREQD)+ {+ return ec = asio::error::host_not_found;+ }+ if (socket_ops::inet_ntop(sa->sa_family,+ addr, host, hostlen, 0, ec) == 0)+ {+ return ec;+ }+ }+ }+ }++ if (serv && servlen > 0)+ {+ if (flags & NI_NUMERICSERV)+ {+ if (servlen < 6)+ {+ return ec = asio::error::no_buffer_space;+ }+#if defined(ASIO_HAS_SECURE_RTL)+ sprintf_s(serv, servlen, "%u", ntohs(port));+#else // defined(ASIO_HAS_SECURE_RTL)+ sprintf(serv, "%u", ntohs(port));+#endif // defined(ASIO_HAS_SECURE_RTL)+ }+ else+ {+#if defined(ASIO_HAS_PTHREADS)+ static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;+ ::pthread_mutex_lock(&mutex);+#endif // defined(ASIO_HAS_PTHREADS)+ servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0);+ if (sptr && sptr->s_name && sptr->s_name[0] != '\0')+ {+ gai_strcpy(serv, sptr->s_name, servlen);+ }+ else+ {+ if (servlen < 6)+ {+ return ec = asio::error::no_buffer_space;+ }+#if defined(ASIO_HAS_SECURE_RTL)+ sprintf_s(serv, servlen, "%u", ntohs(port));+#else // defined(ASIO_HAS_SECURE_RTL)+ sprintf(serv, "%u", ntohs(port));+#endif // defined(ASIO_HAS_SECURE_RTL)+ }+#if defined(ASIO_HAS_PTHREADS)+ ::pthread_mutex_unlock(&mutex);+#endif // defined(ASIO_HAS_PTHREADS)+ }+ }++ ec.assign(0, ec.category());+ return ec;+}++#endif // !defined(ASIO_HAS_GETADDRINFO)++inline asio::error_code translate_addrinfo_error(int error)+{+ switch (error)+ {+ case 0:+ return asio::error_code();+ case EAI_AGAIN:+ return asio::error::host_not_found_try_again;+ case EAI_BADFLAGS:+ return asio::error::invalid_argument;+ case EAI_FAIL:+ return asio::error::no_recovery;+ case EAI_FAMILY:+ return asio::error::address_family_not_supported;+ case EAI_MEMORY:+ return asio::error::no_memory;+ case EAI_NONAME:+#if defined(EAI_ADDRFAMILY)+ case EAI_ADDRFAMILY:+#endif+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)+ case EAI_NODATA:+#endif+ return asio::error::host_not_found;+ case EAI_SERVICE:+ return asio::error::service_not_found;+ case EAI_SOCKTYPE:+ return asio::error::socket_type_not_supported;+ default: // Possibly the non-portable EAI_SYSTEM.+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ return asio::error_code(+ WSAGetLastError(), asio::error::get_system_category());+#else+ return asio::error_code(+ errno, asio::error::get_system_category());+#endif+ }+}++asio::error_code getaddrinfo(const char* host,+ const char* service, const addrinfo_type& hints,+ addrinfo_type** result, asio::error_code& ec)+{+ host = (host && *host) ? host : 0;+ service = (service && *service) ? service : 0;+ clear_last_error();+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# if defined(ASIO_HAS_GETADDRINFO)+ // Building for Windows XP, Windows Server 2003, or later.+ int error = ::getaddrinfo(host, service, &hints, result);+ return ec = translate_addrinfo_error(error);+# else+ // Building for Windows 2000 or earlier.+ typedef int (WSAAPI *gai_t)(const char*,+ const char*, const addrinfo_type*, addrinfo_type**);+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))+ {+ if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))+ {+ int error = gai(host, service, &hints, result);+ return ec = translate_addrinfo_error(error);+ }+ }+ int error = getaddrinfo_emulation(host, service, &hints, result);+ return ec = translate_addrinfo_error(error);+# endif+#elif !defined(ASIO_HAS_GETADDRINFO)+ int error = getaddrinfo_emulation(host, service, &hints, result);+ return ec = translate_addrinfo_error(error);+#else+ int error = ::getaddrinfo(host, service, &hints, result);+#if defined(__MACH__) && defined(__APPLE__)+ using namespace std; // For isdigit and atoi.+ if (error == 0 && service && isdigit(static_cast<unsigned char>(service[0])))+ {+ u_short_type port = host_to_network_short(atoi(service));+ for (addrinfo_type* ai = *result; ai; ai = ai->ai_next)+ {+ switch (ai->ai_family)+ {+ case ASIO_OS_DEF(AF_INET):+ {+ sockaddr_in4_type* sinptr =+ reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);+ if (sinptr->sin_port == 0)+ sinptr->sin_port = port;+ break;+ }+ case ASIO_OS_DEF(AF_INET6):+ {+ sockaddr_in6_type* sin6ptr =+ reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);+ if (sin6ptr->sin6_port == 0)+ sin6ptr->sin6_port = port;+ break;+ }+ default:+ break;+ }+ }+ }+#endif+ return ec = translate_addrinfo_error(error);+#endif+}++asio::error_code background_getaddrinfo(+ const weak_cancel_token_type& cancel_token, const char* host,+ const char* service, const addrinfo_type& hints,+ addrinfo_type** result, asio::error_code& ec)+{+ if (cancel_token.expired())+ ec = asio::error::operation_aborted;+ else+ socket_ops::getaddrinfo(host, service, hints, result, ec);+ return ec;+}++void freeaddrinfo(addrinfo_type* ai)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# if defined(ASIO_HAS_GETADDRINFO)+ // Building for Windows XP, Windows Server 2003, or later.+ ::freeaddrinfo(ai);+# else+ // Building for Windows 2000 or earlier.+ typedef int (WSAAPI *fai_t)(addrinfo_type*);+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))+ {+ if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))+ {+ fai(ai);+ return;+ }+ }+ freeaddrinfo_emulation(ai);+# endif+#elif !defined(ASIO_HAS_GETADDRINFO)+ freeaddrinfo_emulation(ai);+#else+ ::freeaddrinfo(ai);+#endif+}++asio::error_code getnameinfo(const socket_addr_type* addr,+ std::size_t addrlen, char* host, std::size_t hostlen,+ char* serv, std::size_t servlen, int flags, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# if defined(ASIO_HAS_GETADDRINFO)+ // Building for Windows XP, Windows Server 2003, or later.+ clear_last_error();+ int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen),+ host, static_cast<DWORD>(hostlen),+ serv, static_cast<DWORD>(servlen), flags);+ return ec = translate_addrinfo_error(error);+# else+ // Building for Windows 2000 or earlier.+ typedef int (WSAAPI *gni_t)(const socket_addr_type*,+ int, char*, DWORD, char*, DWORD, int);+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))+ {+ if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))+ {+ clear_last_error();+ int error = gni(addr, static_cast<int>(addrlen),+ host, static_cast<DWORD>(hostlen),+ serv, static_cast<DWORD>(servlen), flags);+ return ec = translate_addrinfo_error(error);+ }+ }+ clear_last_error();+ return getnameinfo_emulation(addr, addrlen,+ host, hostlen, serv, servlen, flags, ec);+# endif+#elif !defined(ASIO_HAS_GETADDRINFO)+ using namespace std; // For memcpy.+ sockaddr_storage_type tmp_addr;+ memcpy(&tmp_addr, addr, addrlen);+ addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);+ clear_last_error();+ return getnameinfo_emulation(addr, addrlen,+ host, hostlen, serv, servlen, flags, ec);+#else+ clear_last_error();+ int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);+ return ec = translate_addrinfo_error(error);+#endif+}++asio::error_code sync_getnameinfo(+ const socket_addr_type* addr, std::size_t addrlen,+ char* host, std::size_t hostlen, char* serv,+ std::size_t servlen, int sock_type, asio::error_code& ec)+{+ // First try resolving with the service name. If that fails try resolving+ // but allow the service to be returned as a number.+ int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;+ socket_ops::getnameinfo(addr, addrlen, host,+ hostlen, serv, servlen, flags, ec);+ if (ec)+ {+ socket_ops::getnameinfo(addr, addrlen, host, hostlen,+ serv, servlen, flags | NI_NUMERICSERV, ec);+ }++ return ec;+}++asio::error_code background_getnameinfo(+ const weak_cancel_token_type& cancel_token,+ const socket_addr_type* addr, std::size_t addrlen,+ char* host, std::size_t hostlen, char* serv,+ std::size_t servlen, int sock_type, asio::error_code& ec)+{+ if (cancel_token.expired())+ {+ ec = asio::error::operation_aborted;+ }+ else+ {+ // First try resolving with the service name. If that fails try resolving+ // but allow the service to be returned as a number.+ int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;+ socket_ops::getnameinfo(addr, addrlen, host,+ hostlen, serv, servlen, flags, ec);+ if (ec)+ {+ socket_ops::getnameinfo(addr, addrlen, host, hostlen,+ serv, servlen, flags | NI_NUMERICSERV, ec);+ }+ }++ return ec;+}++#endif // !defined(ASIO_WINDOWS_RUNTIME)++u_long_type network_to_host_long(u_long_type value)+{+#if defined(ASIO_WINDOWS_RUNTIME)+ unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);+ u_long_type result = (static_cast<u_long_type>(value_p[0]) << 24)+ | (static_cast<u_long_type>(value_p[1]) << 16)+ | (static_cast<u_long_type>(value_p[2]) << 8)+ | static_cast<u_long_type>(value_p[3]);+ return result;+#else // defined(ASIO_WINDOWS_RUNTIME)+ return ntohl(value);+#endif // defined(ASIO_WINDOWS_RUNTIME)+}++u_long_type host_to_network_long(u_long_type value)+{+#if defined(ASIO_WINDOWS_RUNTIME)+ u_long_type result;+ unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);+ result_p[0] = static_cast<unsigned char>((value >> 24) & 0xFF);+ result_p[1] = static_cast<unsigned char>((value >> 16) & 0xFF);+ result_p[2] = static_cast<unsigned char>((value >> 8) & 0xFF);+ result_p[3] = static_cast<unsigned char>(value & 0xFF);+ return result;+#else // defined(ASIO_WINDOWS_RUNTIME)+ return htonl(value);+#endif // defined(ASIO_WINDOWS_RUNTIME)+}++u_short_type network_to_host_short(u_short_type value)+{+#if defined(ASIO_WINDOWS_RUNTIME)+ unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);+ u_short_type result = (static_cast<u_short_type>(value_p[0]) << 8)+ | static_cast<u_short_type>(value_p[1]);+ return result;+#else // defined(ASIO_WINDOWS_RUNTIME)+ return ntohs(value);+#endif // defined(ASIO_WINDOWS_RUNTIME)+}++u_short_type host_to_network_short(u_short_type value)+{+#if defined(ASIO_WINDOWS_RUNTIME)+ u_short_type result;+ unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);+ result_p[0] = static_cast<unsigned char>((value >> 8) & 0xFF);+ result_p[1] = static_cast<unsigned char>(value & 0xFF);+ return result;+#else // defined(ASIO_WINDOWS_RUNTIME)+ return htons(value);+#endif // defined(ASIO_WINDOWS_RUNTIME)+}++} // namespace socket_ops+} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_SOCKET_OPS_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/socket_select_interrupter.ipp view
@@ -0,0 +1,185 @@+//+// detail/impl/socket_select_interrupter.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SOCKET_SELECT_INTERRUPTER_IPP+#define ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if !defined(ASIO_WINDOWS_RUNTIME)++#if defined(ASIO_WINDOWS) \+ || defined(__CYGWIN__) \+ || defined(__SYMBIAN32__)++#include <cstdlib>+#include "asio/detail/socket_holder.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/socket_select_interrupter.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++socket_select_interrupter::socket_select_interrupter()+{+ open_descriptors();+}++void socket_select_interrupter::open_descriptors()+{+ asio::error_code ec;+ socket_holder acceptor(socket_ops::socket(+ AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));+ if (acceptor.get() == invalid_socket)+ asio::detail::throw_error(ec, "socket_select_interrupter");++ int opt = 1;+ socket_ops::state_type acceptor_state = 0;+ socket_ops::setsockopt(acceptor.get(), acceptor_state,+ SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);++ using namespace std; // For memset.+ sockaddr_in4_type addr;+ std::size_t addr_len = sizeof(addr);+ memset(&addr, 0, sizeof(addr));+ addr.sin_family = AF_INET;+ addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);+ addr.sin_port = 0;+ if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,+ addr_len, ec) == socket_error_retval)+ asio::detail::throw_error(ec, "socket_select_interrupter");++ if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,+ &addr_len, ec) == socket_error_retval)+ asio::detail::throw_error(ec, "socket_select_interrupter");++ // Some broken firewalls on Windows will intermittently cause getsockname to+ // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We+ // explicitly specify the target address here to work around this problem.+ if (addr.sin_addr.s_addr == socket_ops::host_to_network_long(INADDR_ANY))+ addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);++ if (socket_ops::listen(acceptor.get(),+ SOMAXCONN, ec) == socket_error_retval)+ asio::detail::throw_error(ec, "socket_select_interrupter");++ socket_holder client(socket_ops::socket(+ AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));+ if (client.get() == invalid_socket)+ asio::detail::throw_error(ec, "socket_select_interrupter");++ if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,+ addr_len, ec) == socket_error_retval)+ asio::detail::throw_error(ec, "socket_select_interrupter");++ socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));+ if (server.get() == invalid_socket)+ asio::detail::throw_error(ec, "socket_select_interrupter");+ + ioctl_arg_type non_blocking = 1;+ socket_ops::state_type client_state = 0;+ if (socket_ops::ioctl(client.get(), client_state,+ FIONBIO, &non_blocking, ec))+ asio::detail::throw_error(ec, "socket_select_interrupter");++ opt = 1;+ socket_ops::setsockopt(client.get(), client_state,+ IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);++ non_blocking = 1;+ socket_ops::state_type server_state = 0;+ if (socket_ops::ioctl(server.get(), server_state,+ FIONBIO, &non_blocking, ec))+ asio::detail::throw_error(ec, "socket_select_interrupter");++ opt = 1;+ socket_ops::setsockopt(server.get(), server_state,+ IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);++ read_descriptor_ = server.release();+ write_descriptor_ = client.release();+}++socket_select_interrupter::~socket_select_interrupter()+{+ close_descriptors();+}++void socket_select_interrupter::close_descriptors()+{+ asio::error_code ec;+ socket_ops::state_type state = socket_ops::internal_non_blocking;+ if (read_descriptor_ != invalid_socket)+ socket_ops::close(read_descriptor_, state, true, ec);+ if (write_descriptor_ != invalid_socket)+ socket_ops::close(write_descriptor_, state, true, ec);+}++void socket_select_interrupter::recreate()+{+ close_descriptors();++ write_descriptor_ = invalid_socket;+ read_descriptor_ = invalid_socket;++ open_descriptors();+}++void socket_select_interrupter::interrupt()+{+ char byte = 0;+ socket_ops::buf b;+ socket_ops::init_buf(b, &byte, 1);+ asio::error_code ec;+ socket_ops::send(write_descriptor_, &b, 1, 0, ec);+}++bool socket_select_interrupter::reset()+{+ char data[1024];+ socket_ops::buf b;+ socket_ops::init_buf(b, data, sizeof(data));+ asio::error_code ec;+ for (;;)+ {+ int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);+ if (bytes_read == sizeof(data))+ continue;+ if (bytes_read > 0)+ return true;+ if (bytes_read == 0)+ return false;+ if (ec == asio::error::would_block+ || ec == asio::error::try_again)+ return true;+ return false;+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)++#endif // !defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/strand_executor_service.hpp view
@@ -0,0 +1,385 @@+//+// detail/impl/strand_executor_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_STRAND_EXECUTOR_SERVICE_HPP+#define ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/call_stack.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/recycling_allocator.hpp"+#include "asio/executor_work_guard.hpp"+#include "asio/defer.hpp"+#include "asio/dispatch.hpp"+#include "asio/post.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename F, typename Allocator>+class strand_executor_service::allocator_binder+{+public:+ typedef Allocator allocator_type;++ allocator_binder(ASIO_MOVE_ARG(F) f, const Allocator& a)+ : f_(ASIO_MOVE_CAST(F)(f)),+ allocator_(a)+ {+ }++ allocator_binder(const allocator_binder& other)+ : f_(other.f_),+ allocator_(other.allocator_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ allocator_binder(allocator_binder&& other)+ : f_(ASIO_MOVE_CAST(F)(other.f_)),+ allocator_(ASIO_MOVE_CAST(allocator_type)(other.allocator_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ allocator_type get_allocator() const ASIO_NOEXCEPT+ {+ return allocator_;+ }++ void operator()()+ {+ f_();+ }++private:+ F f_;+ allocator_type allocator_;+};++template <typename Executor>+class strand_executor_service::invoker<Executor,+ typename enable_if<+ execution::is_executor<Executor>::value+ >::type>+{+public:+ invoker(const implementation_type& impl, Executor& ex)+ : impl_(impl),+ executor_(asio::prefer(ex, execution::outstanding_work.tracked))+ {+ }++ invoker(const invoker& other)+ : impl_(other.impl_),+ executor_(other.executor_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ invoker(invoker&& other)+ : impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)),+ executor_(ASIO_MOVE_CAST(executor_type)(other.executor_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ struct on_invoker_exit+ {+ invoker* this_;++ ~on_invoker_exit()+ {+ this_->impl_->mutex_->lock();+ this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_);+ bool more_handlers = this_->impl_->locked_ =+ !this_->impl_->ready_queue_.empty();+ this_->impl_->mutex_->unlock();++ if (more_handlers)+ {+ recycling_allocator<void> allocator;+ execution::execute(+ asio::prefer(+ asio::require(this_->executor_,+ execution::blocking.never),+ execution::allocator(allocator)),+ ASIO_MOVE_CAST(invoker)(*this_));+ }+ }+ };++ void operator()()+ {+ // Indicate that this strand is executing on the current thread.+ call_stack<strand_impl>::context ctx(impl_.get());++ // Ensure the next handler, if any, is scheduled on block exit.+ on_invoker_exit on_exit = { this };+ (void)on_exit;++ // Run all ready handlers. No lock is required since the ready queue is+ // accessed only within the strand.+ asio::error_code ec;+ while (scheduler_operation* o = impl_->ready_queue_.front())+ {+ impl_->ready_queue_.pop();+ o->complete(impl_.get(), ec, 0);+ }+ }++private:+ typedef typename decay<+ typename prefer_result<+ Executor,+ execution::outstanding_work_t::tracked_t+ >::type+ >::type executor_type;++ implementation_type impl_;+ executor_type executor_;+};++#if !defined(ASIO_NO_TS_EXECUTORS)++template <typename Executor>+class strand_executor_service::invoker<Executor,+ typename enable_if<+ !execution::is_executor<Executor>::value+ >::type>+{+public:+ invoker(const implementation_type& impl, Executor& ex)+ : impl_(impl),+ work_(ex)+ {+ }++ invoker(const invoker& other)+ : impl_(other.impl_),+ work_(other.work_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ invoker(invoker&& other)+ : impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)),+ work_(ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ struct on_invoker_exit+ {+ invoker* this_;++ ~on_invoker_exit()+ {+ this_->impl_->mutex_->lock();+ this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_);+ bool more_handlers = this_->impl_->locked_ =+ !this_->impl_->ready_queue_.empty();+ this_->impl_->mutex_->unlock();++ if (more_handlers)+ {+ Executor ex(this_->work_.get_executor());+ recycling_allocator<void> allocator;+ ex.post(ASIO_MOVE_CAST(invoker)(*this_), allocator);+ }+ }+ };++ void operator()()+ {+ // Indicate that this strand is executing on the current thread.+ call_stack<strand_impl>::context ctx(impl_.get());++ // Ensure the next handler, if any, is scheduled on block exit.+ on_invoker_exit on_exit = { this };+ (void)on_exit;++ // Run all ready handlers. No lock is required since the ready queue is+ // accessed only within the strand.+ asio::error_code ec;+ while (scheduler_operation* o = impl_->ready_queue_.front())+ {+ impl_->ready_queue_.pop();+ o->complete(impl_.get(), ec, 0);+ }+ }++private:+ implementation_type impl_;+ executor_work_guard<Executor> work_;+};++#endif // !defined(ASIO_NO_TS_EXECUTORS)++template <typename Executor, typename Function>+inline void strand_executor_service::execute(const implementation_type& impl,+ Executor& ex, ASIO_MOVE_ARG(Function) function,+ typename enable_if<+ can_query<Executor, execution::allocator_t<void> >::value+ >::type*)+{+ return strand_executor_service::do_execute(impl, ex,+ ASIO_MOVE_CAST(Function)(function),+ asio::query(ex, execution::allocator));+}++template <typename Executor, typename Function>+inline void strand_executor_service::execute(const implementation_type& impl,+ Executor& ex, ASIO_MOVE_ARG(Function) function,+ typename enable_if<+ !can_query<Executor, execution::allocator_t<void> >::value+ >::type*)+{+ return strand_executor_service::do_execute(impl, ex,+ ASIO_MOVE_CAST(Function)(function),+ std::allocator<void>());+}++template <typename Executor, typename Function, typename Allocator>+void strand_executor_service::do_execute(const implementation_type& impl,+ Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a)+{+ typedef typename decay<Function>::type function_type;++ // If the executor is not never-blocking, and we are already in the strand,+ // then the function can run immediately.+ if (asio::query(ex, execution::blocking) != execution::blocking.never+ && call_stack<strand_impl>::contains(impl.get()))+ {+ // Make a local, non-const copy of the function.+ function_type tmp(ASIO_MOVE_CAST(Function)(function));++ fenced_block b(fenced_block::full);+ asio_handler_invoke_helpers::invoke(tmp, tmp);+ return;+ }++ // Allocate and construct an operation to wrap the function.+ typedef executor_op<function_type, Allocator> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a);++ ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,+ "strand_executor", impl.get(), 0, "execute"));++ // Add the function to the strand and schedule the strand if required.+ bool first = enqueue(impl, p.p);+ p.v = p.p = 0;+ if (first)+ {+ execution::execute(ex, invoker<Executor>(impl, ex));+ }+}++template <typename Executor, typename Function, typename Allocator>+void strand_executor_service::dispatch(const implementation_type& impl,+ Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a)+{+ typedef typename decay<Function>::type function_type;++ // If we are already in the strand then the function can run immediately.+ if (call_stack<strand_impl>::contains(impl.get()))+ {+ // Make a local, non-const copy of the function.+ function_type tmp(ASIO_MOVE_CAST(Function)(function));++ fenced_block b(fenced_block::full);+ asio_handler_invoke_helpers::invoke(tmp, tmp);+ return;+ }++ // Allocate and construct an operation to wrap the function.+ typedef executor_op<function_type, Allocator> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a);++ ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,+ "strand_executor", impl.get(), 0, "dispatch"));++ // Add the function to the strand and schedule the strand if required.+ bool first = enqueue(impl, p.p);+ p.v = p.p = 0;+ if (first)+ {+ asio::dispatch(ex,+ allocator_binder<invoker<Executor>, Allocator>(+ invoker<Executor>(impl, ex), a));+ }+}++// Request invocation of the given function and return immediately.+template <typename Executor, typename Function, typename Allocator>+void strand_executor_service::post(const implementation_type& impl,+ Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a)+{+ typedef typename decay<Function>::type function_type;++ // Allocate and construct an operation to wrap the function.+ typedef executor_op<function_type, Allocator> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a);++ ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,+ "strand_executor", impl.get(), 0, "post"));++ // Add the function to the strand and schedule the strand if required.+ bool first = enqueue(impl, p.p);+ p.v = p.p = 0;+ if (first)+ {+ asio::post(ex,+ allocator_binder<invoker<Executor>, Allocator>(+ invoker<Executor>(impl, ex), a));+ }+}++// Request invocation of the given function and return immediately.+template <typename Executor, typename Function, typename Allocator>+void strand_executor_service::defer(const implementation_type& impl,+ Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a)+{+ typedef typename decay<Function>::type function_type;++ // Allocate and construct an operation to wrap the function.+ typedef executor_op<function_type, Allocator> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a);++ ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,+ "strand_executor", impl.get(), 0, "defer"));++ // Add the function to the strand and schedule the strand if required.+ bool first = enqueue(impl, p.p);+ p.v = p.p = 0;+ if (first)+ {+ asio::defer(ex,+ allocator_binder<invoker<Executor>, Allocator>(+ invoker<Executor>(impl, ex), a));+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/strand_executor_service.ipp view
@@ -0,0 +1,134 @@+//+// detail/impl/strand_executor_service.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_STRAND_EXECUTOR_SERVICE_IPP+#define ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/detail/strand_executor_service.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++strand_executor_service::strand_executor_service(execution_context& ctx)+ : execution_context_service_base<strand_executor_service>(ctx),+ mutex_(),+ salt_(0),+ impl_list_(0)+{+}++void strand_executor_service::shutdown()+{+ op_queue<scheduler_operation> ops;++ asio::detail::mutex::scoped_lock lock(mutex_);++ strand_impl* impl = impl_list_;+ while (impl)+ {+ impl->mutex_->lock();+ impl->shutdown_ = true;+ ops.push(impl->waiting_queue_);+ ops.push(impl->ready_queue_);+ impl->mutex_->unlock();+ impl = impl->next_;+ }+}++strand_executor_service::implementation_type+strand_executor_service::create_implementation()+{+ implementation_type new_impl(new strand_impl);+ new_impl->locked_ = false;+ new_impl->shutdown_ = false;++ asio::detail::mutex::scoped_lock lock(mutex_);++ // Select a mutex from the pool of shared mutexes.+ std::size_t salt = salt_++;+ std::size_t mutex_index = reinterpret_cast<std::size_t>(new_impl.get());+ mutex_index += (reinterpret_cast<std::size_t>(new_impl.get()) >> 3);+ mutex_index ^= salt + 0x9e3779b9 + (mutex_index << 6) + (mutex_index >> 2);+ mutex_index = mutex_index % num_mutexes;+ if (!mutexes_[mutex_index].get())+ mutexes_[mutex_index].reset(new mutex);+ new_impl->mutex_ = mutexes_[mutex_index].get();++ // Insert implementation into linked list of all implementations.+ new_impl->next_ = impl_list_;+ new_impl->prev_ = 0;+ if (impl_list_)+ impl_list_->prev_ = new_impl.get();+ impl_list_ = new_impl.get();+ new_impl->service_ = this;++ return new_impl;+}++strand_executor_service::strand_impl::~strand_impl()+{+ asio::detail::mutex::scoped_lock lock(service_->mutex_);++ // Remove implementation from linked list of all implementations.+ if (service_->impl_list_ == this)+ service_->impl_list_ = next_;+ if (prev_)+ prev_->next_ = next_;+ if (next_)+ next_->prev_= prev_;+}++bool strand_executor_service::enqueue(const implementation_type& impl,+ scheduler_operation* op)+{+ impl->mutex_->lock();+ if (impl->shutdown_)+ {+ impl->mutex_->unlock();+ op->destroy();+ return false;+ }+ else if (impl->locked_)+ {+ // Some other function already holds the strand lock. Enqueue for later.+ impl->waiting_queue_.push(op);+ impl->mutex_->unlock();+ return false;+ }+ else+ {+ // The function is acquiring the strand lock and so is responsible for+ // scheduling the strand.+ impl->locked_ = true;+ impl->mutex_->unlock();+ impl->ready_queue_.push(op);+ return true;+ }+}++bool strand_executor_service::running_in_this_thread(+ const implementation_type& impl)+{+ return !!call_stack<strand_impl>::contains(impl.get());+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/strand_service.hpp view
@@ -0,0 +1,117 @@+//+// detail/impl/strand_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_STRAND_SERVICE_HPP+#define ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/call_stack.hpp"+#include "asio/detail/completion_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/memory.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++inline strand_service::strand_impl::strand_impl()+ : operation(&strand_service::do_complete),+ locked_(false)+{+}++struct strand_service::on_dispatch_exit+{+ io_context_impl* io_context_impl_;+ strand_impl* impl_;++ ~on_dispatch_exit()+ {+ impl_->mutex_.lock();+ impl_->ready_queue_.push(impl_->waiting_queue_);+ bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();+ impl_->mutex_.unlock();++ if (more_handlers)+ io_context_impl_->post_immediate_completion(impl_, false);+ }+};++template <typename Handler>+void strand_service::dispatch(strand_service::implementation_type& impl,+ Handler& handler)+{+ // If we are already in the strand then the handler can run immediately.+ if (call_stack<strand_impl>::contains(impl))+ {+ fenced_block b(fenced_block::full);+ asio_handler_invoke_helpers::invoke(handler, handler);+ return;+ }++ // Allocate and construct an operation to wrap the handler.+ typedef completion_handler<Handler, io_context::executor_type> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(handler, io_context_.get_executor());++ ASIO_HANDLER_CREATION((this->context(),+ *p.p, "strand", impl, 0, "dispatch"));++ bool dispatch_immediately = do_dispatch(impl, p.p);+ operation* o = p.p;+ p.v = p.p = 0;++ if (dispatch_immediately)+ {+ // Indicate that this strand is executing on the current thread.+ call_stack<strand_impl>::context ctx(impl);++ // Ensure the next handler, if any, is scheduled on block exit.+ on_dispatch_exit on_exit = { &io_context_impl_, impl };+ (void)on_exit;++ op::do_complete(&io_context_impl_, o, asio::error_code(), 0);+ }+}++// Request the io_context to invoke the given handler and return immediately.+template <typename Handler>+void strand_service::post(strand_service::implementation_type& impl,+ Handler& handler)+{+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef completion_handler<Handler, io_context::executor_type> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(handler, io_context_.get_executor());++ ASIO_HANDLER_CREATION((this->context(),+ *p.p, "strand", impl, 0, "post"));++ do_post(impl, p.p, is_continuation);+ p.v = p.p = 0;+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/strand_service.ipp view
@@ -0,0 +1,178 @@+//+// detail/impl/strand_service.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_STRAND_SERVICE_IPP+#define ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/detail/call_stack.hpp"+#include "asio/detail/strand_service.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++struct strand_service::on_do_complete_exit+{+ io_context_impl* owner_;+ strand_impl* impl_;++ ~on_do_complete_exit()+ {+ impl_->mutex_.lock();+ impl_->ready_queue_.push(impl_->waiting_queue_);+ bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();+ impl_->mutex_.unlock();++ if (more_handlers)+ owner_->post_immediate_completion(impl_, true);+ }+};++strand_service::strand_service(asio::io_context& io_context)+ : asio::detail::service_base<strand_service>(io_context),+ io_context_(io_context),+ io_context_impl_(asio::use_service<io_context_impl>(io_context)),+ mutex_(),+ salt_(0)+{+}++void strand_service::shutdown()+{+ op_queue<operation> ops;++ asio::detail::mutex::scoped_lock lock(mutex_);++ for (std::size_t i = 0; i < num_implementations; ++i)+ {+ if (strand_impl* impl = implementations_[i].get())+ {+ ops.push(impl->waiting_queue_);+ ops.push(impl->ready_queue_);+ }+ }+}++void strand_service::construct(strand_service::implementation_type& impl)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ std::size_t salt = salt_++;+#if defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)+ std::size_t index = salt;+#else // defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)+ std::size_t index = reinterpret_cast<std::size_t>(&impl);+ index += (reinterpret_cast<std::size_t>(&impl) >> 3);+ index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2);+#endif // defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)+ index = index % num_implementations;++ if (!implementations_[index].get())+ implementations_[index].reset(new strand_impl);+ impl = implementations_[index].get();+}++bool strand_service::running_in_this_thread(+ const implementation_type& impl) const+{+ return call_stack<strand_impl>::contains(impl) != 0;+}++bool strand_service::do_dispatch(implementation_type& impl, operation* op)+{+ // If we are running inside the io_context, and no other handler already+ // holds the strand lock, then the handler can run immediately.+ bool can_dispatch = io_context_impl_.can_dispatch();+ impl->mutex_.lock();+ if (can_dispatch && !impl->locked_)+ {+ // Immediate invocation is allowed.+ impl->locked_ = true;+ impl->mutex_.unlock();+ return true;+ }++ if (impl->locked_)+ {+ // Some other handler already holds the strand lock. Enqueue for later.+ impl->waiting_queue_.push(op);+ impl->mutex_.unlock();+ }+ else+ {+ // The handler is acquiring the strand lock and so is responsible for+ // scheduling the strand.+ impl->locked_ = true;+ impl->mutex_.unlock();+ impl->ready_queue_.push(op);+ io_context_impl_.post_immediate_completion(impl, false);+ }++ return false;+}++void strand_service::do_post(implementation_type& impl,+ operation* op, bool is_continuation)+{+ impl->mutex_.lock();+ if (impl->locked_)+ {+ // Some other handler already holds the strand lock. Enqueue for later.+ impl->waiting_queue_.push(op);+ impl->mutex_.unlock();+ }+ else+ {+ // The handler is acquiring the strand lock and so is responsible for+ // scheduling the strand.+ impl->locked_ = true;+ impl->mutex_.unlock();+ impl->ready_queue_.push(op);+ io_context_impl_.post_immediate_completion(impl, is_continuation);+ }+}++void strand_service::do_complete(void* owner, operation* base,+ const asio::error_code& ec, std::size_t /*bytes_transferred*/)+{+ if (owner)+ {+ strand_impl* impl = static_cast<strand_impl*>(base);++ // Indicate that this strand is executing on the current thread.+ call_stack<strand_impl>::context ctx(impl);++ // Ensure the next handler, if any, is scheduled on block exit.+ on_do_complete_exit on_exit;+ on_exit.owner_ = static_cast<io_context_impl*>(owner);+ on_exit.impl_ = impl;++ // Run all ready handlers. No lock is required since the ready queue is+ // accessed only within the strand.+ while (operation* o = impl->ready_queue_.front())+ {+ impl->ready_queue_.pop();+ o->complete(owner, ec, 0);+ }+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/throw_error.ipp view
@@ -0,0 +1,60 @@+//+// detail/impl/throw_error.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_THROW_ERROR_IPP+#define ASIO_DETAIL_IMPL_THROW_ERROR_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/system_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++void do_throw_error(const asio::error_code& err)+{+ asio::system_error e(err);+ asio::detail::throw_exception(e);+}++void do_throw_error(const asio::error_code& err, const char* location)+{+ // boostify: non-boost code starts here+#if defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR)+ // Microsoft's implementation of std::system_error is non-conformant in that+ // it ignores the error code's message when a "what" string is supplied. We'll+ // work around this by explicitly formatting the "what" string.+ std::string what_msg = location;+ what_msg += ": ";+ what_msg += err.message();+ asio::system_error e(err, what_msg);+ asio::detail::throw_exception(e);+#else // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR)+ // boostify: non-boost code ends here+ asio::system_error e(err, location);+ asio::detail::throw_exception(e);+ // boostify: non-boost code starts here+#endif // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR)+ // boostify: non-boost code ends here+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_THROW_ERROR_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/timer_queue_ptime.ipp view
@@ -0,0 +1,91 @@+//+// detail/impl/timer_queue_ptime.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_TIMER_QUEUE_PTIME_IPP+#define ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP++#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_BOOST_DATE_TIME)++#include "asio/detail/timer_queue_ptime.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++timer_queue<time_traits<boost::posix_time::ptime> >::timer_queue()+{+}++timer_queue<time_traits<boost::posix_time::ptime> >::~timer_queue()+{+}++bool timer_queue<time_traits<boost::posix_time::ptime> >::enqueue_timer(+ const time_type& time, per_timer_data& timer, wait_op* op)+{+ return impl_.enqueue_timer(time, timer, op);+}++bool timer_queue<time_traits<boost::posix_time::ptime> >::empty() const+{+ return impl_.empty();+}++long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_msec(+ long max_duration) const+{+ return impl_.wait_duration_msec(max_duration);+}++long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_usec(+ long max_duration) const+{+ return impl_.wait_duration_usec(max_duration);+}++void timer_queue<time_traits<boost::posix_time::ptime> >::get_ready_timers(+ op_queue<operation>& ops)+{+ impl_.get_ready_timers(ops);+}++void timer_queue<time_traits<boost::posix_time::ptime> >::get_all_timers(+ op_queue<operation>& ops)+{+ impl_.get_all_timers(ops);+}++std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer(+ per_timer_data& timer, op_queue<operation>& ops, std::size_t max_cancelled)+{+ return impl_.cancel_timer(timer, ops, max_cancelled);+}++void timer_queue<time_traits<boost::posix_time::ptime> >::move_timer(+ per_timer_data& target, per_timer_data& source)+{+ impl_.move_timer(target, source);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_BOOST_DATE_TIME)++#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/timer_queue_set.ipp view
@@ -0,0 +1,101 @@+//+// detail/impl/timer_queue_set.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_TIMER_QUEUE_SET_IPP+#define ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/detail/timer_queue_set.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++timer_queue_set::timer_queue_set()+ : first_(0)+{+}++void timer_queue_set::insert(timer_queue_base* q)+{+ q->next_ = first_;+ first_ = q;+}++void timer_queue_set::erase(timer_queue_base* q)+{+ if (first_)+ {+ if (q == first_)+ {+ first_ = q->next_;+ q->next_ = 0;+ return;+ }++ for (timer_queue_base* p = first_; p->next_; p = p->next_)+ {+ if (p->next_ == q)+ {+ p->next_ = q->next_;+ q->next_ = 0;+ return;+ }+ }+ }+}++bool timer_queue_set::all_empty() const+{+ for (timer_queue_base* p = first_; p; p = p->next_)+ if (!p->empty())+ return false;+ return true;+}++long timer_queue_set::wait_duration_msec(long max_duration) const+{+ long min_duration = max_duration;+ for (timer_queue_base* p = first_; p; p = p->next_)+ min_duration = p->wait_duration_msec(min_duration);+ return min_duration;+}++long timer_queue_set::wait_duration_usec(long max_duration) const+{+ long min_duration = max_duration;+ for (timer_queue_base* p = first_; p; p = p->next_)+ min_duration = p->wait_duration_usec(min_duration);+ return min_duration;+}++void timer_queue_set::get_ready_timers(op_queue<operation>& ops)+{+ for (timer_queue_base* p = first_; p; p = p->next_)+ p->get_ready_timers(ops);+}++void timer_queue_set::get_all_timers(op_queue<operation>& ops)+{+ for (timer_queue_base* p = first_; p; p = p->next_)+ p->get_all_timers(ops);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/win_event.ipp view
@@ -0,0 +1,76 @@+//+// detail/win_event.ipp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WIN_EVENT_IPP+#define ASIO_DETAIL_IMPL_WIN_EVENT_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(ASIO_WINDOWS)++#include "asio/detail/throw_error.hpp"+#include "asio/detail/win_event.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++win_event::win_event()+ : state_(0)+{+#if defined(ASIO_WINDOWS_APP)+ events_[0] = ::CreateEventExW(0, 0,+ CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);+#else // defined(ASIO_WINDOWS_APP)+ events_[0] = ::CreateEventW(0, true, false, 0);+#endif // defined(ASIO_WINDOWS_APP)+ if (!events_[0])+ {+ DWORD last_error = ::GetLastError();+ asio::error_code ec(last_error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "event");+ }++#if defined(ASIO_WINDOWS_APP)+ events_[1] = ::CreateEventExW(0, 0, 0, EVENT_ALL_ACCESS);+#else // defined(ASIO_WINDOWS_APP)+ events_[1] = ::CreateEventW(0, false, false, 0);+#endif // defined(ASIO_WINDOWS_APP)+ if (!events_[1])+ {+ DWORD last_error = ::GetLastError();+ ::CloseHandle(events_[0]);+ asio::error_code ec(last_error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "event");+ }+}++win_event::~win_event()+{+ ::CloseHandle(events_[0]);+ ::CloseHandle(events_[1]);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS)++#endif // ASIO_DETAIL_IMPL_WIN_EVENT_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_handle_service.ipp view
@@ -0,0 +1,525 @@+//+// detail/impl/win_iocp_handle_service.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP+#define ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP++#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_IOCP)++#include "asio/detail/win_iocp_handle_service.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class win_iocp_handle_service::overlapped_wrapper+ : public OVERLAPPED+{+public:+ explicit overlapped_wrapper(asio::error_code& ec)+ {+ Internal = 0;+ InternalHigh = 0;+ Offset = 0;+ OffsetHigh = 0;++ // Create a non-signalled manual-reset event, for GetOverlappedResult.+ hEvent = ::CreateEventW(0, TRUE, FALSE, 0);+ if (hEvent)+ {+ // As documented in GetQueuedCompletionStatus, setting the low order+ // bit of this event prevents our synchronous writes from being treated+ // as completion port events.+ DWORD_PTR tmp = reinterpret_cast<DWORD_PTR>(hEvent);+ hEvent = reinterpret_cast<HANDLE>(tmp | 1);+ }+ else+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ }+ }++ ~overlapped_wrapper()+ {+ if (hEvent)+ {+ ::CloseHandle(hEvent);+ }+ }+};++win_iocp_handle_service::win_iocp_handle_service(execution_context& context)+ : execution_context_service_base<win_iocp_handle_service>(context),+ iocp_service_(asio::use_service<win_iocp_io_context>(context)),+ mutex_(),+ impl_list_(0)+{+}++void win_iocp_handle_service::shutdown()+{+ // Close all implementations, causing all operations to complete.+ asio::detail::mutex::scoped_lock lock(mutex_);+ implementation_type* impl = impl_list_;+ while (impl)+ {+ close_for_destruction(*impl);+ impl = impl->next_;+ }+}++void win_iocp_handle_service::construct(+ win_iocp_handle_service::implementation_type& impl)+{+ impl.handle_ = INVALID_HANDLE_VALUE;+ impl.safe_cancellation_thread_id_ = 0;++ // Insert implementation into linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ impl.next_ = impl_list_;+ impl.prev_ = 0;+ if (impl_list_)+ impl_list_->prev_ = &impl;+ impl_list_ = &impl;+}++void win_iocp_handle_service::move_construct(+ win_iocp_handle_service::implementation_type& impl,+ win_iocp_handle_service::implementation_type& other_impl)+{+ impl.handle_ = other_impl.handle_;+ other_impl.handle_ = INVALID_HANDLE_VALUE;++ impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;+ other_impl.safe_cancellation_thread_id_ = 0;++ // Insert implementation into linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ impl.next_ = impl_list_;+ impl.prev_ = 0;+ if (impl_list_)+ impl_list_->prev_ = &impl;+ impl_list_ = &impl;+}++void win_iocp_handle_service::move_assign(+ win_iocp_handle_service::implementation_type& impl,+ win_iocp_handle_service& other_service,+ win_iocp_handle_service::implementation_type& other_impl)+{+ close_for_destruction(impl);++ if (this != &other_service)+ {+ // Remove implementation from linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ if (impl_list_ == &impl)+ impl_list_ = impl.next_;+ if (impl.prev_)+ impl.prev_->next_ = impl.next_;+ if (impl.next_)+ impl.next_->prev_= impl.prev_;+ impl.next_ = 0;+ impl.prev_ = 0;+ }++ impl.handle_ = other_impl.handle_;+ other_impl.handle_ = INVALID_HANDLE_VALUE;++ impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;+ other_impl.safe_cancellation_thread_id_ = 0;++ if (this != &other_service)+ {+ // Insert implementation into linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(other_service.mutex_);+ impl.next_ = other_service.impl_list_;+ impl.prev_ = 0;+ if (other_service.impl_list_)+ other_service.impl_list_->prev_ = &impl;+ other_service.impl_list_ = &impl;+ }+}++void win_iocp_handle_service::destroy(+ win_iocp_handle_service::implementation_type& impl)+{+ close_for_destruction(impl);+ + // Remove implementation from linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ if (impl_list_ == &impl)+ impl_list_ = impl.next_;+ if (impl.prev_)+ impl.prev_->next_ = impl.next_;+ if (impl.next_)+ impl.next_->prev_= impl.prev_;+ impl.next_ = 0;+ impl.prev_ = 0;+}++asio::error_code win_iocp_handle_service::assign(+ win_iocp_handle_service::implementation_type& impl,+ const native_handle_type& handle, asio::error_code& ec)+{+ if (is_open(impl))+ {+ ec = asio::error::already_open;+ return ec;+ }++ if (iocp_service_.register_handle(handle, ec))+ return ec;++ impl.handle_ = handle;+ ec = asio::error_code();+ return ec;+}++asio::error_code win_iocp_handle_service::close(+ win_iocp_handle_service::implementation_type& impl,+ asio::error_code& ec)+{+ if (is_open(impl))+ {+ ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",+ &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close"));++ if (!::CloseHandle(impl.handle_))+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ }+ else+ {+ ec = asio::error_code();+ }++ impl.handle_ = INVALID_HANDLE_VALUE;+ impl.safe_cancellation_thread_id_ = 0;+ }+ else+ {+ ec = asio::error_code();+ }++ return ec;+}++asio::error_code win_iocp_handle_service::cancel(+ win_iocp_handle_service::implementation_type& impl,+ asio::error_code& ec)+{+ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return ec;+ }++ ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",+ &impl, reinterpret_cast<uintmax_t>(impl.handle_), "cancel"));++ if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(+ ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))+ {+ // The version of Windows supports cancellation from any thread.+ typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);+ cancel_io_ex_t cancel_io_ex = reinterpret_cast<cancel_io_ex_t>(+ reinterpret_cast<void*>(cancel_io_ex_ptr));+ if (!cancel_io_ex(impl.handle_, 0))+ {+ DWORD last_error = ::GetLastError();+ if (last_error == ERROR_NOT_FOUND)+ {+ // ERROR_NOT_FOUND means that there were no operations to be+ // cancelled. We swallow this error to match the behaviour on other+ // platforms.+ ec = asio::error_code();+ }+ else+ {+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ }+ }+ else+ {+ ec = asio::error_code();+ }+ }+ else if (impl.safe_cancellation_thread_id_ == 0)+ {+ // No operations have been started, so there's nothing to cancel.+ ec = asio::error_code();+ }+ else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())+ {+ // Asynchronous operations have been started from the current thread only,+ // so it is safe to try to cancel them using CancelIo.+ if (!::CancelIo(impl.handle_))+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ }+ else+ {+ ec = asio::error_code();+ }+ }+ else+ {+ // Asynchronous operations have been started from more than one thread,+ // so cancellation is not safe.+ ec = asio::error::operation_not_supported;+ }++ return ec;+}++size_t win_iocp_handle_service::do_write(+ win_iocp_handle_service::implementation_type& impl, uint64_t offset,+ const asio::const_buffer& buffer, asio::error_code& ec)+{+ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ // A request to write 0 bytes on a handle is a no-op.+ if (buffer.size() == 0)+ {+ ec = asio::error_code();+ return 0;+ }++ overlapped_wrapper overlapped(ec);+ if (ec)+ {+ return 0;+ }++ // Write the data. + overlapped.Offset = offset & 0xFFFFFFFF;+ overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;+ BOOL ok = ::WriteFile(impl.handle_, buffer.data(),+ static_cast<DWORD>(buffer.size()), 0, &overlapped);+ if (!ok) + {+ DWORD last_error = ::GetLastError();+ if (last_error != ERROR_IO_PENDING)+ {+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ return 0;+ }+ }++ // Wait for the operation to complete.+ DWORD bytes_transferred = 0;+ ok = ::GetOverlappedResult(impl.handle_,+ &overlapped, &bytes_transferred, TRUE);+ if (!ok)+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ return 0;+ }++ ec = asio::error_code();+ return bytes_transferred;+}++void win_iocp_handle_service::start_write_op(+ win_iocp_handle_service::implementation_type& impl, uint64_t offset,+ const asio::const_buffer& buffer, operation* op)+{+ update_cancellation_thread_id(impl);+ iocp_service_.work_started();++ if (!is_open(impl))+ {+ iocp_service_.on_completion(op, asio::error::bad_descriptor);+ }+ else if (buffer.size() == 0)+ {+ // A request to write 0 bytes on a handle is a no-op.+ iocp_service_.on_completion(op);+ }+ else+ {+ DWORD bytes_transferred = 0;+ op->Offset = offset & 0xFFFFFFFF;+ op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;+ BOOL ok = ::WriteFile(impl.handle_, buffer.data(),+ static_cast<DWORD>(buffer.size()),+ &bytes_transferred, op);+ DWORD last_error = ::GetLastError();+ if (!ok && last_error != ERROR_IO_PENDING+ && last_error != ERROR_MORE_DATA)+ {+ iocp_service_.on_completion(op, last_error, bytes_transferred);+ }+ else+ {+ iocp_service_.on_pending(op);+ }+ }+}++size_t win_iocp_handle_service::do_read(+ win_iocp_handle_service::implementation_type& impl, uint64_t offset,+ const asio::mutable_buffer& buffer, asio::error_code& ec)+{+ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }+ + // A request to read 0 bytes on a stream handle is a no-op.+ if (buffer.size() == 0)+ {+ ec = asio::error_code();+ return 0;+ }++ overlapped_wrapper overlapped(ec);+ if (ec)+ {+ return 0;+ }++ // Read some data.+ overlapped.Offset = offset & 0xFFFFFFFF;+ overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;+ BOOL ok = ::ReadFile(impl.handle_, buffer.data(),+ static_cast<DWORD>(buffer.size()), 0, &overlapped);+ if (!ok) + {+ DWORD last_error = ::GetLastError();+ if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)+ {+ if (last_error == ERROR_HANDLE_EOF)+ {+ ec = asio::error::eof;+ }+ else+ {+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ }+ return 0;+ }+ }++ // Wait for the operation to complete.+ DWORD bytes_transferred = 0;+ ok = ::GetOverlappedResult(impl.handle_,+ &overlapped, &bytes_transferred, TRUE);+ if (!ok)+ {+ DWORD last_error = ::GetLastError();+ if (last_error == ERROR_HANDLE_EOF)+ {+ ec = asio::error::eof;+ }+ else+ {+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ }+ return (last_error == ERROR_MORE_DATA) ? bytes_transferred : 0;+ }++ ec = asio::error_code();+ return bytes_transferred;+}++void win_iocp_handle_service::start_read_op(+ win_iocp_handle_service::implementation_type& impl, uint64_t offset,+ const asio::mutable_buffer& buffer, operation* op)+{+ update_cancellation_thread_id(impl);+ iocp_service_.work_started();++ if (!is_open(impl))+ {+ iocp_service_.on_completion(op, asio::error::bad_descriptor);+ }+ else if (buffer.size() == 0)+ {+ // A request to read 0 bytes on a handle is a no-op.+ iocp_service_.on_completion(op);+ }+ else+ {+ DWORD bytes_transferred = 0;+ op->Offset = offset & 0xFFFFFFFF;+ op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;+ BOOL ok = ::ReadFile(impl.handle_, buffer.data(),+ static_cast<DWORD>(buffer.size()),+ &bytes_transferred, op);+ DWORD last_error = ::GetLastError();+ if (!ok && last_error != ERROR_IO_PENDING+ && last_error != ERROR_MORE_DATA)+ {+ iocp_service_.on_completion(op, last_error, bytes_transferred);+ }+ else+ {+ iocp_service_.on_pending(op);+ }+ }+}++void win_iocp_handle_service::update_cancellation_thread_id(+ win_iocp_handle_service::implementation_type& impl)+{+ if (impl.safe_cancellation_thread_id_ == 0)+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())+ impl.safe_cancellation_thread_id_ = ~DWORD(0);+}++void win_iocp_handle_service::close_for_destruction(implementation_type& impl)+{+ if (is_open(impl))+ {+ ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",+ &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close"));++ ::CloseHandle(impl.handle_);+ impl.handle_ = INVALID_HANDLE_VALUE;+ impl.safe_cancellation_thread_id_ = 0;+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_io_context.hpp view
@@ -0,0 +1,103 @@+//+// detail/impl/win_iocp_io_context.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WIN_IOCP_IO_CONTEXT_HPP+#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_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_IOCP)++#include "asio/detail/completion_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/memory.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Time_Traits>+void win_iocp_io_context::add_timer_queue(+ timer_queue<Time_Traits>& queue)+{+ do_add_timer_queue(queue);+}++template <typename Time_Traits>+void win_iocp_io_context::remove_timer_queue(+ timer_queue<Time_Traits>& queue)+{+ do_remove_timer_queue(queue);+}++template <typename Time_Traits>+void win_iocp_io_context::schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)+{+ // If the service has been shut down we silently discard the timer.+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)+ {+ post_immediate_completion(op, false);+ return;+ }++ mutex::scoped_lock lock(dispatch_mutex_);++ bool earliest = queue.enqueue_timer(time, timer, op);+ work_started();+ if (earliest)+ update_timeout();+}++template <typename Time_Traits>+std::size_t win_iocp_io_context::cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled)+{+ // If the service has been shut down we silently ignore the cancellation.+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)+ return 0;++ mutex::scoped_lock lock(dispatch_mutex_);+ op_queue<win_iocp_operation> ops;+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);+ post_deferred_completions(ops);+ return n;+}++template <typename Time_Traits>+void win_iocp_io_context::move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& to,+ typename timer_queue<Time_Traits>::per_timer_data& from)+{+ asio::detail::mutex::scoped_lock lock(dispatch_mutex_);+ op_queue<operation> ops;+ queue.cancel_timer(to, ops);+ queue.move_timer(to, from);+ lock.unlock();+ post_deferred_completions(ops);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_io_context.ipp view
@@ -0,0 +1,603 @@+//+// detail/impl/win_iocp_io_context.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WIN_IOCP_IO_CONTEXT_IPP+#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP++#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_IOCP)++#include "asio/error.hpp"+#include "asio/detail/cstdint.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/limits.hpp"+#include "asio/detail/thread.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/win_iocp_io_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++struct win_iocp_io_context::thread_function+{+ explicit thread_function(win_iocp_io_context* s)+ : this_(s)+ {+ }++ void operator()()+ {+ asio::error_code ec;+ this_->run(ec);+ }++ win_iocp_io_context* this_;+};++struct win_iocp_io_context::work_finished_on_block_exit+{+ ~work_finished_on_block_exit()+ {+ io_context_->work_finished();+ }++ win_iocp_io_context* io_context_;+};++struct win_iocp_io_context::timer_thread_function+{+ void operator()()+ {+ while (::InterlockedExchangeAdd(&io_context_->shutdown_, 0) == 0)+ {+ if (::WaitForSingleObject(io_context_->waitable_timer_.handle,+ INFINITE) == WAIT_OBJECT_0)+ {+ ::InterlockedExchange(&io_context_->dispatch_required_, 1);+ ::PostQueuedCompletionStatus(io_context_->iocp_.handle,+ 0, wake_for_dispatch, 0);+ }+ }+ }++ win_iocp_io_context* io_context_;+};++win_iocp_io_context::win_iocp_io_context(+ asio::execution_context& ctx, int concurrency_hint, bool own_thread)+ : execution_context_service_base<win_iocp_io_context>(ctx),+ iocp_(),+ outstanding_work_(0),+ stopped_(0),+ stop_event_posted_(0),+ shutdown_(0),+ gqcs_timeout_(get_gqcs_timeout()),+ dispatch_required_(0),+ concurrency_hint_(concurrency_hint)+{+ ASIO_HANDLER_TRACKING_INIT;++ iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,+ static_cast<DWORD>(concurrency_hint >= 0 ? concurrency_hint : DWORD(~0)));+ if (!iocp_.handle)+ {+ DWORD last_error = ::GetLastError();+ asio::error_code ec(last_error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "iocp");+ }++ if (own_thread)+ {+ ::InterlockedIncrement(&outstanding_work_);+ thread_.reset(new asio::detail::thread(thread_function(this)));+ }+}++win_iocp_io_context::~win_iocp_io_context()+{+ if (thread_.get())+ {+ stop();+ thread_->join();+ thread_.reset();+ }+}++void win_iocp_io_context::shutdown()+{+ ::InterlockedExchange(&shutdown_, 1);++ if (timer_thread_.get())+ {+ LARGE_INTEGER timeout;+ timeout.QuadPart = 1;+ ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE);+ }++ if (thread_.get())+ {+ stop();+ thread_->join();+ thread_.reset();+ ::InterlockedDecrement(&outstanding_work_);+ }++ while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0)+ {+ op_queue<win_iocp_operation> ops;+ timer_queues_.get_all_timers(ops);+ ops.push(completed_ops_);+ if (!ops.empty())+ {+ while (win_iocp_operation* op = ops.front())+ {+ ops.pop();+ ::InterlockedDecrement(&outstanding_work_);+ op->destroy();+ }+ }+ else+ {+ DWORD bytes_transferred = 0;+ dword_ptr_t completion_key = 0;+ LPOVERLAPPED overlapped = 0;+ ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,+ &completion_key, &overlapped, gqcs_timeout_);+ if (overlapped)+ {+ ::InterlockedDecrement(&outstanding_work_);+ static_cast<win_iocp_operation*>(overlapped)->destroy();+ }+ }+ }++ if (timer_thread_.get())+ timer_thread_->join();+}++asio::error_code win_iocp_io_context::register_handle(+ HANDLE handle, asio::error_code& ec)+{+ if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ }+ else+ {+ ec = asio::error_code();+ }+ return ec;+}++size_t win_iocp_io_context::run(asio::error_code& ec)+{+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)+ {+ stop();+ ec = asio::error_code();+ return 0;+ }++ win_iocp_thread_info this_thread;+ thread_call_stack::context ctx(this, this_thread);++ size_t n = 0;+ while (do_one(INFINITE, this_thread, ec))+ if (n != (std::numeric_limits<size_t>::max)())+ ++n;+ return n;+}++size_t win_iocp_io_context::run_one(asio::error_code& ec)+{+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)+ {+ stop();+ ec = asio::error_code();+ return 0;+ }++ win_iocp_thread_info this_thread;+ thread_call_stack::context ctx(this, this_thread);++ return do_one(INFINITE, this_thread, ec);+}++size_t win_iocp_io_context::wait_one(long usec, asio::error_code& ec)+{+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)+ {+ stop();+ ec = asio::error_code();+ return 0;+ }++ win_iocp_thread_info this_thread;+ thread_call_stack::context ctx(this, this_thread);++ return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), this_thread, ec);+}++size_t win_iocp_io_context::poll(asio::error_code& ec)+{+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)+ {+ stop();+ ec = asio::error_code();+ return 0;+ }++ win_iocp_thread_info this_thread;+ thread_call_stack::context ctx(this, this_thread);++ size_t n = 0;+ while (do_one(0, this_thread, ec))+ if (n != (std::numeric_limits<size_t>::max)())+ ++n;+ return n;+}++size_t win_iocp_io_context::poll_one(asio::error_code& ec)+{+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)+ {+ stop();+ ec = asio::error_code();+ return 0;+ }++ win_iocp_thread_info this_thread;+ thread_call_stack::context ctx(this, this_thread);++ return do_one(0, this_thread, ec);+}++void win_iocp_io_context::stop()+{+ if (::InterlockedExchange(&stopped_, 1) == 0)+ {+ if (::InterlockedExchange(&stop_event_posted_, 1) == 0)+ {+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))+ {+ DWORD last_error = ::GetLastError();+ asio::error_code ec(last_error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "pqcs");+ }+ }+ }+}++void win_iocp_io_context::capture_current_exception()+{+ if (thread_info_base* this_thread = thread_call_stack::contains(this))+ this_thread->capture_current_exception();+}++void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op)+{+ // Flag the operation as ready.+ op->ready_ = 1;++ // Enqueue the operation on the I/O completion port.+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op))+ {+ // Out of resources. Put on completed queue instead.+ mutex::scoped_lock lock(dispatch_mutex_);+ completed_ops_.push(op);+ ::InterlockedExchange(&dispatch_required_, 1);+ }+}++void win_iocp_io_context::post_deferred_completions(+ op_queue<win_iocp_operation>& ops)+{+ while (win_iocp_operation* op = ops.front())+ {+ ops.pop();++ // Flag the operation as ready.+ op->ready_ = 1;++ // Enqueue the operation on the I/O completion port.+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op))+ {+ // Out of resources. Put on completed queue instead.+ mutex::scoped_lock lock(dispatch_mutex_);+ completed_ops_.push(op);+ completed_ops_.push(ops);+ ::InterlockedExchange(&dispatch_required_, 1);+ }+ }+}++void win_iocp_io_context::abandon_operations(+ op_queue<win_iocp_operation>& ops)+{+ while (win_iocp_operation* op = ops.front())+ {+ ops.pop();+ ::InterlockedDecrement(&outstanding_work_);+ op->destroy();+ }+}++void win_iocp_io_context::on_pending(win_iocp_operation* op)+{+ if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)+ {+ // Enqueue the operation on the I/O completion port.+ if (!::PostQueuedCompletionStatus(iocp_.handle,+ 0, overlapped_contains_result, op))+ {+ // Out of resources. Put on completed queue instead.+ mutex::scoped_lock lock(dispatch_mutex_);+ completed_ops_.push(op);+ ::InterlockedExchange(&dispatch_required_, 1);+ }+ }+}++void win_iocp_io_context::on_completion(win_iocp_operation* op,+ DWORD last_error, DWORD bytes_transferred)+{+ // Flag that the operation is ready for invocation.+ op->ready_ = 1;++ // Store results in the OVERLAPPED structure.+ op->Internal = reinterpret_cast<ulong_ptr_t>(+ &asio::error::get_system_category());+ op->Offset = last_error;+ op->OffsetHigh = bytes_transferred;++ // Enqueue the operation on the I/O completion port.+ if (!::PostQueuedCompletionStatus(iocp_.handle,+ 0, overlapped_contains_result, op))+ {+ // Out of resources. Put on completed queue instead.+ mutex::scoped_lock lock(dispatch_mutex_);+ completed_ops_.push(op);+ ::InterlockedExchange(&dispatch_required_, 1);+ }+}++void win_iocp_io_context::on_completion(win_iocp_operation* op,+ const asio::error_code& ec, DWORD bytes_transferred)+{+ // Flag that the operation is ready for invocation.+ op->ready_ = 1;++ // Store results in the OVERLAPPED structure.+ op->Internal = reinterpret_cast<ulong_ptr_t>(&ec.category());+ op->Offset = ec.value();+ op->OffsetHigh = bytes_transferred;++ // Enqueue the operation on the I/O completion port.+ if (!::PostQueuedCompletionStatus(iocp_.handle,+ 0, overlapped_contains_result, op))+ {+ // Out of resources. Put on completed queue instead.+ mutex::scoped_lock lock(dispatch_mutex_);+ completed_ops_.push(op);+ ::InterlockedExchange(&dispatch_required_, 1);+ }+}++size_t win_iocp_io_context::do_one(DWORD msec,+ win_iocp_thread_info& this_thread, asio::error_code& ec)+{+ for (;;)+ {+ // Try to acquire responsibility for dispatching timers and completed ops.+ if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1)+ {+ mutex::scoped_lock lock(dispatch_mutex_);++ // Dispatch pending timers and operations.+ op_queue<win_iocp_operation> ops;+ ops.push(completed_ops_);+ timer_queues_.get_ready_timers(ops);+ post_deferred_completions(ops);+ update_timeout();+ }++ // Get the next operation from the queue.+ DWORD bytes_transferred = 0;+ dword_ptr_t completion_key = 0;+ LPOVERLAPPED overlapped = 0;+ ::SetLastError(0);+ BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle,+ &bytes_transferred, &completion_key, &overlapped,+ msec < gqcs_timeout_ ? msec : gqcs_timeout_);+ DWORD last_error = ::GetLastError();++ if (overlapped)+ {+ win_iocp_operation* op = static_cast<win_iocp_operation*>(overlapped);+ asio::error_code result_ec(last_error,+ asio::error::get_system_category());++ // We may have been passed the last_error and bytes_transferred in the+ // OVERLAPPED structure itself.+ if (completion_key == overlapped_contains_result)+ {+ result_ec = asio::error_code(static_cast<int>(op->Offset),+ *reinterpret_cast<asio::error_category*>(op->Internal));+ bytes_transferred = op->OffsetHigh;+ }++ // Otherwise ensure any result has been saved into the OVERLAPPED+ // structure.+ else+ {+ op->Internal = reinterpret_cast<ulong_ptr_t>(&result_ec.category());+ op->Offset = result_ec.value();+ op->OffsetHigh = bytes_transferred;+ }++ // Dispatch the operation only if ready. The operation may not be ready+ // if the initiating function (e.g. a call to WSARecv) has not yet+ // returned. This is because the initiating function still wants access+ // to the operation's OVERLAPPED structure.+ if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)+ {+ // Ensure the count of outstanding work is decremented on block exit.+ work_finished_on_block_exit on_exit = { this };+ (void)on_exit;++ op->complete(this, result_ec, bytes_transferred);+ this_thread.rethrow_pending_exception();+ ec = asio::error_code();+ return 1;+ }+ }+ else if (!ok)+ {+ if (last_error != WAIT_TIMEOUT)+ {+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ return 0;+ }++ // If we're waiting indefinitely we need to keep going until we get a+ // real handler.+ if (msec == INFINITE)+ continue;++ ec = asio::error_code();+ return 0;+ }+ else if (completion_key == wake_for_dispatch)+ {+ // We have been woken up to try to acquire responsibility for dispatching+ // timers and completed operations.+ }+ else+ {+ // Indicate that there is no longer an in-flight stop event.+ ::InterlockedExchange(&stop_event_posted_, 0);++ // The stopped_ flag is always checked to ensure that any leftover+ // stop events from a previous run invocation are ignored.+ if (::InterlockedExchangeAdd(&stopped_, 0) != 0)+ {+ // Wake up next thread that is blocked on GetQueuedCompletionStatus.+ if (::InterlockedExchange(&stop_event_posted_, 1) == 0)+ {+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))+ {+ last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ return 0;+ }+ }++ ec = asio::error_code();+ return 0;+ }+ }+ }+}++DWORD win_iocp_io_context::get_gqcs_timeout()+{+ OSVERSIONINFOEX osvi;+ ZeroMemory(&osvi, sizeof(osvi));+ osvi.dwOSVersionInfoSize = sizeof(osvi);+ osvi.dwMajorVersion = 6ul;++ const uint64_t condition_mask = ::VerSetConditionMask(+ 0, VER_MAJORVERSION, VER_GREATER_EQUAL);++ if (!!::VerifyVersionInfo(&osvi, VER_MAJORVERSION, condition_mask))+ return INFINITE;++ return default_gqcs_timeout;+}++void win_iocp_io_context::do_add_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(dispatch_mutex_);++ timer_queues_.insert(&queue);++ if (!waitable_timer_.handle)+ {+ waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0);+ if (waitable_timer_.handle == 0)+ {+ DWORD last_error = ::GetLastError();+ asio::error_code ec(last_error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "timer");+ }++ LARGE_INTEGER timeout;+ timeout.QuadPart = -max_timeout_usec;+ timeout.QuadPart *= 10;+ ::SetWaitableTimer(waitable_timer_.handle,+ &timeout, max_timeout_msec, 0, 0, FALSE);+ }++ if (!timer_thread_.get())+ {+ timer_thread_function thread_function = { this };+ timer_thread_.reset(new thread(thread_function, 65536));+ }+}++void win_iocp_io_context::do_remove_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(dispatch_mutex_);++ timer_queues_.erase(&queue);+}++void win_iocp_io_context::update_timeout()+{+ if (timer_thread_.get())+ {+ // There's no point updating the waitable timer if the new timeout period+ // exceeds the maximum timeout. In that case, we might as well wait for the+ // existing period of the timer to expire.+ long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec);+ if (timeout_usec < max_timeout_usec)+ {+ LARGE_INTEGER timeout;+ timeout.QuadPart = -timeout_usec;+ timeout.QuadPart *= 10;+ ::SetWaitableTimer(waitable_timer_.handle,+ &timeout, max_timeout_msec, 0, 0, FALSE);+ }+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_serial_port_service.ipp view
@@ -0,0 +1,192 @@+//+// detail/impl/win_iocp_serial_port_service.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP+#define ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP++#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_IOCP) && defined(ASIO_HAS_SERIAL_PORT)++#include <cstring>+#include "asio/detail/win_iocp_serial_port_service.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++win_iocp_serial_port_service::win_iocp_serial_port_service(+ execution_context& context)+ : execution_context_service_base<win_iocp_serial_port_service>(context),+ handle_service_(context)+{+}++void win_iocp_serial_port_service::shutdown()+{+}++asio::error_code win_iocp_serial_port_service::open(+ win_iocp_serial_port_service::implementation_type& impl,+ const std::string& device, asio::error_code& ec)+{+ if (is_open(impl))+ {+ ec = asio::error::already_open;+ return ec;+ }++ // For convenience, add a leading \\.\ sequence if not already present.+ std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;++ // Open a handle to the serial port.+ ::HANDLE handle = ::CreateFileA(name.c_str(),+ GENERIC_READ | GENERIC_WRITE, 0, 0,+ OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);+ if (handle == INVALID_HANDLE_VALUE)+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ return ec;+ }++ // Determine the initial serial port parameters.+ using namespace std; // For memset.+ ::DCB dcb;+ memset(&dcb, 0, sizeof(DCB));+ dcb.DCBlength = sizeof(DCB);+ if (!::GetCommState(handle, &dcb))+ {+ DWORD last_error = ::GetLastError();+ ::CloseHandle(handle);+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ return ec;+ }++ // Set some default serial port parameters. This implementation does not+ // support changing all of these, so they might as well be in a known state.+ dcb.fBinary = TRUE; // Win32 only supports binary mode.+ dcb.fNull = FALSE; // Do not ignore NULL characters.+ dcb.fAbortOnError = FALSE; // Ignore serial framing errors.+ dcb.BaudRate = CBR_9600; // 9600 baud by default+ dcb.ByteSize = 8; // 8 bit bytes+ dcb.fOutxCtsFlow = FALSE; // No flow control+ dcb.fOutxDsrFlow = FALSE;+ dcb.fDtrControl = DTR_CONTROL_DISABLE;+ dcb.fDsrSensitivity = FALSE;+ dcb.fOutX = FALSE;+ dcb.fInX = FALSE;+ dcb.fRtsControl = RTS_CONTROL_DISABLE;+ dcb.fParity = FALSE; // No parity+ dcb.Parity = NOPARITY;+ dcb.StopBits = ONESTOPBIT; // One stop bit+ if (!::SetCommState(handle, &dcb))+ {+ DWORD last_error = ::GetLastError();+ ::CloseHandle(handle);+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ return ec;+ }++ // Set up timeouts so that the serial port will behave similarly to a+ // network socket. Reads wait for at least one byte, then return with+ // whatever they have. Writes return once everything is out the door.+ ::COMMTIMEOUTS timeouts;+ timeouts.ReadIntervalTimeout = 1;+ timeouts.ReadTotalTimeoutMultiplier = 0;+ timeouts.ReadTotalTimeoutConstant = 0;+ timeouts.WriteTotalTimeoutMultiplier = 0;+ timeouts.WriteTotalTimeoutConstant = 0;+ if (!::SetCommTimeouts(handle, &timeouts))+ {+ DWORD last_error = ::GetLastError();+ ::CloseHandle(handle);+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ return ec;+ }++ // We're done. Take ownership of the serial port handle.+ if (handle_service_.assign(impl, handle, ec))+ ::CloseHandle(handle);+ return ec;+}++asio::error_code win_iocp_serial_port_service::do_set_option(+ win_iocp_serial_port_service::implementation_type& impl,+ win_iocp_serial_port_service::store_function_type store,+ const void* option, asio::error_code& ec)+{+ using namespace std; // For memcpy.++ ::DCB dcb;+ memset(&dcb, 0, sizeof(DCB));+ dcb.DCBlength = sizeof(DCB);+ if (!::GetCommState(handle_service_.native_handle(impl), &dcb))+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ return ec;+ }++ if (store(option, dcb, ec))+ return ec;++ if (!::SetCommState(handle_service_.native_handle(impl), &dcb))+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ return ec;+ }++ ec = asio::error_code();+ return ec;+}++asio::error_code win_iocp_serial_port_service::do_get_option(+ const win_iocp_serial_port_service::implementation_type& impl,+ win_iocp_serial_port_service::load_function_type load,+ void* option, asio::error_code& ec) const+{+ using namespace std; // For memset.++ ::DCB dcb;+ memset(&dcb, 0, sizeof(DCB));+ dcb.DCBlength = sizeof(DCB);+ if (!::GetCommState(handle_service_.native_handle(impl), &dcb))+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ return ec;+ }++ return load(option, dcb, ec);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)++#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp view
@@ -0,0 +1,801 @@+//+// detail/impl/win_iocp_socket_service_base.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP+#define ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP++#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_IOCP)++#include "asio/detail/win_iocp_socket_service_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++win_iocp_socket_service_base::win_iocp_socket_service_base(+ execution_context& context)+ : context_(context),+ iocp_service_(use_service<win_iocp_io_context>(context)),+ reactor_(0),+ connect_ex_(0),+ nt_set_info_(0),+ mutex_(),+ impl_list_(0)+{+}++void win_iocp_socket_service_base::base_shutdown()+{+ // Close all implementations, causing all operations to complete.+ asio::detail::mutex::scoped_lock lock(mutex_);+ base_implementation_type* impl = impl_list_;+ while (impl)+ {+ close_for_destruction(*impl);+ impl = impl->next_;+ }+}++void win_iocp_socket_service_base::construct(+ win_iocp_socket_service_base::base_implementation_type& impl)+{+ impl.socket_ = invalid_socket;+ impl.state_ = 0;+ impl.cancel_token_.reset();+#if defined(ASIO_ENABLE_CANCELIO)+ impl.safe_cancellation_thread_id_ = 0;+#endif // defined(ASIO_ENABLE_CANCELIO)++ // Insert implementation into linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ impl.next_ = impl_list_;+ impl.prev_ = 0;+ if (impl_list_)+ impl_list_->prev_ = &impl;+ impl_list_ = &impl;+}++void win_iocp_socket_service_base::base_move_construct(+ win_iocp_socket_service_base::base_implementation_type& impl,+ win_iocp_socket_service_base::base_implementation_type& other_impl)+ ASIO_NOEXCEPT+{+ impl.socket_ = other_impl.socket_;+ other_impl.socket_ = invalid_socket;++ impl.state_ = other_impl.state_;+ other_impl.state_ = 0;++ impl.cancel_token_ = other_impl.cancel_token_;+ other_impl.cancel_token_.reset();++#if defined(ASIO_ENABLE_CANCELIO)+ impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;+ other_impl.safe_cancellation_thread_id_ = 0;+#endif // defined(ASIO_ENABLE_CANCELIO)++ // Insert implementation into linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ impl.next_ = impl_list_;+ impl.prev_ = 0;+ if (impl_list_)+ impl_list_->prev_ = &impl;+ impl_list_ = &impl;+}++void win_iocp_socket_service_base::base_move_assign(+ win_iocp_socket_service_base::base_implementation_type& impl,+ win_iocp_socket_service_base& other_service,+ win_iocp_socket_service_base::base_implementation_type& other_impl)+{+ close_for_destruction(impl);++ if (this != &other_service)+ {+ // Remove implementation from linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ if (impl_list_ == &impl)+ impl_list_ = impl.next_;+ if (impl.prev_)+ impl.prev_->next_ = impl.next_;+ if (impl.next_)+ impl.next_->prev_= impl.prev_;+ impl.next_ = 0;+ impl.prev_ = 0;+ }++ impl.socket_ = other_impl.socket_;+ other_impl.socket_ = invalid_socket;++ impl.state_ = other_impl.state_;+ other_impl.state_ = 0;++ impl.cancel_token_ = other_impl.cancel_token_;+ other_impl.cancel_token_.reset();++#if defined(ASIO_ENABLE_CANCELIO)+ impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;+ other_impl.safe_cancellation_thread_id_ = 0;+#endif // defined(ASIO_ENABLE_CANCELIO)++ if (this != &other_service)+ {+ // Insert implementation into linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(other_service.mutex_);+ impl.next_ = other_service.impl_list_;+ impl.prev_ = 0;+ if (other_service.impl_list_)+ other_service.impl_list_->prev_ = &impl;+ other_service.impl_list_ = &impl;+ }+}++void win_iocp_socket_service_base::destroy(+ win_iocp_socket_service_base::base_implementation_type& impl)+{+ close_for_destruction(impl);++ // Remove implementation from linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ if (impl_list_ == &impl)+ impl_list_ = impl.next_;+ if (impl.prev_)+ impl.prev_->next_ = impl.next_;+ if (impl.next_)+ impl.next_->prev_= impl.prev_;+ impl.next_ = 0;+ impl.prev_ = 0;+}++asio::error_code win_iocp_socket_service_base::close(+ win_iocp_socket_service_base::base_implementation_type& impl,+ asio::error_code& ec)+{+ if (is_open(impl))+ {+ ASIO_HANDLER_OPERATION((iocp_service_.context(),+ "socket", &impl, impl.socket_, "close"));++ // Check if the reactor was created, in which case we need to close the+ // socket on the reactor as well to cancel any operations that might be+ // running there.+ select_reactor* r = static_cast<select_reactor*>(+ interlocked_compare_exchange_pointer(+ reinterpret_cast<void**>(&reactor_), 0, 0));+ if (r)+ r->deregister_descriptor(impl.socket_, impl.reactor_data_, true);++ socket_ops::close(impl.socket_, impl.state_, false, ec);++ if (r)+ r->cleanup_descriptor_data(impl.reactor_data_);+ }+ else+ {+ ec = asio::error_code();+ }++ impl.socket_ = invalid_socket;+ impl.state_ = 0;+ impl.cancel_token_.reset();+#if defined(ASIO_ENABLE_CANCELIO)+ impl.safe_cancellation_thread_id_ = 0;+#endif // defined(ASIO_ENABLE_CANCELIO)++ return ec;+}++socket_type win_iocp_socket_service_base::release(+ win_iocp_socket_service_base::base_implementation_type& impl,+ asio::error_code& ec)+{+ if (!is_open(impl))+ return invalid_socket;++ cancel(impl, ec);+ if (ec)+ return invalid_socket;++ nt_set_info_fn fn = get_nt_set_info();+ if (fn == 0)+ {+ ec = asio::error::operation_not_supported;+ return invalid_socket;+ }++ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(impl.socket_);+ ULONG_PTR iosb[2] = { 0, 0 };+ void* info[2] = { 0, 0 };+ if (fn(sock_as_handle, iosb, &info, sizeof(info),+ 61 /* FileReplaceCompletionInformation */))+ {+ ec = asio::error::operation_not_supported;+ return invalid_socket;+ }++ socket_type tmp = impl.socket_;+ impl.socket_ = invalid_socket;+ return tmp;+}++asio::error_code win_iocp_socket_service_base::cancel(+ win_iocp_socket_service_base::base_implementation_type& impl,+ asio::error_code& ec)+{+ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return ec;+ }++ ASIO_HANDLER_OPERATION((iocp_service_.context(),+ "socket", &impl, impl.socket_, "cancel"));++ if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(+ ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))+ {+ // The version of Windows supports cancellation from any thread.+ typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);+ cancel_io_ex_t cancel_io_ex = reinterpret_cast<cancel_io_ex_t>(+ reinterpret_cast<void*>(cancel_io_ex_ptr));+ socket_type sock = impl.socket_;+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);+ if (!cancel_io_ex(sock_as_handle, 0))+ {+ DWORD last_error = ::GetLastError();+ if (last_error == ERROR_NOT_FOUND)+ {+ // ERROR_NOT_FOUND means that there were no operations to be+ // cancelled. We swallow this error to match the behaviour on other+ // platforms.+ ec = asio::error_code();+ }+ else+ {+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ }+ }+ else+ {+ ec = asio::error_code();+ }+ }+#if defined(ASIO_ENABLE_CANCELIO)+ else if (impl.safe_cancellation_thread_id_ == 0)+ {+ // No operations have been started, so there's nothing to cancel.+ ec = asio::error_code();+ }+ else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())+ {+ // Asynchronous operations have been started from the current thread only,+ // so it is safe to try to cancel them using CancelIo.+ socket_type sock = impl.socket_;+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);+ if (!::CancelIo(sock_as_handle))+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ }+ else+ {+ ec = asio::error_code();+ }+ }+ else+ {+ // Asynchronous operations have been started from more than one thread,+ // so cancellation is not safe.+ ec = asio::error::operation_not_supported;+ }+#else // defined(ASIO_ENABLE_CANCELIO)+ else+ {+ // Cancellation is not supported as CancelIo may not be used.+ ec = asio::error::operation_not_supported;+ }+#endif // defined(ASIO_ENABLE_CANCELIO)++ // Cancel any operations started via the reactor.+ if (!ec)+ {+ select_reactor* r = static_cast<select_reactor*>(+ interlocked_compare_exchange_pointer(+ reinterpret_cast<void**>(&reactor_), 0, 0));+ if (r)+ r->cancel_ops(impl.socket_, impl.reactor_data_);+ }++ return ec;+}++asio::error_code win_iocp_socket_service_base::do_open(+ win_iocp_socket_service_base::base_implementation_type& impl,+ int family, int type, int protocol, asio::error_code& ec)+{+ if (is_open(impl))+ {+ ec = asio::error::already_open;+ return ec;+ }++ socket_holder sock(socket_ops::socket(family, type, protocol, ec));+ if (sock.get() == invalid_socket)+ return ec;++ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());+ if (iocp_service_.register_handle(sock_as_handle, ec))+ return ec;++ impl.socket_ = sock.release();+ switch (type)+ {+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;+ default: impl.state_ = 0; break;+ }+ impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());+ ec = asio::error_code();+ return ec;+}++asio::error_code win_iocp_socket_service_base::do_assign(+ win_iocp_socket_service_base::base_implementation_type& impl,+ int type, socket_type native_socket, asio::error_code& ec)+{+ if (is_open(impl))+ {+ ec = asio::error::already_open;+ return ec;+ }++ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(native_socket);+ if (iocp_service_.register_handle(sock_as_handle, ec))+ return ec;++ impl.socket_ = native_socket;+ switch (type)+ {+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;+ default: impl.state_ = 0; break;+ }+ impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());+ ec = asio::error_code();+ return ec;+}++void win_iocp_socket_service_base::start_send_op(+ win_iocp_socket_service_base::base_implementation_type& impl,+ WSABUF* buffers, std::size_t buffer_count,+ socket_base::message_flags flags, bool noop, operation* op)+{+ update_cancellation_thread_id(impl);+ iocp_service_.work_started();++ if (noop)+ iocp_service_.on_completion(op);+ else if (!is_open(impl))+ iocp_service_.on_completion(op, asio::error::bad_descriptor);+ else+ {+ DWORD bytes_transferred = 0;+ int result = ::WSASend(impl.socket_, buffers,+ static_cast<DWORD>(buffer_count), &bytes_transferred, flags, op, 0);+ DWORD last_error = ::WSAGetLastError();+ if (last_error == ERROR_PORT_UNREACHABLE)+ last_error = WSAECONNREFUSED;+ if (result != 0 && last_error != WSA_IO_PENDING)+ iocp_service_.on_completion(op, last_error, bytes_transferred);+ else+ iocp_service_.on_pending(op);+ }+}++void win_iocp_socket_service_base::start_send_to_op(+ win_iocp_socket_service_base::base_implementation_type& impl,+ WSABUF* buffers, std::size_t buffer_count,+ const socket_addr_type* addr, int addrlen,+ socket_base::message_flags flags, operation* op)+{+ update_cancellation_thread_id(impl);+ iocp_service_.work_started();++ if (!is_open(impl))+ iocp_service_.on_completion(op, asio::error::bad_descriptor);+ else+ {+ DWORD bytes_transferred = 0;+ int result = ::WSASendTo(impl.socket_, buffers,+ static_cast<DWORD>(buffer_count),+ &bytes_transferred, flags, addr, addrlen, op, 0);+ DWORD last_error = ::WSAGetLastError();+ if (last_error == ERROR_PORT_UNREACHABLE)+ last_error = WSAECONNREFUSED;+ if (result != 0 && last_error != WSA_IO_PENDING)+ iocp_service_.on_completion(op, last_error, bytes_transferred);+ else+ iocp_service_.on_pending(op);+ }+}++void win_iocp_socket_service_base::start_receive_op(+ win_iocp_socket_service_base::base_implementation_type& impl,+ WSABUF* buffers, std::size_t buffer_count,+ socket_base::message_flags flags, bool noop, operation* op)+{+ update_cancellation_thread_id(impl);+ iocp_service_.work_started();++ if (noop)+ iocp_service_.on_completion(op);+ else if (!is_open(impl))+ iocp_service_.on_completion(op, asio::error::bad_descriptor);+ else+ {+ DWORD bytes_transferred = 0;+ DWORD recv_flags = flags;+ int result = ::WSARecv(impl.socket_, buffers,+ static_cast<DWORD>(buffer_count),+ &bytes_transferred, &recv_flags, op, 0);+ DWORD last_error = ::WSAGetLastError();+ if (last_error == ERROR_NETNAME_DELETED)+ last_error = WSAECONNRESET;+ else if (last_error == ERROR_PORT_UNREACHABLE)+ last_error = WSAECONNREFUSED;+ if (result != 0 && last_error != WSA_IO_PENDING)+ iocp_service_.on_completion(op, last_error, bytes_transferred);+ else+ iocp_service_.on_pending(op);+ }+}++void win_iocp_socket_service_base::start_null_buffers_receive_op(+ win_iocp_socket_service_base::base_implementation_type& impl,+ socket_base::message_flags flags, reactor_op* op)+{+ if ((impl.state_ & socket_ops::stream_oriented) != 0)+ {+ // For stream sockets on Windows, we may issue a 0-byte overlapped+ // WSARecv to wait until there is data available on the socket.+ ::WSABUF buf = { 0, 0 };+ start_receive_op(impl, &buf, 1, flags, false, op);+ }+ else+ {+ start_reactor_op(impl,+ (flags & socket_base::message_out_of_band)+ ? select_reactor::except_op : select_reactor::read_op,+ op);+ }+}++void win_iocp_socket_service_base::start_receive_from_op(+ win_iocp_socket_service_base::base_implementation_type& impl,+ WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,+ socket_base::message_flags flags, int* addrlen, operation* op)+{+ update_cancellation_thread_id(impl);+ iocp_service_.work_started();++ if (!is_open(impl))+ iocp_service_.on_completion(op, asio::error::bad_descriptor);+ else+ {+ DWORD bytes_transferred = 0;+ DWORD recv_flags = flags;+ int result = ::WSARecvFrom(impl.socket_, buffers,+ static_cast<DWORD>(buffer_count),+ &bytes_transferred, &recv_flags, addr, addrlen, op, 0);+ DWORD last_error = ::WSAGetLastError();+ if (last_error == ERROR_PORT_UNREACHABLE)+ last_error = WSAECONNREFUSED;+ if (result != 0 && last_error != WSA_IO_PENDING)+ iocp_service_.on_completion(op, last_error, bytes_transferred);+ else+ iocp_service_.on_pending(op);+ }+}++void win_iocp_socket_service_base::start_accept_op(+ win_iocp_socket_service_base::base_implementation_type& impl,+ bool peer_is_open, socket_holder& new_socket, int family, int type,+ int protocol, void* output_buffer, DWORD address_length, operation* op)+{+ update_cancellation_thread_id(impl);+ iocp_service_.work_started();++ if (!is_open(impl))+ iocp_service_.on_completion(op, asio::error::bad_descriptor);+ else if (peer_is_open)+ iocp_service_.on_completion(op, asio::error::already_open);+ else+ {+ asio::error_code ec;+ new_socket.reset(socket_ops::socket(family, type, protocol, ec));+ if (new_socket.get() == invalid_socket)+ iocp_service_.on_completion(op, ec);+ else+ {+ DWORD bytes_read = 0;+ BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer,+ 0, address_length, address_length, &bytes_read, op);+ DWORD last_error = ::WSAGetLastError();+ if (!result && last_error != WSA_IO_PENDING)+ iocp_service_.on_completion(op, last_error);+ else+ iocp_service_.on_pending(op);+ }+ }+}++void win_iocp_socket_service_base::restart_accept_op(+ socket_type s, socket_holder& new_socket, int family, int type,+ int protocol, void* output_buffer, DWORD address_length, operation* op)+{+ new_socket.reset();+ iocp_service_.work_started();++ asio::error_code ec;+ new_socket.reset(socket_ops::socket(family, type, protocol, ec));+ if (new_socket.get() == invalid_socket)+ iocp_service_.on_completion(op, ec);+ else+ {+ DWORD bytes_read = 0;+ BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer,+ 0, address_length, address_length, &bytes_read, op);+ DWORD last_error = ::WSAGetLastError();+ if (!result && last_error != WSA_IO_PENDING)+ iocp_service_.on_completion(op, last_error);+ else+ iocp_service_.on_pending(op);+ }+}++void win_iocp_socket_service_base::start_reactor_op(+ win_iocp_socket_service_base::base_implementation_type& impl,+ int op_type, reactor_op* op)+{+ select_reactor& r = get_reactor();+ update_cancellation_thread_id(impl);++ if (is_open(impl))+ {+ r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false, false);+ return;+ }+ else+ op->ec_ = asio::error::bad_descriptor;++ iocp_service_.post_immediate_completion(op, false);+}++void win_iocp_socket_service_base::start_connect_op(+ win_iocp_socket_service_base::base_implementation_type& impl,+ int family, int type, const socket_addr_type* addr,+ std::size_t addrlen, win_iocp_socket_connect_op_base* op)+{+ // If ConnectEx is available, use that.+ if (family == ASIO_OS_DEF(AF_INET)+ || family == ASIO_OS_DEF(AF_INET6))+ {+ if (connect_ex_fn connect_ex = get_connect_ex(impl, type))+ {+ union address_union+ {+ socket_addr_type base;+ sockaddr_in4_type v4;+ sockaddr_in6_type v6;+ } a;++ using namespace std; // For memset.+ memset(&a, 0, sizeof(a));+ a.base.sa_family = family;++ socket_ops::bind(impl.socket_, &a.base,+ family == ASIO_OS_DEF(AF_INET)+ ? sizeof(a.v4) : sizeof(a.v6), op->ec_);+ if (op->ec_ && op->ec_ != asio::error::invalid_argument)+ {+ iocp_service_.post_immediate_completion(op, false);+ return;+ }++ op->connect_ex_ = true;+ update_cancellation_thread_id(impl);+ iocp_service_.work_started();++ BOOL result = connect_ex(impl.socket_,+ addr, static_cast<int>(addrlen), 0, 0, 0, op);+ DWORD last_error = ::WSAGetLastError();+ if (!result && last_error != WSA_IO_PENDING)+ iocp_service_.on_completion(op, last_error);+ else+ iocp_service_.on_pending(op);+ return;+ }+ }++ // Otherwise, fall back to a reactor-based implementation.+ select_reactor& r = get_reactor();+ update_cancellation_thread_id(impl);++ if ((impl.state_ & socket_ops::non_blocking) != 0+ || socket_ops::set_internal_non_blocking(+ impl.socket_, impl.state_, true, op->ec_))+ {+ if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)+ {+ if (op->ec_ == asio::error::in_progress+ || op->ec_ == asio::error::would_block)+ {+ op->ec_ = asio::error_code();+ r.start_op(select_reactor::connect_op, impl.socket_,+ impl.reactor_data_, op, false, false);+ return;+ }+ }+ }++ r.post_immediate_completion(op, false);+}++void win_iocp_socket_service_base::close_for_destruction(+ win_iocp_socket_service_base::base_implementation_type& impl)+{+ if (is_open(impl))+ {+ ASIO_HANDLER_OPERATION((iocp_service_.context(),+ "socket", &impl, impl.socket_, "close"));++ // Check if the reactor was created, in which case we need to close the+ // socket on the reactor as well to cancel any operations that might be+ // running there.+ select_reactor* r = static_cast<select_reactor*>(+ interlocked_compare_exchange_pointer(+ reinterpret_cast<void**>(&reactor_), 0, 0));+ if (r)+ r->deregister_descriptor(impl.socket_, impl.reactor_data_, true);++ asio::error_code ignored_ec;+ socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);++ if (r)+ r->cleanup_descriptor_data(impl.reactor_data_);+ }++ impl.socket_ = invalid_socket;+ impl.state_ = 0;+ impl.cancel_token_.reset();+#if defined(ASIO_ENABLE_CANCELIO)+ impl.safe_cancellation_thread_id_ = 0;+#endif // defined(ASIO_ENABLE_CANCELIO)+}++void win_iocp_socket_service_base::update_cancellation_thread_id(+ win_iocp_socket_service_base::base_implementation_type& impl)+{+#if defined(ASIO_ENABLE_CANCELIO)+ if (impl.safe_cancellation_thread_id_ == 0)+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())+ impl.safe_cancellation_thread_id_ = ~DWORD(0);+#else // defined(ASIO_ENABLE_CANCELIO)+ (void)impl;+#endif // defined(ASIO_ENABLE_CANCELIO)+}++select_reactor& win_iocp_socket_service_base::get_reactor()+{+ select_reactor* r = static_cast<select_reactor*>(+ interlocked_compare_exchange_pointer(+ reinterpret_cast<void**>(&reactor_), 0, 0));+ if (!r)+ {+ r = &(use_service<select_reactor>(context_));+ interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);+ }+ return *r;+}++win_iocp_socket_service_base::connect_ex_fn+win_iocp_socket_service_base::get_connect_ex(+ win_iocp_socket_service_base::base_implementation_type& impl, int type)+{+#if defined(ASIO_DISABLE_CONNECTEX)+ (void)impl;+ (void)type;+ return 0;+#else // defined(ASIO_DISABLE_CONNECTEX)+ if (type != ASIO_OS_DEF(SOCK_STREAM)+ && type != ASIO_OS_DEF(SOCK_SEQPACKET))+ return 0;++ void* ptr = interlocked_compare_exchange_pointer(&connect_ex_, 0, 0);+ if (!ptr)+ {+ GUID guid = { 0x25a207b9, 0xddf3, 0x4660,+ { 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e } };++ DWORD bytes = 0;+ if (::WSAIoctl(impl.socket_, SIO_GET_EXTENSION_FUNCTION_POINTER,+ &guid, sizeof(guid), &ptr, sizeof(ptr), &bytes, 0, 0) != 0)+ {+ // Set connect_ex_ to a special value to indicate that ConnectEx is+ // unavailable. That way we won't bother trying to look it up again.+ ptr = this;+ }++ interlocked_exchange_pointer(&connect_ex_, ptr);+ }++ return reinterpret_cast<connect_ex_fn>(ptr == this ? 0 : ptr);+#endif // defined(ASIO_DISABLE_CONNECTEX)+}++win_iocp_socket_service_base::nt_set_info_fn+win_iocp_socket_service_base::get_nt_set_info()+{+ void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0);+ if (!ptr)+ {+ if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL"))+ ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile"));++ // On failure, set nt_set_info_ to a special value to indicate that the+ // NtSetInformationFile function is unavailable. That way we won't bother+ // trying to look it up again.+ interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this);+ }++ return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr);+}++void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer(+ void** dest, void* exch, void* cmp)+{+#if defined(_M_IX86)+ return reinterpret_cast<void*>(InterlockedCompareExchange(+ reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),+ reinterpret_cast<LONG>(cmp)));+#else+ return InterlockedCompareExchangePointer(dest, exch, cmp);+#endif+}++void* win_iocp_socket_service_base::interlocked_exchange_pointer(+ void** dest, void* val)+{+#if defined(_M_IX86)+ return reinterpret_cast<void*>(InterlockedExchange(+ reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));+#else+ return InterlockedExchangePointer(dest, val);+#endif+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/win_mutex.ipp view
@@ -0,0 +1,84 @@+//+// detail/impl/win_mutex.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WIN_MUTEX_IPP+#define ASIO_DETAIL_IMPL_WIN_MUTEX_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(ASIO_WINDOWS)++#include "asio/detail/throw_error.hpp"+#include "asio/detail/win_mutex.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++win_mutex::win_mutex()+{+ int error = do_init();+ asio::error_code ec(error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "mutex");+}++int win_mutex::do_init()+{+#if defined(__MINGW32__)+ // Not sure if MinGW supports structured exception handling, so for now+ // we'll just call the Windows API and hope.+# if defined(UNDER_CE)+ ::InitializeCriticalSection(&crit_section_);+# elif defined(ASIO_WINDOWS_APP)+ if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0))+ return ::GetLastError();+# else+ if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))+ return ::GetLastError();+# endif+ return 0;+#else+ __try+ {+# if defined(UNDER_CE)+ ::InitializeCriticalSection(&crit_section_);+# elif defined(ASIO_WINDOWS_APP)+ if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0))+ return ::GetLastError();+# else+ if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))+ return ::GetLastError();+# endif+ }+ __except(GetExceptionCode() == STATUS_NO_MEMORY+ ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)+ {+ return ERROR_OUTOFMEMORY;+ }++ return 0;+#endif+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS)++#endif // ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/win_object_handle_service.ipp view
@@ -0,0 +1,448 @@+//+// detail/impl/win_object_handle_service.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2011 Boris Schaeling (boris@highscore.de)+//+// 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_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP+#define ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP++#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_WINDOWS_OBJECT_HANDLE)++#include "asio/detail/win_object_handle_service.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++win_object_handle_service::win_object_handle_service(execution_context& context)+ : execution_context_service_base<win_object_handle_service>(context),+ scheduler_(asio::use_service<scheduler_impl>(context)),+ mutex_(),+ impl_list_(0),+ shutdown_(false)+{+}++void win_object_handle_service::shutdown()+{+ mutex::scoped_lock lock(mutex_);++ // Setting this flag to true prevents new objects from being registered, and+ // new asynchronous wait operations from being started. We only need to worry+ // about cleaning up the operations that are currently in progress.+ shutdown_ = true;++ op_queue<operation> ops;+ for (implementation_type* impl = impl_list_; impl; impl = impl->next_)+ ops.push(impl->op_queue_);++ lock.unlock();++ scheduler_.abandon_operations(ops);+}++void win_object_handle_service::construct(+ win_object_handle_service::implementation_type& impl)+{+ impl.handle_ = INVALID_HANDLE_VALUE;+ impl.wait_handle_ = INVALID_HANDLE_VALUE;+ impl.owner_ = this;++ // Insert implementation into linked list of all implementations.+ mutex::scoped_lock lock(mutex_);+ if (!shutdown_)+ {+ impl.next_ = impl_list_;+ impl.prev_ = 0;+ if (impl_list_)+ impl_list_->prev_ = &impl;+ impl_list_ = &impl;+ }+}++void win_object_handle_service::move_construct(+ win_object_handle_service::implementation_type& impl,+ win_object_handle_service::implementation_type& other_impl)+{+ mutex::scoped_lock lock(mutex_);++ // Insert implementation into linked list of all implementations.+ if (!shutdown_)+ {+ impl.next_ = impl_list_;+ impl.prev_ = 0;+ if (impl_list_)+ impl_list_->prev_ = &impl;+ impl_list_ = &impl;+ }++ impl.handle_ = other_impl.handle_;+ other_impl.handle_ = INVALID_HANDLE_VALUE;+ impl.wait_handle_ = other_impl.wait_handle_;+ other_impl.wait_handle_ = INVALID_HANDLE_VALUE;+ impl.op_queue_.push(other_impl.op_queue_);+ impl.owner_ = this;++ // We must not hold the lock while calling UnregisterWaitEx. This is because+ // the registered callback function might be invoked while we are waiting for+ // UnregisterWaitEx to complete.+ lock.unlock();++ if (impl.wait_handle_ != INVALID_HANDLE_VALUE)+ ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);++ if (!impl.op_queue_.empty())+ register_wait_callback(impl, lock);+}++void win_object_handle_service::move_assign(+ win_object_handle_service::implementation_type& impl,+ win_object_handle_service& other_service,+ win_object_handle_service::implementation_type& other_impl)+{+ asio::error_code ignored_ec;+ close(impl, ignored_ec);++ mutex::scoped_lock lock(mutex_);++ if (this != &other_service)+ {+ // Remove implementation from linked list of all implementations.+ if (impl_list_ == &impl)+ impl_list_ = impl.next_;+ if (impl.prev_)+ impl.prev_->next_ = impl.next_;+ if (impl.next_)+ impl.next_->prev_= impl.prev_;+ impl.next_ = 0;+ impl.prev_ = 0;+ }++ impl.handle_ = other_impl.handle_;+ other_impl.handle_ = INVALID_HANDLE_VALUE;+ impl.wait_handle_ = other_impl.wait_handle_;+ other_impl.wait_handle_ = INVALID_HANDLE_VALUE;+ impl.op_queue_.push(other_impl.op_queue_);+ impl.owner_ = this;++ if (this != &other_service)+ {+ // Insert implementation into linked list of all implementations.+ impl.next_ = other_service.impl_list_;+ impl.prev_ = 0;+ if (other_service.impl_list_)+ other_service.impl_list_->prev_ = &impl;+ other_service.impl_list_ = &impl;+ }++ // We must not hold the lock while calling UnregisterWaitEx. This is because+ // the registered callback function might be invoked while we are waiting for+ // UnregisterWaitEx to complete.+ lock.unlock();++ if (impl.wait_handle_ != INVALID_HANDLE_VALUE)+ ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);++ if (!impl.op_queue_.empty())+ register_wait_callback(impl, lock);+}++void win_object_handle_service::destroy(+ win_object_handle_service::implementation_type& impl)+{+ mutex::scoped_lock lock(mutex_);++ // Remove implementation from linked list of all implementations.+ if (impl_list_ == &impl)+ impl_list_ = impl.next_;+ if (impl.prev_)+ impl.prev_->next_ = impl.next_;+ if (impl.next_)+ impl.next_->prev_= impl.prev_;+ impl.next_ = 0;+ impl.prev_ = 0;++ if (is_open(impl))+ {+ ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",+ &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));++ HANDLE wait_handle = impl.wait_handle_;+ impl.wait_handle_ = INVALID_HANDLE_VALUE;++ op_queue<operation> ops;+ while (wait_op* op = impl.op_queue_.front())+ {+ op->ec_ = asio::error::operation_aborted;+ impl.op_queue_.pop();+ ops.push(op);+ }++ // We must not hold the lock while calling UnregisterWaitEx. This is+ // because the registered callback function might be invoked while we are+ // waiting for UnregisterWaitEx to complete.+ lock.unlock();++ if (wait_handle != INVALID_HANDLE_VALUE)+ ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);++ ::CloseHandle(impl.handle_);+ impl.handle_ = INVALID_HANDLE_VALUE;++ scheduler_.post_deferred_completions(ops);+ }+}++asio::error_code win_object_handle_service::assign(+ win_object_handle_service::implementation_type& impl,+ const native_handle_type& handle, asio::error_code& ec)+{+ if (is_open(impl))+ {+ ec = asio::error::already_open;+ return ec;+ }++ impl.handle_ = handle;+ ec = asio::error_code();+ return ec;+}++asio::error_code win_object_handle_service::close(+ win_object_handle_service::implementation_type& impl,+ asio::error_code& ec)+{+ if (is_open(impl))+ {+ ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",+ &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));++ mutex::scoped_lock lock(mutex_);++ HANDLE wait_handle = impl.wait_handle_;+ impl.wait_handle_ = INVALID_HANDLE_VALUE;++ op_queue<operation> completed_ops;+ while (wait_op* op = impl.op_queue_.front())+ {+ impl.op_queue_.pop();+ op->ec_ = asio::error::operation_aborted;+ completed_ops.push(op);+ }++ // We must not hold the lock while calling UnregisterWaitEx. This is+ // because the registered callback function might be invoked while we are+ // waiting for UnregisterWaitEx to complete.+ lock.unlock();++ if (wait_handle != INVALID_HANDLE_VALUE)+ ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);++ if (::CloseHandle(impl.handle_))+ {+ impl.handle_ = INVALID_HANDLE_VALUE;+ ec = asio::error_code();+ }+ else+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ }++ scheduler_.post_deferred_completions(completed_ops);+ }+ else+ {+ ec = asio::error_code();+ }++ return ec;+}++asio::error_code win_object_handle_service::cancel(+ win_object_handle_service::implementation_type& impl,+ asio::error_code& ec)+{+ if (is_open(impl))+ {+ ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",+ &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel"));++ mutex::scoped_lock lock(mutex_);++ HANDLE wait_handle = impl.wait_handle_;+ impl.wait_handle_ = INVALID_HANDLE_VALUE;++ op_queue<operation> completed_ops;+ while (wait_op* op = impl.op_queue_.front())+ {+ op->ec_ = asio::error::operation_aborted;+ impl.op_queue_.pop();+ completed_ops.push(op);+ }++ // We must not hold the lock while calling UnregisterWaitEx. This is+ // because the registered callback function might be invoked while we are+ // waiting for UnregisterWaitEx to complete.+ lock.unlock();++ if (wait_handle != INVALID_HANDLE_VALUE)+ ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);++ ec = asio::error_code();++ scheduler_.post_deferred_completions(completed_ops);+ }+ else+ {+ ec = asio::error::bad_descriptor;+ }++ return ec;+}++void win_object_handle_service::wait(+ win_object_handle_service::implementation_type& impl,+ asio::error_code& ec)+{+ switch (::WaitForSingleObject(impl.handle_, INFINITE))+ {+ case WAIT_FAILED:+ {+ DWORD last_error = ::GetLastError();+ ec = asio::error_code(last_error,+ asio::error::get_system_category());+ break;+ }+ case WAIT_OBJECT_0:+ case WAIT_ABANDONED:+ default:+ ec = asio::error_code();+ break;+ }+}++void win_object_handle_service::start_wait_op(+ win_object_handle_service::implementation_type& impl, wait_op* op)+{+ scheduler_.work_started();++ if (is_open(impl))+ {+ mutex::scoped_lock lock(mutex_);++ if (!shutdown_)+ {+ impl.op_queue_.push(op);++ // Only the first operation to be queued gets to register a wait callback.+ // Subsequent operations have to wait for the first to finish.+ if (impl.op_queue_.front() == op)+ register_wait_callback(impl, lock);+ }+ else+ {+ lock.unlock();+ scheduler_.post_deferred_completion(op);+ }+ }+ else+ {+ op->ec_ = asio::error::bad_descriptor;+ scheduler_.post_deferred_completion(op);+ }+}++void win_object_handle_service::register_wait_callback(+ win_object_handle_service::implementation_type& impl,+ mutex::scoped_lock& lock)+{+ lock.lock();++ if (!RegisterWaitForSingleObject(&impl.wait_handle_,+ impl.handle_, &win_object_handle_service::wait_callback,+ &impl, INFINITE, WT_EXECUTEONLYONCE))+ {+ DWORD last_error = ::GetLastError();+ asio::error_code ec(last_error,+ asio::error::get_system_category());++ op_queue<operation> completed_ops;+ while (wait_op* op = impl.op_queue_.front())+ {+ op->ec_ = ec;+ impl.op_queue_.pop();+ completed_ops.push(op);+ }++ lock.unlock();+ scheduler_.post_deferred_completions(completed_ops);+ }+}++void win_object_handle_service::wait_callback(PVOID param, BOOLEAN)+{+ implementation_type* impl = static_cast<implementation_type*>(param);+ mutex::scoped_lock lock(impl->owner_->mutex_);++ if (impl->wait_handle_ != INVALID_HANDLE_VALUE)+ {+ ::UnregisterWaitEx(impl->wait_handle_, NULL);+ impl->wait_handle_ = INVALID_HANDLE_VALUE;+ }++ if (wait_op* op = impl->op_queue_.front())+ {+ op_queue<operation> completed_ops;++ op->ec_ = asio::error_code();+ impl->op_queue_.pop();+ completed_ops.push(op);++ if (!impl->op_queue_.empty())+ {+ if (!RegisterWaitForSingleObject(&impl->wait_handle_,+ impl->handle_, &win_object_handle_service::wait_callback,+ param, INFINITE, WT_EXECUTEONLYONCE))+ {+ DWORD last_error = ::GetLastError();+ asio::error_code ec(last_error,+ asio::error::get_system_category());++ while ((op = impl->op_queue_.front()) != 0)+ {+ op->ec_ = ec;+ impl->op_queue_.pop();+ completed_ops.push(op);+ }+ }+ }++ scheduler_impl& sched = impl->owner_->scheduler_;+ lock.unlock();+ sched.post_deferred_completions(completed_ops);+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)++#endif // ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/win_static_mutex.ipp view
@@ -0,0 +1,136 @@+//+// detail/impl/win_static_mutex.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WIN_STATIC_MUTEX_IPP+#define ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(ASIO_WINDOWS)++#include <cstdio>+#include "asio/detail/throw_error.hpp"+#include "asio/detail/win_static_mutex.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++void win_static_mutex::init()+{+ int error = do_init();+ asio::error_code ec(error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "static_mutex");+}++int win_static_mutex::do_init()+{+ using namespace std; // For sprintf.+ wchar_t mutex_name[128];+#if defined(ASIO_HAS_SECURE_RTL)+ swprintf_s(+#else // defined(ASIO_HAS_SECURE_RTL)+ _snwprintf(+#endif // defined(ASIO_HAS_SECURE_RTL)+ mutex_name, 128, L"asio-58CCDC44-6264-4842-90C2-F3C545CB8AA7-%u-%p",+ static_cast<unsigned int>(::GetCurrentProcessId()), this);++#if defined(ASIO_WINDOWS_APP)+ HANDLE mutex = ::CreateMutexExW(0, mutex_name, CREATE_MUTEX_INITIAL_OWNER, 0);+#else // defined(ASIO_WINDOWS_APP)+ HANDLE mutex = ::CreateMutexW(0, TRUE, mutex_name);+#endif // defined(ASIO_WINDOWS_APP)+ DWORD last_error = ::GetLastError();+ if (mutex == 0)+ return ::GetLastError();++ if (last_error == ERROR_ALREADY_EXISTS)+ {+#if defined(ASIO_WINDOWS_APP)+ ::WaitForSingleObjectEx(mutex, INFINITE, false);+#else // defined(ASIO_WINDOWS_APP)+ ::WaitForSingleObject(mutex, INFINITE);+#endif // defined(ASIO_WINDOWS_APP)+ }++ if (initialised_)+ {+ ::ReleaseMutex(mutex);+ ::CloseHandle(mutex);+ return 0;+ }++#if defined(__MINGW32__)+ // Not sure if MinGW supports structured exception handling, so for now+ // we'll just call the Windows API and hope.+# if defined(UNDER_CE)+ ::InitializeCriticalSection(&crit_section_);+# else+ if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))+ {+ last_error = ::GetLastError();+ ::ReleaseMutex(mutex);+ ::CloseHandle(mutex);+ return last_error;+ }+# endif+#else+ __try+ {+# if defined(UNDER_CE)+ ::InitializeCriticalSection(&crit_section_);+# elif defined(ASIO_WINDOWS_APP)+ if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0))+ {+ last_error = ::GetLastError();+ ::ReleaseMutex(mutex);+ ::CloseHandle(mutex);+ return last_error;+ }+# else+ if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))+ {+ last_error = ::GetLastError();+ ::ReleaseMutex(mutex);+ ::CloseHandle(mutex);+ return last_error;+ }+# endif+ }+ __except(GetExceptionCode() == STATUS_NO_MEMORY+ ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)+ {+ ::ReleaseMutex(mutex);+ ::CloseHandle(mutex);+ return ERROR_OUTOFMEMORY;+ }+#endif++ initialised_ = true;+ ::ReleaseMutex(mutex);+ ::CloseHandle(mutex);+ return 0;+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS)++#endif // ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/win_thread.ipp view
@@ -0,0 +1,150 @@+//+// detail/impl/win_thread.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WIN_THREAD_IPP+#define ASIO_DETAIL_IMPL_WIN_THREAD_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_APP) \+ && !defined(UNDER_CE)++#include <process.h>+#include "asio/detail/throw_error.hpp"+#include "asio/detail/win_thread.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++win_thread::~win_thread()+{+ ::CloseHandle(thread_);++ // The exit_event_ handle is deliberately allowed to leak here since it+ // is an error for the owner of an internal thread not to join() it.+}++void win_thread::join()+{+ HANDLE handles[2] = { exit_event_, thread_ };+ ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);+ ::CloseHandle(exit_event_);+ if (terminate_threads())+ {+ ::TerminateThread(thread_, 0);+ }+ else+ {+ ::QueueUserAPC(apc_function, thread_, 0);+ ::WaitForSingleObject(thread_, INFINITE);+ }+}++std::size_t win_thread::hardware_concurrency()+{+ SYSTEM_INFO system_info;+ ::GetSystemInfo(&system_info);+ return system_info.dwNumberOfProcessors;+}++void win_thread::start_thread(func_base* arg, unsigned int stack_size)+{+ ::HANDLE entry_event = 0;+ arg->entry_event_ = entry_event = ::CreateEventW(0, true, false, 0);+ if (!entry_event)+ {+ DWORD last_error = ::GetLastError();+ delete arg;+ asio::error_code ec(last_error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "thread.entry_event");+ }++ arg->exit_event_ = exit_event_ = ::CreateEventW(0, true, false, 0);+ if (!exit_event_)+ {+ DWORD last_error = ::GetLastError();+ delete arg;+ asio::error_code ec(last_error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "thread.exit_event");+ }++ unsigned int thread_id = 0;+ thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0,+ stack_size, win_thread_function, arg, 0, &thread_id));+ if (!thread_)+ {+ DWORD last_error = ::GetLastError();+ delete arg;+ if (entry_event)+ ::CloseHandle(entry_event);+ if (exit_event_)+ ::CloseHandle(exit_event_);+ asio::error_code ec(last_error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "thread");+ }++ if (entry_event)+ {+ ::WaitForSingleObject(entry_event, INFINITE);+ ::CloseHandle(entry_event);+ }+}++unsigned int __stdcall win_thread_function(void* arg)+{+ win_thread::auto_func_base_ptr func = {+ static_cast<win_thread::func_base*>(arg) };++ ::SetEvent(func.ptr->entry_event_);++ func.ptr->run();++ // Signal that the thread has finished its work, but rather than returning go+ // to sleep to put the thread into a well known state. If the thread is being+ // joined during global object destruction then it may be killed using+ // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx+ // call will be interrupted using QueueUserAPC and the thread will shut down+ // cleanly.+ HANDLE exit_event = func.ptr->exit_event_;+ delete func.ptr;+ func.ptr = 0;+ ::SetEvent(exit_event);+ ::SleepEx(INFINITE, TRUE);++ return 0;+}++#if defined(WINVER) && (WINVER < 0x0500)+void __stdcall apc_function(ULONG) {}+#else+void __stdcall apc_function(ULONG_PTR) {}+#endif++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_APP)+ // && !defined(UNDER_CE)++#endif // ASIO_DETAIL_IMPL_WIN_THREAD_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/win_tss_ptr.ipp view
@@ -0,0 +1,57 @@+//+// detail/impl/win_tss_ptr.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WIN_TSS_PTR_IPP+#define ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(ASIO_WINDOWS)++#include "asio/detail/throw_error.hpp"+#include "asio/detail/win_tss_ptr.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++DWORD win_tss_ptr_create()+{+#if defined(UNDER_CE)+ const DWORD out_of_indexes = 0xFFFFFFFF;+#else+ const DWORD out_of_indexes = TLS_OUT_OF_INDEXES;+#endif++ DWORD tss_key = ::TlsAlloc();+ if (tss_key == out_of_indexes)+ {+ DWORD last_error = ::GetLastError();+ asio::error_code ec(last_error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "tss");+ }+ return tss_key;+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS)++#endif // ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_ssocket_service_base.ipp view
@@ -0,0 +1,626 @@+//+// detail/impl/winrt_ssocket_service_base.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP+#define ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(ASIO_WINDOWS_RUNTIME)++#include <cstring>+#include "asio/detail/winrt_ssocket_service_base.hpp"+#include "asio/detail/winrt_async_op.hpp"+#include "asio/detail/winrt_utils.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++winrt_ssocket_service_base::winrt_ssocket_service_base(+ execution_context& context)+ : scheduler_(use_service<scheduler_impl>(context)),+ async_manager_(use_service<winrt_async_manager>(context)),+ mutex_(),+ impl_list_(0)+{+}++void winrt_ssocket_service_base::base_shutdown()+{+ // Close all implementations, causing all operations to complete.+ asio::detail::mutex::scoped_lock lock(mutex_);+ base_implementation_type* impl = impl_list_;+ while (impl)+ {+ asio::error_code ignored_ec;+ close(*impl, ignored_ec);+ impl = impl->next_;+ }+}++void winrt_ssocket_service_base::construct(+ winrt_ssocket_service_base::base_implementation_type& impl)+{+ // Insert implementation into linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ impl.next_ = impl_list_;+ impl.prev_ = 0;+ if (impl_list_)+ impl_list_->prev_ = &impl;+ impl_list_ = &impl;+}++void winrt_ssocket_service_base::base_move_construct(+ winrt_ssocket_service_base::base_implementation_type& impl,+ winrt_ssocket_service_base::base_implementation_type& other_impl)+ ASIO_NOEXCEPT+{+ impl.socket_ = other_impl.socket_;+ other_impl.socket_ = nullptr;++ // Insert implementation into linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ impl.next_ = impl_list_;+ impl.prev_ = 0;+ if (impl_list_)+ impl_list_->prev_ = &impl;+ impl_list_ = &impl;+}++void winrt_ssocket_service_base::base_move_assign(+ winrt_ssocket_service_base::base_implementation_type& impl,+ winrt_ssocket_service_base& other_service,+ winrt_ssocket_service_base::base_implementation_type& other_impl)+{+ asio::error_code ignored_ec;+ close(impl, ignored_ec);++ if (this != &other_service)+ {+ // Remove implementation from linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ if (impl_list_ == &impl)+ impl_list_ = impl.next_;+ if (impl.prev_)+ impl.prev_->next_ = impl.next_;+ if (impl.next_)+ impl.next_->prev_= impl.prev_;+ impl.next_ = 0;+ impl.prev_ = 0;+ }++ impl.socket_ = other_impl.socket_;+ other_impl.socket_ = nullptr;++ if (this != &other_service)+ {+ // Insert implementation into linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(other_service.mutex_);+ impl.next_ = other_service.impl_list_;+ impl.prev_ = 0;+ if (other_service.impl_list_)+ other_service.impl_list_->prev_ = &impl;+ other_service.impl_list_ = &impl;+ }+}++void winrt_ssocket_service_base::destroy(+ winrt_ssocket_service_base::base_implementation_type& impl)+{+ asio::error_code ignored_ec;+ close(impl, ignored_ec);++ // Remove implementation from linked list of all implementations.+ asio::detail::mutex::scoped_lock lock(mutex_);+ if (impl_list_ == &impl)+ impl_list_ = impl.next_;+ if (impl.prev_)+ impl.prev_->next_ = impl.next_;+ if (impl.next_)+ impl.next_->prev_= impl.prev_;+ impl.next_ = 0;+ impl.prev_ = 0;+}++asio::error_code winrt_ssocket_service_base::close(+ winrt_ssocket_service_base::base_implementation_type& impl,+ asio::error_code& ec)+{+ delete impl.socket_;+ impl.socket_ = nullptr;+ ec = asio::error_code();+ return ec;+}++winrt_ssocket_service_base::native_handle_type+winrt_ssocket_service_base::release(+ winrt_ssocket_service_base::base_implementation_type& impl,+ asio::error_code& ec)+{+ if (!is_open(impl))+ return nullptr;++ cancel(impl, ec);+ if (ec)+ return nullptr;++ native_handle_type tmp = impl.socket_;+ impl.socket_ = nullptr;+ return tmp;+}++std::size_t winrt_ssocket_service_base::do_get_endpoint(+ const base_implementation_type& impl, bool local,+ void* addr, std::size_t addr_len, asio::error_code& ec) const+{+ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return addr_len;+ }++ try+ {+ std::string addr_string = winrt_utils::string(local+ ? impl.socket_->Information->LocalAddress->CanonicalName+ : impl.socket_->Information->RemoteAddress->CanonicalName);+ unsigned short port = winrt_utils::integer(local+ ? impl.socket_->Information->LocalPort+ : impl.socket_->Information->RemotePort);+ unsigned long scope = 0;++ switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)+ {+ case ASIO_OS_DEF(AF_INET):+ if (addr_len < sizeof(sockaddr_in4_type))+ {+ ec = asio::error::invalid_argument;+ return addr_len;+ }+ else+ {+ socket_ops::inet_pton(ASIO_OS_DEF(AF_INET), addr_string.c_str(),+ &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec);+ reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port+ = socket_ops::host_to_network_short(port);+ ec = asio::error_code();+ return sizeof(sockaddr_in4_type);+ }+ case ASIO_OS_DEF(AF_INET6):+ if (addr_len < sizeof(sockaddr_in6_type))+ {+ ec = asio::error::invalid_argument;+ return addr_len;+ }+ else+ {+ socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6), addr_string.c_str(),+ &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec);+ reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port+ = socket_ops::host_to_network_short(port);+ ec = asio::error_code();+ return sizeof(sockaddr_in6_type);+ }+ default:+ ec = asio::error::address_family_not_supported;+ return addr_len;+ }+ }+ catch (Platform::Exception^ e)+ {+ ec = asio::error_code(e->HResult,+ asio::system_category());+ return addr_len;+ }+}++asio::error_code winrt_ssocket_service_base::do_set_option(+ winrt_ssocket_service_base::base_implementation_type& impl,+ int level, int optname, const void* optval,+ std::size_t optlen, asio::error_code& ec)+{+ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return ec;+ }++ try+ {+ if (level == ASIO_OS_DEF(SOL_SOCKET)+ && optname == ASIO_OS_DEF(SO_KEEPALIVE))+ {+ if (optlen == sizeof(int))+ {+ int value = 0;+ std::memcpy(&value, optval, optlen);+ impl.socket_->Control->KeepAlive = !!value;+ ec = asio::error_code();+ }+ else+ {+ ec = asio::error::invalid_argument;+ }+ }+ else if (level == ASIO_OS_DEF(IPPROTO_TCP)+ && optname == ASIO_OS_DEF(TCP_NODELAY))+ {+ if (optlen == sizeof(int))+ {+ int value = 0;+ std::memcpy(&value, optval, optlen);+ impl.socket_->Control->NoDelay = !!value;+ ec = asio::error_code();+ }+ else+ {+ ec = asio::error::invalid_argument;+ }+ }+ else+ {+ ec = asio::error::invalid_argument;+ }+ }+ catch (Platform::Exception^ e)+ {+ ec = asio::error_code(e->HResult,+ asio::system_category());+ }++ return ec;+}++void winrt_ssocket_service_base::do_get_option(+ const winrt_ssocket_service_base::base_implementation_type& impl,+ int level, int optname, void* optval,+ std::size_t* optlen, asio::error_code& ec) const+{+ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return;+ }++ try+ {+ if (level == ASIO_OS_DEF(SOL_SOCKET)+ && optname == ASIO_OS_DEF(SO_KEEPALIVE))+ {+ if (*optlen >= sizeof(int))+ {+ int value = impl.socket_->Control->KeepAlive ? 1 : 0;+ std::memcpy(optval, &value, sizeof(int));+ *optlen = sizeof(int);+ ec = asio::error_code();+ }+ else+ {+ ec = asio::error::invalid_argument;+ }+ }+ else if (level == ASIO_OS_DEF(IPPROTO_TCP)+ && optname == ASIO_OS_DEF(TCP_NODELAY))+ {+ if (*optlen >= sizeof(int))+ {+ int value = impl.socket_->Control->NoDelay ? 1 : 0;+ std::memcpy(optval, &value, sizeof(int));+ *optlen = sizeof(int);+ ec = asio::error_code();+ }+ else+ {+ ec = asio::error::invalid_argument;+ }+ }+ else+ {+ ec = asio::error::invalid_argument;+ }+ }+ catch (Platform::Exception^ e)+ {+ ec = asio::error_code(e->HResult,+ asio::system_category());+ }+}++asio::error_code winrt_ssocket_service_base::do_connect(+ winrt_ssocket_service_base::base_implementation_type& impl,+ const void* addr, asio::error_code& ec)+{+ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return ec;+ }++ char addr_string[max_addr_v6_str_len];+ unsigned short port;+ switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)+ {+ case ASIO_OS_DEF(AF_INET):+ socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET),+ &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,+ addr_string, sizeof(addr_string), 0, ec);+ port = socket_ops::network_to_host_short(+ reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);+ break;+ case ASIO_OS_DEF(AF_INET6):+ socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6),+ &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,+ addr_string, sizeof(addr_string), 0, ec);+ port = socket_ops::network_to_host_short(+ reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);+ break;+ default:+ ec = asio::error::address_family_not_supported;+ return ec;+ }++ if (!ec) try+ {+ async_manager_.sync(impl.socket_->ConnectAsync(+ ref new Windows::Networking::HostName(+ winrt_utils::string(addr_string)),+ winrt_utils::string(port)), ec);+ }+ catch (Platform::Exception^ e)+ {+ ec = asio::error_code(e->HResult,+ asio::system_category());+ }++ return ec;+}++void winrt_ssocket_service_base::start_connect_op(+ winrt_ssocket_service_base::base_implementation_type& impl,+ const void* addr, winrt_async_op<void>* op, bool is_continuation)+{+ if (!is_open(impl))+ {+ op->ec_ = asio::error::bad_descriptor;+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }++ char addr_string[max_addr_v6_str_len];+ unsigned short port = 0;+ switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)+ {+ case ASIO_OS_DEF(AF_INET):+ socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET),+ &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,+ addr_string, sizeof(addr_string), 0, op->ec_);+ port = socket_ops::network_to_host_short(+ reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);+ break;+ case ASIO_OS_DEF(AF_INET6):+ socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6),+ &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,+ addr_string, sizeof(addr_string), 0, op->ec_);+ port = socket_ops::network_to_host_short(+ reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);+ break;+ default:+ op->ec_ = asio::error::address_family_not_supported;+ break;+ }++ if (op->ec_)+ {+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }++ try+ {+ async_manager_.async(impl.socket_->ConnectAsync(+ ref new Windows::Networking::HostName(+ winrt_utils::string(addr_string)),+ winrt_utils::string(port)), op);+ }+ catch (Platform::Exception^ e)+ {+ op->ec_ = asio::error_code(+ e->HResult, asio::system_category());+ scheduler_.post_immediate_completion(op, is_continuation);+ }+}++std::size_t winrt_ssocket_service_base::do_send(+ winrt_ssocket_service_base::base_implementation_type& impl,+ const asio::const_buffer& data,+ socket_base::message_flags flags, asio::error_code& ec)+{+ if (flags)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ try+ {+ buffer_sequence_adapter<asio::const_buffer,+ asio::const_buffer> bufs(asio::buffer(data));++ if (bufs.all_empty())+ {+ ec = asio::error_code();+ return 0;+ }++ return async_manager_.sync(+ impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec);+ }+ catch (Platform::Exception^ e)+ {+ ec = asio::error_code(e->HResult,+ asio::system_category());+ return 0;+ }+}++void winrt_ssocket_service_base::start_send_op(+ winrt_ssocket_service_base::base_implementation_type& impl,+ const asio::const_buffer& data, socket_base::message_flags flags,+ winrt_async_op<unsigned int>* op, bool is_continuation)+{+ if (flags)+ {+ op->ec_ = asio::error::operation_not_supported;+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }++ if (!is_open(impl))+ {+ op->ec_ = asio::error::bad_descriptor;+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }++ try+ {+ buffer_sequence_adapter<asio::const_buffer,+ asio::const_buffer> bufs(asio::buffer(data));++ if (bufs.all_empty())+ {+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }++ async_manager_.async(+ impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op);+ }+ catch (Platform::Exception^ e)+ {+ op->ec_ = asio::error_code(e->HResult,+ asio::system_category());+ scheduler_.post_immediate_completion(op, is_continuation);+ }+}++std::size_t winrt_ssocket_service_base::do_receive(+ winrt_ssocket_service_base::base_implementation_type& impl,+ const asio::mutable_buffer& data,+ socket_base::message_flags flags, asio::error_code& ec)+{+ if (flags)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ if (!is_open(impl))+ {+ ec = asio::error::bad_descriptor;+ return 0;+ }++ try+ {+ buffer_sequence_adapter<asio::mutable_buffer,+ asio::mutable_buffer> bufs(asio::buffer(data));++ if (bufs.all_empty())+ {+ ec = asio::error_code();+ return 0;+ }++ async_manager_.sync(+ impl.socket_->InputStream->ReadAsync(+ bufs.buffers()[0], bufs.buffers()[0]->Capacity,+ Windows::Storage::Streams::InputStreamOptions::Partial), ec);++ std::size_t bytes_transferred = bufs.buffers()[0]->Length;+ if (bytes_transferred == 0 && !ec)+ {+ ec = asio::error::eof;+ }++ return bytes_transferred;+ }+ catch (Platform::Exception^ e)+ {+ ec = asio::error_code(e->HResult,+ asio::system_category());+ return 0;+ }+}++void winrt_ssocket_service_base::start_receive_op(+ winrt_ssocket_service_base::base_implementation_type& impl,+ const asio::mutable_buffer& data, socket_base::message_flags flags,+ winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,+ bool is_continuation)+{+ if (flags)+ {+ op->ec_ = asio::error::operation_not_supported;+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }++ if (!is_open(impl))+ {+ op->ec_ = asio::error::bad_descriptor;+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }++ try+ {+ buffer_sequence_adapter<asio::mutable_buffer,+ asio::mutable_buffer> bufs(asio::buffer(data));++ if (bufs.all_empty())+ {+ scheduler_.post_immediate_completion(op, is_continuation);+ return;+ }++ async_manager_.async(+ impl.socket_->InputStream->ReadAsync(+ bufs.buffers()[0], bufs.buffers()[0]->Capacity,+ Windows::Storage::Streams::InputStreamOptions::Partial), op);+ }+ catch (Platform::Exception^ e)+ {+ op->ec_ = asio::error_code(e->HResult,+ asio::system_category());+ scheduler_.post_immediate_completion(op, is_continuation);+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_timer_scheduler.hpp view
@@ -0,0 +1,92 @@+//+// detail/impl/winrt_timer_scheduler.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WINRT_TIMER_SCHEDULER_HPP+#define ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_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_WINDOWS_RUNTIME)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Time_Traits>+void winrt_timer_scheduler::add_timer_queue(timer_queue<Time_Traits>& queue)+{+ do_add_timer_queue(queue);+}++// Remove a timer queue from the reactor.+template <typename Time_Traits>+void winrt_timer_scheduler::remove_timer_queue(timer_queue<Time_Traits>& queue)+{+ do_remove_timer_queue(queue);+}++template <typename Time_Traits>+void winrt_timer_scheduler::schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)+{+ asio::detail::mutex::scoped_lock lock(mutex_);++ if (shutdown_)+ {+ scheduler_.post_immediate_completion(op, false);+ return;+ }++ bool earliest = queue.enqueue_timer(time, timer, op);+ scheduler_.work_started();+ if (earliest)+ event_.signal(lock);+}++template <typename Time_Traits>+std::size_t winrt_timer_scheduler::cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled)+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ op_queue<operation> ops;+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);+ lock.unlock();+ scheduler_.post_deferred_completions(ops);+ return n;+}++template <typename Time_Traits>+void winrt_timer_scheduler::move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& to,+ typename timer_queue<Time_Traits>::per_timer_data& from)+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ op_queue<operation> ops;+ queue.cancel_timer(to, ops);+ queue.move_timer(to, from);+ lock.unlock();+ scheduler_.post_deferred_completions(ops);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/winrt_timer_scheduler.ipp view
@@ -0,0 +1,121 @@+//+// detail/impl/winrt_timer_scheduler.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WINRT_TIMER_SCHEDULER_IPP+#define ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(ASIO_WINDOWS_RUNTIME)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/winrt_timer_scheduler.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++winrt_timer_scheduler::winrt_timer_scheduler(execution_context& context)+ : execution_context_service_base<winrt_timer_scheduler>(context),+ scheduler_(use_service<scheduler_impl>(context)),+ mutex_(),+ event_(),+ timer_queues_(),+ thread_(0),+ stop_thread_(false),+ shutdown_(false)+{+ thread_ = new asio::detail::thread(+ bind_handler(&winrt_timer_scheduler::call_run_thread, this));+}++winrt_timer_scheduler::~winrt_timer_scheduler()+{+ shutdown();+}++void winrt_timer_scheduler::shutdown()+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ shutdown_ = true;+ stop_thread_ = true;+ event_.signal(lock);+ lock.unlock();++ if (thread_)+ {+ thread_->join();+ delete thread_;+ thread_ = 0;+ }++ op_queue<operation> ops;+ timer_queues_.get_all_timers(ops);+ scheduler_.abandon_operations(ops);+}++void winrt_timer_scheduler::notify_fork(execution_context::fork_event)+{+}++void winrt_timer_scheduler::init_task()+{+}++void winrt_timer_scheduler::run_thread()+{+ asio::detail::mutex::scoped_lock lock(mutex_);+ while (!stop_thread_)+ {+ const long max_wait_duration = 5 * 60 * 1000000;+ long wait_duration = timer_queues_.wait_duration_usec(max_wait_duration);+ event_.wait_for_usec(lock, wait_duration);+ event_.clear(lock);+ op_queue<operation> ops;+ timer_queues_.get_ready_timers(ops);+ if (!ops.empty())+ {+ lock.unlock();+ scheduler_.post_deferred_completions(ops);+ lock.lock();+ }+ }+}++void winrt_timer_scheduler::call_run_thread(winrt_timer_scheduler* scheduler)+{+ scheduler->run_thread();+}++void winrt_timer_scheduler::do_add_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(mutex_);+ timer_queues_.insert(&queue);+}++void winrt_timer_scheduler::do_remove_timer_queue(timer_queue_base& queue)+{+ mutex::scoped_lock lock(mutex_);+ timer_queues_.erase(&queue);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/impl/winsock_init.ipp view
@@ -0,0 +1,82 @@+//+// detail/impl/winsock_init.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WINSOCK_INIT_IPP+#define ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)++#include "asio/detail/socket_types.hpp"+#include "asio/detail/winsock_init.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++void winsock_init_base::startup(data& d,+ unsigned char major, unsigned char minor)+{+ if (::InterlockedIncrement(&d.init_count_) == 1)+ {+ WSADATA wsa_data;+ long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data);+ ::InterlockedExchange(&d.result_, result);+ }+}++void winsock_init_base::manual_startup(data& d)+{+ if (::InterlockedIncrement(&d.init_count_) == 1)+ {+ ::InterlockedExchange(&d.result_, 0);+ }+}++void winsock_init_base::cleanup(data& d)+{+ if (::InterlockedDecrement(&d.init_count_) == 0)+ {+ ::WSACleanup();+ }+}++void winsock_init_base::manual_cleanup(data& d)+{+ ::InterlockedDecrement(&d.init_count_);+}++void winsock_init_base::throw_on_error(data& d)+{+ long result = ::InterlockedExchangeAdd(&d.result_, 0);+ if (result != 0)+ {+ asio::error_code ec(result,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "winsock");+ }+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++#endif // ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
+ link/modules/asio-standalone/asio/include/asio/detail/io_control.hpp view
@@ -0,0 +1,84 @@+//+// detail/io_control.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IO_CONTROL_HPP+#define ASIO_DETAIL_IO_CONTROL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {+namespace io_control {++// I/O control command for getting number of bytes available.+class bytes_readable+{+public:+ // Default constructor.+ bytes_readable()+ : value_(0)+ {+ }++ // Construct with a specific command value.+ bytes_readable(std::size_t value)+ : value_(static_cast<detail::ioctl_arg_type>(value))+ {+ }++ // Get the name of the IO control command.+ int name() const+ {+ return static_cast<int>(ASIO_OS_DEF(FIONREAD));+ }++ // Set the value of the I/O control command.+ void set(std::size_t value)+ {+ value_ = static_cast<detail::ioctl_arg_type>(value);+ }++ // Get the current value of the I/O control command.+ std::size_t get() const+ {+ return static_cast<std::size_t>(value_);+ }++ // Get the address of the command data.+ detail::ioctl_arg_type* data()+ {+ return &value_;+ }++ // Get the address of the command data.+ const detail::ioctl_arg_type* data() const+ {+ return &value_;+ }++private:+ detail::ioctl_arg_type value_;+};++} // namespace io_control+} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IO_CONTROL_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/io_object_impl.hpp view
@@ -0,0 +1,175 @@+//+// io_object_impl.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IO_OBJECT_IMPL_HPP+#define ASIO_DETAIL_IO_OBJECT_IMPL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include <new>+#include "asio/detail/config.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution/context.hpp"+#include "asio/io_context.hpp"+#include "asio/query.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename IoObjectService,+ typename Executor = io_context::executor_type>+class io_object_impl+{+public:+ // The type of the service that will be used to provide I/O operations.+ typedef IoObjectService service_type;++ // The underlying implementation type of I/O object.+ typedef typename service_type::implementation_type implementation_type;++ // The type of the executor associated with the object.+ typedef Executor executor_type;++ // Construct an I/O object using an executor.+ explicit io_object_impl(const executor_type& ex)+ : service_(&asio::use_service<IoObjectService>(+ io_object_impl::get_context(ex))),+ executor_(ex)+ {+ service_->construct(implementation_);+ }++ // Construct an I/O object using an execution context.+ template <typename ExecutionContext>+ explicit io_object_impl(ExecutionContext& context,+ typename enable_if<is_convertible<+ ExecutionContext&, execution_context&>::value>::type* = 0)+ : service_(&asio::use_service<IoObjectService>(context)),+ executor_(context.get_executor())+ {+ service_->construct(implementation_);+ }++#if defined(ASIO_HAS_MOVE)+ // Move-construct an I/O object.+ io_object_impl(io_object_impl&& other)+ : service_(&other.get_service()),+ executor_(other.get_executor())+ {+ service_->move_construct(implementation_, other.implementation_);+ }++ // Perform a converting move-construction of an I/O object.+ template <typename IoObjectService1, typename Executor1>+ io_object_impl(io_object_impl<IoObjectService1, Executor1>&& other)+ : service_(&asio::use_service<IoObjectService>(+ io_object_impl::get_context(other.get_executor()))),+ executor_(other.get_executor())+ {+ service_->converting_move_construct(implementation_,+ other.get_service(), other.get_implementation());+ }+#endif // defined(ASIO_HAS_MOVE)++ // Destructor.+ ~io_object_impl()+ {+ service_->destroy(implementation_);+ }++#if defined(ASIO_HAS_MOVE)+ // Move-assign an I/O object.+ io_object_impl& operator=(io_object_impl&& other)+ {+ if (this != &other)+ {+ service_->move_assign(implementation_,+ *other.service_, other.implementation_);+ executor_.~executor_type();+ new (&executor_) executor_type(+ std::move(other.executor_));+ service_ = other.service_;+ }+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE)++ // Get the executor associated with the object.+ const executor_type& get_executor() ASIO_NOEXCEPT+ {+ return executor_;+ }++ // Get the service associated with the I/O object.+ service_type& get_service()+ {+ return *service_;+ }++ // Get the service associated with the I/O object.+ const service_type& get_service() const+ {+ return *service_;+ }++ // Get the underlying implementation of the I/O object.+ implementation_type& get_implementation()+ {+ return implementation_;+ }++ // Get the underlying implementation of the I/O object.+ const implementation_type& get_implementation() const+ {+ return implementation_;+ }++private:+ // Helper function to get an executor's context.+ template <typename T>+ static execution_context& get_context(const T& t,+ typename enable_if<execution::is_executor<T>::value>::type* = 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,+ typename enable_if<!execution::is_executor<T>::value>::type* = 0)+ {+ return t.context();+ }++ // Disallow copying and copy assignment.+ io_object_impl(const io_object_impl&);+ io_object_impl& operator=(const io_object_impl&);++ // The service associated with the I/O object.+ service_type* service_;++ // The underlying implementation of the I/O object.+ implementation_type implementation_;++ // The associated executor.+ executor_type executor_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IO_OBJECT_IMPL_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/is_buffer_sequence.hpp view
@@ -0,0 +1,312 @@+//+// detail/is_buffer_sequence.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IS_BUFFER_SEQUENCE_HPP+#define ASIO_DETAIL_IS_BUFFER_SEQUENCE_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 {++class mutable_buffer;+class const_buffer;++namespace detail {++struct buffer_sequence_memfns_base+{+ void begin();+ void end();+ void size();+ void max_size();+ void capacity();+ void data();+ void prepare();+ void commit();+ void consume();+ void grow();+ void shrink();+};++template <typename T>+struct buffer_sequence_memfns_derived+ : T, buffer_sequence_memfns_base+{+};++template <typename T, T>+struct buffer_sequence_memfns_check+{+};++#if defined(ASIO_HAS_DECLTYPE)++template <typename>+char buffer_sequence_begin_helper(...);++template <typename T>+char (&buffer_sequence_begin_helper(T* t,+ typename enable_if<!is_same<+ decltype(asio::buffer_sequence_begin(*t)),+ void>::value>::type*))[2];++#else // defined(ASIO_HAS_DECLTYPE)++template <typename>+char (&buffer_sequence_begin_helper(...))[2];++template <typename T>+char buffer_sequence_begin_helper(T* t,+ buffer_sequence_memfns_check<+ void (buffer_sequence_memfns_base::*)(),+ &buffer_sequence_memfns_derived<T>::begin>*);++#endif // defined(ASIO_HAS_DECLTYPE)++#if defined(ASIO_HAS_DECLTYPE)++template <typename>+char buffer_sequence_end_helper(...);++template <typename T>+char (&buffer_sequence_end_helper(T* t,+ typename enable_if<!is_same<+ decltype(asio::buffer_sequence_end(*t)),+ void>::value>::type*))[2];++#else // defined(ASIO_HAS_DECLTYPE)++template <typename>+char (&buffer_sequence_end_helper(...))[2];++template <typename T>+char buffer_sequence_end_helper(T* t,+ buffer_sequence_memfns_check<+ void (buffer_sequence_memfns_base::*)(),+ &buffer_sequence_memfns_derived<T>::end>*);++#endif // defined(ASIO_HAS_DECLTYPE)++template <typename>+char (&size_memfn_helper(...))[2];++template <typename T>+char size_memfn_helper(+ buffer_sequence_memfns_check<+ void (buffer_sequence_memfns_base::*)(),+ &buffer_sequence_memfns_derived<T>::size>*);++template <typename>+char (&max_size_memfn_helper(...))[2];++template <typename T>+char max_size_memfn_helper(+ buffer_sequence_memfns_check<+ void (buffer_sequence_memfns_base::*)(),+ &buffer_sequence_memfns_derived<T>::max_size>*);++template <typename>+char (&capacity_memfn_helper(...))[2];++template <typename T>+char capacity_memfn_helper(+ buffer_sequence_memfns_check<+ void (buffer_sequence_memfns_base::*)(),+ &buffer_sequence_memfns_derived<T>::capacity>*);++template <typename>+char (&data_memfn_helper(...))[2];++template <typename T>+char data_memfn_helper(+ buffer_sequence_memfns_check<+ void (buffer_sequence_memfns_base::*)(),+ &buffer_sequence_memfns_derived<T>::data>*);++template <typename>+char (&prepare_memfn_helper(...))[2];++template <typename T>+char prepare_memfn_helper(+ buffer_sequence_memfns_check<+ void (buffer_sequence_memfns_base::*)(),+ &buffer_sequence_memfns_derived<T>::prepare>*);++template <typename>+char (&commit_memfn_helper(...))[2];++template <typename T>+char commit_memfn_helper(+ buffer_sequence_memfns_check<+ void (buffer_sequence_memfns_base::*)(),+ &buffer_sequence_memfns_derived<T>::commit>*);++template <typename>+char (&consume_memfn_helper(...))[2];++template <typename T>+char consume_memfn_helper(+ buffer_sequence_memfns_check<+ void (buffer_sequence_memfns_base::*)(),+ &buffer_sequence_memfns_derived<T>::consume>*);++template <typename>+char (&grow_memfn_helper(...))[2];++template <typename T>+char grow_memfn_helper(+ buffer_sequence_memfns_check<+ void (buffer_sequence_memfns_base::*)(),+ &buffer_sequence_memfns_derived<T>::grow>*);++template <typename>+char (&shrink_memfn_helper(...))[2];++template <typename T>+char shrink_memfn_helper(+ buffer_sequence_memfns_check<+ void (buffer_sequence_memfns_base::*)(),+ &buffer_sequence_memfns_derived<T>::shrink>*);++template <typename, typename>+char (&buffer_sequence_element_type_helper(...))[2];++#if defined(ASIO_HAS_DECLTYPE)++template <typename T, typename Buffer>+char buffer_sequence_element_type_helper(T* t,+ typename enable_if<is_convertible<+ decltype(*asio::buffer_sequence_begin(*t)),+ Buffer>::value>::type*);++#else // defined(ASIO_HAS_DECLTYPE)++template <typename T, typename Buffer>+char buffer_sequence_element_type_helper(+ typename T::const_iterator*,+ typename enable_if<is_convertible<+ typename T::value_type, Buffer>::value>::type*);++#endif // defined(ASIO_HAS_DECLTYPE)++template <typename>+char (&const_buffers_type_typedef_helper(...))[2];++template <typename T>+char const_buffers_type_typedef_helper(+ typename T::const_buffers_type*);++template <typename>+char (&mutable_buffers_type_typedef_helper(...))[2];++template <typename T>+char mutable_buffers_type_typedef_helper(+ typename T::mutable_buffers_type*);++template <typename T, typename Buffer>+struct is_buffer_sequence_class+ : integral_constant<bool,+ sizeof(buffer_sequence_begin_helper<T>(0, 0)) != 1 &&+ sizeof(buffer_sequence_end_helper<T>(0, 0)) != 1 &&+ sizeof(buffer_sequence_element_type_helper<T, Buffer>(0, 0)) == 1>+{+};++template <typename T, typename Buffer>+struct is_buffer_sequence+ : conditional<is_class<T>::value,+ is_buffer_sequence_class<T, Buffer>,+ false_type>::type+{+};++template <>+struct is_buffer_sequence<mutable_buffer, mutable_buffer>+ : true_type+{+};++template <>+struct is_buffer_sequence<mutable_buffer, const_buffer>+ : true_type+{+};++template <>+struct is_buffer_sequence<const_buffer, const_buffer>+ : true_type+{+};++template <>+struct is_buffer_sequence<const_buffer, mutable_buffer>+ : false_type+{+};++template <typename T>+struct is_dynamic_buffer_class_v1+ : integral_constant<bool,+ sizeof(size_memfn_helper<T>(0)) != 1 &&+ sizeof(max_size_memfn_helper<T>(0)) != 1 &&+ sizeof(capacity_memfn_helper<T>(0)) != 1 &&+ sizeof(data_memfn_helper<T>(0)) != 1 &&+ sizeof(consume_memfn_helper<T>(0)) != 1 &&+ sizeof(prepare_memfn_helper<T>(0)) != 1 &&+ sizeof(commit_memfn_helper<T>(0)) != 1 &&+ sizeof(const_buffers_type_typedef_helper<T>(0)) == 1 &&+ sizeof(mutable_buffers_type_typedef_helper<T>(0)) == 1>+{+};++template <typename T>+struct is_dynamic_buffer_v1+ : conditional<is_class<T>::value,+ is_dynamic_buffer_class_v1<T>,+ false_type>::type+{+};++template <typename T>+struct is_dynamic_buffer_class_v2+ : integral_constant<bool,+ sizeof(size_memfn_helper<T>(0)) != 1 &&+ sizeof(max_size_memfn_helper<T>(0)) != 1 &&+ sizeof(capacity_memfn_helper<T>(0)) != 1 &&+ sizeof(data_memfn_helper<T>(0)) != 1 &&+ sizeof(consume_memfn_helper<T>(0)) != 1 &&+ sizeof(grow_memfn_helper<T>(0)) != 1 &&+ sizeof(shrink_memfn_helper<T>(0)) != 1 &&+ sizeof(const_buffers_type_typedef_helper<T>(0)) == 1 &&+ sizeof(mutable_buffers_type_typedef_helper<T>(0)) == 1>+{+};++template <typename T>+struct is_dynamic_buffer_v2+ : conditional<is_class<T>::value,+ is_dynamic_buffer_class_v2<T>,+ false_type>::type+{+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/is_executor.hpp view
@@ -0,0 +1,126 @@+//+// detail/is_executor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IS_EXECUTOR_HPP+#define ASIO_DETAIL_IS_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/detail/push_options.hpp"++namespace asio {+namespace detail {++struct executor_memfns_base+{+ void context();+ void on_work_started();+ void on_work_finished();+ void dispatch();+ void post();+ void defer();+};++template <typename T>+struct executor_memfns_derived+ : T, executor_memfns_base+{+};++template <typename T, T>+struct executor_memfns_check+{+};++template <typename>+char (&context_memfn_helper(...))[2];++template <typename T>+char context_memfn_helper(+ executor_memfns_check<+ void (executor_memfns_base::*)(),+ &executor_memfns_derived<T>::context>*);++template <typename>+char (&on_work_started_memfn_helper(...))[2];++template <typename T>+char on_work_started_memfn_helper(+ executor_memfns_check<+ void (executor_memfns_base::*)(),+ &executor_memfns_derived<T>::on_work_started>*);++template <typename>+char (&on_work_finished_memfn_helper(...))[2];++template <typename T>+char on_work_finished_memfn_helper(+ executor_memfns_check<+ void (executor_memfns_base::*)(),+ &executor_memfns_derived<T>::on_work_finished>*);++template <typename>+char (&dispatch_memfn_helper(...))[2];++template <typename T>+char dispatch_memfn_helper(+ executor_memfns_check<+ void (executor_memfns_base::*)(),+ &executor_memfns_derived<T>::dispatch>*);++template <typename>+char (&post_memfn_helper(...))[2];++template <typename T>+char post_memfn_helper(+ executor_memfns_check<+ void (executor_memfns_base::*)(),+ &executor_memfns_derived<T>::post>*);++template <typename>+char (&defer_memfn_helper(...))[2];++template <typename T>+char defer_memfn_helper(+ executor_memfns_check<+ void (executor_memfns_base::*)(),+ &executor_memfns_derived<T>::defer>*);++template <typename T>+struct is_executor_class+ : integral_constant<bool,+ sizeof(context_memfn_helper<T>(0)) != 1 &&+ sizeof(on_work_started_memfn_helper<T>(0)) != 1 &&+ sizeof(on_work_finished_memfn_helper<T>(0)) != 1 &&+ sizeof(dispatch_memfn_helper<T>(0)) != 1 &&+ sizeof(post_memfn_helper<T>(0)) != 1 &&+ sizeof(defer_memfn_helper<T>(0)) != 1>+{+};++template <typename T>+struct is_executor+ : conditional<is_class<T>::value,+ is_executor_class<T>,+ false_type>::type+{+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_IS_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/keyword_tss_ptr.hpp view
@@ -0,0 +1,70 @@+//+// detail/keyword_tss_ptr.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_KEYWORD_TSS_PTR_HPP+#define ASIO_DETAIL_KEYWORD_TSS_PTR_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_THREAD_KEYWORD_EXTENSION)++#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename T>+class keyword_tss_ptr+ : private noncopyable+{+public:+ // Constructor.+ keyword_tss_ptr()+ {+ }++ // Destructor.+ ~keyword_tss_ptr()+ {+ }++ // Get the value.+ operator T*() const+ {+ return value_;+ }++ // Set the value.+ void operator=(T* value)+ {+ value_ = value;+ }++private:+ static ASIO_THREAD_KEYWORD T* value_;+};++template <typename T>+ASIO_THREAD_KEYWORD T* keyword_tss_ptr<T>::value_;++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)++#endif // ASIO_DETAIL_KEYWORD_TSS_PTR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/kqueue_reactor.hpp view
@@ -0,0 +1,242 @@+//+// detail/kqueue_reactor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2005 Stefan Arentz (stefan at soze 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_KQUEUE_REACTOR_HPP+#define ASIO_DETAIL_KQUEUE_REACTOR_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_KQUEUE)++#include <cstddef>+#include <sys/types.h>+#include <sys/event.h>+#include <sys/time.h>+#include "asio/detail/limits.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/object_pool.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/select_interrupter.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/timer_queue_base.hpp"+#include "asio/detail/timer_queue_set.hpp"+#include "asio/detail/wait_op.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"++// Older versions of Mac OS X may not define EV_OOBAND.+#if !defined(EV_OOBAND)+# define EV_OOBAND EV_FLAG1+#endif // !defined(EV_OOBAND)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class scheduler;++class kqueue_reactor+ : public execution_context_service_base<kqueue_reactor>+{+private:+ // The mutex type used by this reactor.+ typedef conditionally_enabled_mutex mutex;++public:+ enum op_types { read_op = 0, write_op = 1,+ connect_op = 1, except_op = 2, max_ops = 3 };++ // Per-descriptor queues.+ struct descriptor_state+ {+ descriptor_state(bool locking) : mutex_(locking) {}++ friend class kqueue_reactor;+ friend class object_pool_access;++ descriptor_state* next_;+ descriptor_state* prev_;++ mutex mutex_;+ int descriptor_;+ int num_kevents_; // 1 == read only, 2 == read and write+ op_queue<reactor_op> op_queue_[max_ops];+ bool shutdown_;+ };++ // Per-descriptor data.+ typedef descriptor_state* per_descriptor_data;++ // Constructor.+ ASIO_DECL kqueue_reactor(asio::execution_context& ctx);++ // Destructor.+ ASIO_DECL ~kqueue_reactor();++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Recreate internal descriptors following a fork.+ ASIO_DECL void notify_fork(+ asio::execution_context::fork_event fork_ev);++ // Initialise the task.+ ASIO_DECL void init_task();++ // Register a socket with the reactor. Returns 0 on success, system error+ // code on failure.+ ASIO_DECL int register_descriptor(socket_type descriptor,+ per_descriptor_data& descriptor_data);++ // Register a descriptor with an associated single operation. Returns 0 on+ // success, system error code on failure.+ ASIO_DECL int register_internal_descriptor(+ int op_type, socket_type descriptor,+ per_descriptor_data& descriptor_data, reactor_op* op);++ // Move descriptor registration from one descriptor_data object to another.+ ASIO_DECL void move_descriptor(socket_type descriptor,+ per_descriptor_data& target_descriptor_data,+ per_descriptor_data& source_descriptor_data);++ // Post a reactor operation for immediate completion.+ void post_immediate_completion(reactor_op* op, bool is_continuation)+ {+ scheduler_.post_immediate_completion(op, is_continuation);+ }++ // Start a new operation. The reactor operation will be performed when the+ // given descriptor is flagged as ready, or an error has occurred.+ ASIO_DECL void start_op(int op_type, socket_type descriptor,+ per_descriptor_data& descriptor_data, reactor_op* op,+ bool is_continuation, bool allow_speculative);++ // Cancel all operations associated with the given descriptor. The+ // handlers associated with the descriptor will be invoked with the+ // operation_aborted error.+ ASIO_DECL void cancel_ops(socket_type descriptor,+ per_descriptor_data& descriptor_data);++ // Cancel any operations that are running against the descriptor and remove+ // its registration from the reactor. The reactor resources associated with+ // the descriptor must be released by calling cleanup_descriptor_data.+ ASIO_DECL void deregister_descriptor(socket_type descriptor,+ per_descriptor_data& descriptor_data, bool closing);++ // Remove the descriptor's registration from the reactor. The reactor+ // resources associated with the descriptor must be released by calling+ // cleanup_descriptor_data.+ ASIO_DECL void deregister_internal_descriptor(+ socket_type descriptor, per_descriptor_data& descriptor_data);++ // Perform any post-deregistration cleanup tasks associated with the+ // descriptor data.+ ASIO_DECL void cleanup_descriptor_data(+ per_descriptor_data& descriptor_data);++ // Add a new timer queue to the reactor.+ template <typename Time_Traits>+ void add_timer_queue(timer_queue<Time_Traits>& queue);++ // Remove a timer queue from the reactor.+ template <typename Time_Traits>+ void remove_timer_queue(timer_queue<Time_Traits>& queue);++ // Schedule a new operation in the given timer queue to expire at the+ // specified absolute time.+ template <typename Time_Traits>+ void schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);++ // Cancel the timer operations associated with the given token. Returns the+ // number of operations that have been posted or dispatched.+ template <typename Time_Traits>+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());++ // Move the timer operations associated with the given timer.+ template <typename Time_Traits>+ void move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& target,+ typename timer_queue<Time_Traits>::per_timer_data& source);++ // Run the kqueue loop.+ ASIO_DECL void run(long usec, op_queue<operation>& ops);++ // Interrupt the kqueue loop.+ ASIO_DECL void interrupt();++private:+ // Create the kqueue file descriptor. Throws an exception if the descriptor+ // cannot be created.+ ASIO_DECL static int do_kqueue_create();++ // Allocate a new descriptor state object.+ ASIO_DECL descriptor_state* allocate_descriptor_state();++ // Free an existing descriptor state object.+ ASIO_DECL void free_descriptor_state(descriptor_state* s);++ // Helper function to add a new timer queue.+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);++ // Helper function to remove a timer queue.+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);++ // Get the timeout value for the kevent call.+ ASIO_DECL timespec* get_timeout(long usec, timespec& ts);++ // The scheduler used to post completions.+ scheduler& scheduler_;++ // Mutex to protect access to internal data.+ mutex mutex_;++ // The kqueue file descriptor.+ int kqueue_fd_;++ // The interrupter is used to break a blocking kevent call.+ select_interrupter interrupter_;++ // The timer queues.+ timer_queue_set timer_queues_;++ // Whether the service has been shut down.+ bool shutdown_;++ // Mutex to protect access to the registered descriptors.+ mutex registered_descriptors_mutex_;++ // Keep track of all registered descriptors.+ object_pool<descriptor_state> registered_descriptors_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/detail/impl/kqueue_reactor.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/kqueue_reactor.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_KQUEUE)++#endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/limits.hpp view
@@ -0,0 +1,26 @@+//+// detail/limits.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2011 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_LIMITS_HPP+#define ASIO_DETAIL_LIMITS_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_BOOST_LIMITS)+# include <boost/limits.hpp>+#else // defined(ASIO_HAS_BOOST_LIMITS)+# include <limits>+#endif // defined(ASIO_HAS_BOOST_LIMITS)++#endif // ASIO_DETAIL_LIMITS_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/local_free_on_block_exit.hpp view
@@ -0,0 +1,59 @@+//+// detail/local_free_on_block_exit.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_LOCAL_FREE_ON_BLOCK_EXIT_HPP+#define ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_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_WINDOWS) || defined(__CYGWIN__)+#if !defined(ASIO_WINDOWS_APP)++#include "asio/detail/noncopyable.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class local_free_on_block_exit+ : private noncopyable+{+public:+ // Constructor blocks all signals for the calling thread.+ explicit local_free_on_block_exit(void* p)+ : p_(p)+ {+ }++ // Destructor restores the previous signal mask.+ ~local_free_on_block_exit()+ {+ ::LocalFree(p_);+ }++private:+ void* p_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_WINDOWS_APP)+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++#endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/macos_fenced_block.hpp view
@@ -0,0 +1,62 @@+//+// detail/macos_fenced_block.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_MACOS_FENCED_BLOCK_HPP+#define ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(__MACH__) && defined(__APPLE__)++#include <libkern/OSAtomic.h>+#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class macos_fenced_block+ : private noncopyable+{+public:+ enum half_t { half };+ enum full_t { full };++ // Constructor for a half fenced block.+ explicit macos_fenced_block(half_t)+ {+ }++ // Constructor for a full fenced block.+ explicit macos_fenced_block(full_t)+ {+ OSMemoryBarrier();+ }++ // Destructor.+ ~macos_fenced_block()+ {+ OSMemoryBarrier();+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(__MACH__) && defined(__APPLE__)++#endif // ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/memory.hpp view
@@ -0,0 +1,73 @@+//+// detail/memory.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_MEMORY_HPP+#define ASIO_DETAIL_MEMORY_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <memory>++#if !defined(ASIO_HAS_STD_SHARED_PTR)+# include <boost/make_shared.hpp>+# include <boost/shared_ptr.hpp>+# include <boost/weak_ptr.hpp>+#endif // !defined(ASIO_HAS_STD_SHARED_PTR)++#if !defined(ASIO_HAS_STD_ADDRESSOF)+# include <boost/utility/addressof.hpp>+#endif // !defined(ASIO_HAS_STD_ADDRESSOF)++namespace asio {+namespace detail {++#if defined(ASIO_HAS_STD_SHARED_PTR)+using std::make_shared;+using std::shared_ptr;+using std::weak_ptr;+#else // defined(ASIO_HAS_STD_SHARED_PTR)+using boost::make_shared;+using boost::shared_ptr;+using boost::weak_ptr;+#endif // defined(ASIO_HAS_STD_SHARED_PTR)++#if defined(ASIO_HAS_STD_ADDRESSOF)+using std::addressof;+#else // defined(ASIO_HAS_STD_ADDRESSOF)+using boost::addressof;+#endif // defined(ASIO_HAS_STD_ADDRESSOF)++} // namespace detail++#if defined(ASIO_HAS_CXX11_ALLOCATORS)+using std::allocator_arg_t;+# define ASIO_USES_ALLOCATOR(t) \+ namespace std { \+ template <typename Allocator> \+ struct uses_allocator<t, Allocator> : true_type {}; \+ } \+ /**/+# define ASIO_REBIND_ALLOC(alloc, t) \+ typename std::allocator_traits<alloc>::template rebind_alloc<t>+ /**/+#else // defined(ASIO_HAS_CXX11_ALLOCATORS)+struct allocator_arg_t {};+# define ASIO_USES_ALLOCATOR(t)+# define ASIO_REBIND_ALLOC(alloc, t) \+ typename alloc::template rebind<t>::other+ /**/+#endif // defined(ASIO_HAS_CXX11_ALLOCATORS)++} // namespace asio++#endif // ASIO_DETAIL_MEMORY_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/mutex.hpp view
@@ -0,0 +1,48 @@+//+// detail/mutex.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_MUTEX_HPP+#define ASIO_DETAIL_MUTEX_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_THREADS)+# include "asio/detail/null_mutex.hpp"+#elif defined(ASIO_WINDOWS)+# include "asio/detail/win_mutex.hpp"+#elif defined(ASIO_HAS_PTHREADS)+# include "asio/detail/posix_mutex.hpp"+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)+# include "asio/detail/std_mutex.hpp"+#else+# error Only Windows, POSIX and std::mutex are supported!+#endif++namespace asio {+namespace detail {++#if !defined(ASIO_HAS_THREADS)+typedef null_mutex mutex;+#elif defined(ASIO_WINDOWS)+typedef win_mutex mutex;+#elif defined(ASIO_HAS_PTHREADS)+typedef posix_mutex mutex;+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)+typedef std_mutex mutex;+#endif++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_MUTEX_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/non_const_lvalue.hpp view
@@ -0,0 +1,54 @@+//+// detail/non_const_lvalue.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NON_CONST_LVALUE_HPP+#define ASIO_DETAIL_NON_CONST_LVALUE_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 {+namespace detail {++template <typename T>+struct non_const_lvalue+{+#if defined(ASIO_HAS_MOVE)+ explicit non_const_lvalue(T& t)+ : value(static_cast<typename conditional<+ is_same<T, typename decay<T>::type>::value,+ typename decay<T>::type&, T&&>::type>(t))+ {+ }++ typename conditional<is_same<T, typename decay<T>::type>::value,+ typename decay<T>::type&, typename decay<T>::type>::type value;+#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ explicit non_const_lvalue(const typename decay<T>::type& t)+ : value(t)+ {+ }++ typename decay<T>::type value;+#endif // defined(ASIO_HAS_MOVE)+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_NON_CONST_LVALUE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/noncopyable.hpp view
@@ -0,0 +1,43 @@+//+// detail/noncopyable.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NONCOPYABLE_HPP+#define ASIO_DETAIL_NONCOPYABLE_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 {+namespace detail {++class noncopyable+{+protected:+ noncopyable() {}+ ~noncopyable() {}+private:+ noncopyable(const noncopyable&);+ const noncopyable& operator=(const noncopyable&);+};++} // namespace detail++using asio::detail::noncopyable;++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_NONCOPYABLE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/null_event.hpp view
@@ -0,0 +1,106 @@+//+// detail/null_event.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NULL_EVENT_HPP+#define ASIO_DETAIL_NULL_EVENT_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/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class null_event+ : private noncopyable+{+public:+ // Constructor.+ null_event()+ {+ }++ // Destructor.+ ~null_event()+ {+ }++ // Signal the event. (Retained for backward compatibility.)+ template <typename Lock>+ void signal(Lock&)+ {+ }++ // Signal all waiters.+ template <typename Lock>+ void signal_all(Lock&)+ {+ }++ // Unlock the mutex and signal one waiter.+ template <typename Lock>+ void unlock_and_signal_one(Lock&)+ {+ }++ // Unlock the mutex and signal one waiter who may destroy us.+ template <typename Lock>+ void unlock_and_signal_one_for_destruction(Lock&)+ {+ }++ // If there's a waiter, unlock the mutex and signal it.+ template <typename Lock>+ bool maybe_unlock_and_signal_one(Lock&)+ {+ return false;+ }++ // Reset the event.+ template <typename Lock>+ void clear(Lock&)+ {+ }++ // Wait for the event to become signalled.+ template <typename Lock>+ void wait(Lock&)+ {+ do_wait();+ }++ // Timed wait for the event to become signalled.+ template <typename Lock>+ bool wait_for_usec(Lock&, long usec)+ {+ do_wait_for_usec(usec);+ return true;+ }++private:+ ASIO_DECL static void do_wait();+ ASIO_DECL static void do_wait_for_usec(long usec);+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/null_event.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_NULL_EVENT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/null_fenced_block.hpp view
@@ -0,0 +1,47 @@+//+// detail/null_fenced_block.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NULL_FENCED_BLOCK_HPP+#define ASIO_DETAIL_NULL_FENCED_BLOCK_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class null_fenced_block+ : private noncopyable+{+public:+ enum half_or_full_t { half, full };++ // Constructor.+ explicit null_fenced_block(half_or_full_t)+ {+ }++ // Destructor.+ ~null_fenced_block()+ {+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_NULL_FENCED_BLOCK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/null_global.hpp view
@@ -0,0 +1,59 @@+//+// detail/null_global.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NULL_GLOBAL_HPP+#define ASIO_DETAIL_NULL_GLOBAL_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 {+namespace detail {++template <typename T>+struct null_global_impl+{+ null_global_impl()+ : ptr_(0)+ {+ }++ // Destructor automatically cleans up the global.+ ~null_global_impl()+ {+ delete ptr_;+ }++ static null_global_impl instance_;+ T* ptr_;+};++template <typename T>+null_global_impl<T> null_global_impl<T>::instance_;++template <typename T>+T& null_global()+{+ if (null_global_impl<T>::instance_.ptr_ == 0)+ null_global_impl<T>::instance_.ptr_ = new T;+ return *null_global_impl<T>::instance_.ptr_;+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_NULL_GLOBAL_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/null_mutex.hpp view
@@ -0,0 +1,64 @@+//+// detail/null_mutex.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NULL_MUTEX_HPP+#define ASIO_DETAIL_NULL_MUTEX_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_THREADS)++#include "asio/detail/noncopyable.hpp"+#include "asio/detail/scoped_lock.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class null_mutex+ : private noncopyable+{+public:+ typedef asio::detail::scoped_lock<null_mutex> scoped_lock;++ // Constructor.+ null_mutex()+ {+ }++ // Destructor.+ ~null_mutex()+ {+ }++ // Lock the mutex.+ void lock()+ {+ }++ // Unlock the mutex.+ void unlock()+ {+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_HAS_THREADS)++#endif // ASIO_DETAIL_NULL_MUTEX_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/null_reactor.hpp view
@@ -0,0 +1,68 @@+//+// detail/null_reactor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NULL_REACTOR_HPP+#define ASIO_DETAIL_NULL_REACTOR_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_IOCP) || defined(ASIO_WINDOWS_RUNTIME)++#include "asio/detail/scheduler_operation.hpp"+#include "asio/execution_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class null_reactor+ : public execution_context_service_base<null_reactor>+{+public:+ // Constructor.+ null_reactor(asio::execution_context& ctx)+ : execution_context_service_base<null_reactor>(ctx)+ {+ }++ // Destructor.+ ~null_reactor()+ {+ }++ // Destroy all user-defined handler objects owned by the service.+ void shutdown()+ {+ }++ // No-op because should never be called.+ void run(long /*usec*/, op_queue<scheduler_operation>& /*ops*/)+ {+ }++ // No-op.+ void interrupt()+ {+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_NULL_REACTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/null_signal_blocker.hpp view
@@ -0,0 +1,69 @@+//+// detail/null_signal_blocker.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NULL_SIGNAL_BLOCKER_HPP+#define ASIO_DETAIL_NULL_SIGNAL_BLOCKER_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_THREADS) \+ || defined(ASIO_WINDOWS) \+ || defined(ASIO_WINDOWS_RUNTIME) \+ || defined(__CYGWIN__) \+ || defined(__SYMBIAN32__)++#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class null_signal_blocker+ : private noncopyable+{+public:+ // Constructor blocks all signals for the calling thread.+ null_signal_blocker()+ {+ }++ // Destructor restores the previous signal mask.+ ~null_signal_blocker()+ {+ }++ // Block all signals for the calling thread.+ void block()+ {+ }++ // Restore the previous signal mask.+ void unblock()+ {+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_HAS_THREADS)+ // || defined(ASIO_WINDOWS)+ // || defined(ASIO_WINDOWS_RUNTIME)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)++#endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/null_socket_service.hpp view
@@ -0,0 +1,519 @@+//+// detail/null_socket_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NULL_SOCKET_SERVICE_HPP+#define ASIO_DETAIL_NULL_SOCKET_SERVICE_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_WINDOWS_RUNTIME)++#include "asio/buffer.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/post.hpp"+#include "asio/socket_base.hpp"+#include "asio/detail/bind_handler.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Protocol>+class null_socket_service :+ public execution_context_service_base<null_socket_service<Protocol> >+{+public:+ // The protocol type.+ typedef Protocol protocol_type;++ // The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ // The native type of a socket.+ typedef int native_handle_type;++ // The implementation type of the socket.+ struct implementation_type+ {+ };++ // Constructor.+ null_socket_service(execution_context& context)+ : execution_context_service_base<null_socket_service<Protocol> >(context)+ {+ }++ // Destroy all user-defined handler objects owned by the service.+ void shutdown()+ {+ }++ // Construct a new socket implementation.+ void construct(implementation_type&)+ {+ }++ // Move-construct a new socket implementation.+ void move_construct(implementation_type&, implementation_type&)+ {+ }++ // Move-assign from another socket implementation.+ void move_assign(implementation_type&,+ null_socket_service&, implementation_type&)+ {+ }++ // Move-construct a new socket implementation from another protocol type.+ template <typename Protocol1>+ void converting_move_construct(implementation_type&,+ null_socket_service<Protocol1>&,+ typename null_socket_service<Protocol1>::implementation_type&)+ {+ }++ // Destroy a socket implementation.+ void destroy(implementation_type&)+ {+ }++ // Open a new socket implementation.+ asio::error_code open(implementation_type&,+ const protocol_type&, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Assign a native socket to a socket implementation.+ asio::error_code assign(implementation_type&, const protocol_type&,+ const native_handle_type&, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Determine whether the socket is open.+ bool is_open(const implementation_type&) const+ {+ return false;+ }++ // Destroy a socket implementation.+ asio::error_code close(implementation_type&,+ asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Release ownership of the socket.+ native_handle_type release(implementation_type&,+ asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Get the native socket representation.+ native_handle_type native_handle(implementation_type&)+ {+ return 0;+ }++ // Cancel all operations associated with the socket.+ asio::error_code cancel(implementation_type&,+ asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Determine whether the socket is at the out-of-band data mark.+ bool at_mark(const implementation_type&,+ asio::error_code& ec) const+ {+ ec = asio::error::operation_not_supported;+ return false;+ }++ // Determine the number of bytes available for reading.+ std::size_t available(const implementation_type&,+ asio::error_code& ec) const+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Place the socket into the state where it will listen for new connections.+ asio::error_code listen(implementation_type&,+ int, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Perform an IO control command on the socket.+ template <typename IO_Control_Command>+ asio::error_code io_control(implementation_type&,+ IO_Control_Command&, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Gets the non-blocking mode of the socket.+ bool non_blocking(const implementation_type&) const+ {+ return false;+ }++ // Sets the non-blocking mode of the socket.+ asio::error_code non_blocking(implementation_type&,+ bool, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Gets the non-blocking mode of the native socket implementation.+ bool native_non_blocking(const implementation_type&) const+ {+ return false;+ }++ // Sets the non-blocking mode of the native socket implementation.+ asio::error_code native_non_blocking(implementation_type&,+ bool, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Disable sends or receives on the socket.+ asio::error_code shutdown(implementation_type&,+ socket_base::shutdown_type, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Bind the socket to the specified local endpoint.+ asio::error_code bind(implementation_type&,+ const endpoint_type&, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Set a socket option.+ template <typename Option>+ asio::error_code set_option(implementation_type&,+ const Option&, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Set a socket option.+ template <typename Option>+ asio::error_code get_option(const implementation_type&,+ Option&, asio::error_code& ec) const+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Get the local endpoint.+ endpoint_type local_endpoint(const implementation_type&,+ asio::error_code& ec) const+ {+ ec = asio::error::operation_not_supported;+ return endpoint_type();+ }++ // Get the remote endpoint.+ endpoint_type remote_endpoint(const implementation_type&,+ asio::error_code& ec) const+ {+ ec = asio::error::operation_not_supported;+ return endpoint_type();+ }++ // Send the given data to the peer.+ template <typename ConstBufferSequence>+ std::size_t send(implementation_type&, const ConstBufferSequence&,+ socket_base::message_flags, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Wait until data can be sent without blocking.+ std::size_t send(implementation_type&, const null_buffers&,+ socket_base::message_flags, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Start an asynchronous send. The data being sent must be valid for the+ // lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_send(implementation_type&, const ConstBufferSequence&,+ socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex, detail::bind_handler(+ handler, ec, bytes_transferred));+ }++ // Start an asynchronous wait until data can be sent without blocking.+ template <typename Handler, typename IoExecutor>+ void async_send(implementation_type&, const null_buffers&,+ socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex, detail::bind_handler(+ handler, ec, bytes_transferred));+ }++ // Receive some data from the peer. Returns the number of bytes received.+ template <typename MutableBufferSequence>+ std::size_t receive(implementation_type&, const MutableBufferSequence&,+ socket_base::message_flags, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Wait until data can be received without blocking.+ std::size_t receive(implementation_type&, const null_buffers&,+ socket_base::message_flags, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Start an asynchronous receive. The buffer for the data being received+ // must be valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_receive(implementation_type&, const MutableBufferSequence&,+ socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex, detail::bind_handler(+ handler, ec, bytes_transferred));+ }++ // Wait until data can be received without blocking.+ template <typename Handler, typename IoExecutor>+ void async_receive(implementation_type&, const null_buffers&,+ socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex, detail::bind_handler(+ handler, ec, bytes_transferred));+ }++ // Receive some data with associated flags. Returns the number of bytes+ // received.+ template <typename MutableBufferSequence>+ std::size_t receive_with_flags(implementation_type&,+ const MutableBufferSequence&, socket_base::message_flags,+ socket_base::message_flags&, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Wait until data can be received without blocking.+ std::size_t receive_with_flags(implementation_type&,+ const null_buffers&, socket_base::message_flags,+ socket_base::message_flags&, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Start an asynchronous receive. The buffer for the data being received+ // must be valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_receive_with_flags(implementation_type&,+ const MutableBufferSequence&, socket_base::message_flags,+ socket_base::message_flags&, Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex, detail::bind_handler(+ handler, ec, bytes_transferred));+ }++ // Wait until data can be received without blocking.+ template <typename Handler, typename IoExecutor>+ void async_receive_with_flags(implementation_type&, const null_buffers&,+ socket_base::message_flags, socket_base::message_flags&,+ Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex, detail::bind_handler(+ handler, ec, bytes_transferred));+ }++ // Send a datagram to the specified endpoint. Returns the number of bytes+ // sent.+ template <typename ConstBufferSequence>+ std::size_t send_to(implementation_type&, const ConstBufferSequence&,+ const endpoint_type&, socket_base::message_flags,+ asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Wait until data can be sent without blocking.+ std::size_t send_to(implementation_type&, const null_buffers&,+ const endpoint_type&, socket_base::message_flags,+ asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Start an asynchronous send. The data being sent must be valid for the+ // lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_send_to(implementation_type&, const ConstBufferSequence&,+ const endpoint_type&, socket_base::message_flags,+ Handler& handler)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex, detail::bind_handler(+ handler, ec, bytes_transferred));+ }++ // Start an asynchronous wait until data can be sent without blocking.+ template <typename Handler, typename IoExecutor>+ void async_send_to(implementation_type&, const null_buffers&,+ const endpoint_type&, socket_base::message_flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex, detail::bind_handler(+ handler, ec, bytes_transferred));+ }++ // Receive a datagram with the endpoint of the sender. Returns the number of+ // bytes received.+ template <typename MutableBufferSequence>+ std::size_t receive_from(implementation_type&, const MutableBufferSequence&,+ endpoint_type&, socket_base::message_flags,+ asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Wait until data can be received without blocking.+ std::size_t receive_from(implementation_type&, const null_buffers&,+ endpoint_type&, socket_base::message_flags,+ asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Start an asynchronous receive. The buffer for the data being received and+ // the sender_endpoint object must both be valid for the lifetime of the+ // asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_receive_from(implementation_type&, const MutableBufferSequence&,+ endpoint_type&, socket_base::message_flags, Handler& handler,+ const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex, detail::bind_handler(+ handler, ec, bytes_transferred));+ }++ // Wait until data can be received without blocking.+ template <typename Handler, typename IoExecutor>+ void async_receive_from(implementation_type&, const null_buffers&,+ endpoint_type&, socket_base::message_flags, Handler& handler,+ const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex, detail::bind_handler(+ handler, ec, bytes_transferred));+ }++ // Accept a new connection.+ template <typename Socket>+ asio::error_code accept(implementation_type&,+ Socket&, endpoint_type*, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Start an asynchronous accept. The peer and peer_endpoint objects+ // must be valid until the accept's handler is invoked.+ template <typename Socket, typename Handler, typename IoExecutor>+ void async_accept(implementation_type&, Socket&, endpoint_type*,+ Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ asio::post(io_ex, detail::bind_handler(handler, ec));+ }++ // Connect the socket to the specified endpoint.+ asio::error_code connect(implementation_type&,+ const endpoint_type&, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Start an asynchronous connect.+ template <typename Handler, typename IoExecutor>+ void async_connect(implementation_type&, const endpoint_type&,+ Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ asio::post(io_ex, detail::bind_handler(handler, ec));+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/null_static_mutex.hpp view
@@ -0,0 +1,60 @@+//+// detail/null_static_mutex.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NULL_STATIC_MUTEX_HPP+#define ASIO_DETAIL_NULL_STATIC_MUTEX_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_THREADS)++#include "asio/detail/scoped_lock.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++struct null_static_mutex+{+ typedef asio::detail::scoped_lock<null_static_mutex> scoped_lock;++ // Initialise the mutex.+ void init()+ {+ }++ // Lock the mutex.+ void lock()+ {+ }++ // Unlock the mutex.+ void unlock()+ {+ }++ int unused_;+};++#define ASIO_NULL_STATIC_MUTEX_INIT { 0 }++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_HAS_THREADS)++#endif // ASIO_DETAIL_NULL_STATIC_MUTEX_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/null_thread.hpp view
@@ -0,0 +1,67 @@+//+// detail/null_thread.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NULL_THREAD_HPP+#define ASIO_DETAIL_NULL_THREAD_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_THREADS)++#include "asio/detail/noncopyable.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class null_thread+ : private noncopyable+{+public:+ // Constructor.+ template <typename Function>+ null_thread(Function, unsigned int = 0)+ {+ asio::detail::throw_error(+ asio::error::operation_not_supported, "thread");+ }++ // Destructor.+ ~null_thread()+ {+ }++ // Wait for the thread to exit.+ void join()+ {+ }++ // Get number of CPUs.+ static std::size_t hardware_concurrency()+ {+ return 1;+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_HAS_THREADS)++#endif // ASIO_DETAIL_NULL_THREAD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/null_tss_ptr.hpp view
@@ -0,0 +1,68 @@+//+// detail/null_tss_ptr.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_NULL_TSS_PTR_HPP+#define ASIO_DETAIL_NULL_TSS_PTR_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_THREADS)++#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename T>+class null_tss_ptr+ : private noncopyable+{+public:+ // Constructor.+ null_tss_ptr()+ : value_(0)+ {+ }++ // Destructor.+ ~null_tss_ptr()+ {+ }++ // Get the value.+ operator T*() const+ {+ return value_;+ }++ // Set the value.+ void operator=(T* value)+ {+ value_ = value;+ }++private:+ T* value_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_HAS_THREADS)++#endif // ASIO_DETAIL_NULL_TSS_PTR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/object_pool.hpp view
@@ -0,0 +1,171 @@+//+// detail/object_pool.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_OBJECT_POOL_HPP+#define ASIO_DETAIL_OBJECT_POOL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Object>+class object_pool;++class object_pool_access+{+public:+ template <typename Object>+ static Object* create()+ {+ return new Object;+ }++ template <typename Object, typename Arg>+ static Object* create(Arg arg)+ {+ return new Object(arg);+ }++ template <typename Object>+ static void destroy(Object* o)+ {+ delete o;+ }++ template <typename Object>+ static Object*& next(Object* o)+ {+ return o->next_;+ }++ template <typename Object>+ static Object*& prev(Object* o)+ {+ return o->prev_;+ }+};++template <typename Object>+class object_pool+ : private noncopyable+{+public:+ // Constructor.+ object_pool()+ : live_list_(0),+ free_list_(0)+ {+ }++ // Destructor destroys all objects.+ ~object_pool()+ {+ destroy_list(live_list_);+ destroy_list(free_list_);+ }++ // Get the object at the start of the live list.+ Object* first()+ {+ return live_list_;+ }++ // Allocate a new object.+ Object* alloc()+ {+ Object* o = free_list_;+ if (o)+ free_list_ = object_pool_access::next(free_list_);+ else+ o = object_pool_access::create<Object>();++ object_pool_access::next(o) = live_list_;+ object_pool_access::prev(o) = 0;+ if (live_list_)+ object_pool_access::prev(live_list_) = o;+ live_list_ = o;++ return o;+ }++ // Allocate a new object with an argument.+ template <typename Arg>+ Object* alloc(Arg arg)+ {+ Object* o = free_list_;+ if (o)+ free_list_ = object_pool_access::next(free_list_);+ else+ o = object_pool_access::create<Object>(arg);++ object_pool_access::next(o) = live_list_;+ object_pool_access::prev(o) = 0;+ if (live_list_)+ object_pool_access::prev(live_list_) = o;+ live_list_ = o;++ return o;+ }++ // Free an object. Moves it to the free list. No destructors are run.+ void free(Object* o)+ {+ if (live_list_ == o)+ live_list_ = object_pool_access::next(o);++ if (object_pool_access::prev(o))+ {+ object_pool_access::next(object_pool_access::prev(o))+ = object_pool_access::next(o);+ }++ if (object_pool_access::next(o))+ {+ object_pool_access::prev(object_pool_access::next(o))+ = object_pool_access::prev(o);+ }++ object_pool_access::next(o) = free_list_;+ object_pool_access::prev(o) = 0;+ free_list_ = o;+ }++private:+ // Helper function to destroy all elements in a list.+ void destroy_list(Object* list)+ {+ while (list)+ {+ Object* o = list;+ list = object_pool_access::next(o);+ object_pool_access::destroy(o);+ }+ }++ // The list of live objects.+ Object* live_list_;++ // The free list.+ Object* free_list_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_OBJECT_POOL_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/old_win_sdk_compat.hpp view
@@ -0,0 +1,214 @@+//+// detail/old_win_sdk_compat.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_OLD_WIN_SDK_COMPAT_HPP+#define ASIO_DETAIL_OLD_WIN_SDK_COMPAT_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_WINDOWS) || defined(__CYGWIN__)++// Guess whether we are building against on old Platform SDK.+#if !defined(IN6ADDR_ANY_INIT)+#define ASIO_HAS_OLD_WIN_SDK 1+#endif // !defined(IN6ADDR_ANY_INIT)++#if defined(ASIO_HAS_OLD_WIN_SDK)++// Emulation of types that are missing from old Platform SDKs.+//+// N.B. this emulation is also used if building for a Windows 2000 target with+// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support+// in that case.++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++enum+{+ sockaddr_storage_maxsize = 128, // Maximum size.+ sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment.+ sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)),+ sockaddr_storage_pad2size = (sockaddr_storage_maxsize -+ (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize))+};++struct sockaddr_storage_emulation+{+ short ss_family;+ char __ss_pad1[sockaddr_storage_pad1size];+ __int64 __ss_align;+ char __ss_pad2[sockaddr_storage_pad2size];+};++struct in6_addr_emulation+{+ union+ {+ u_char Byte[16];+ u_short Word[8];+ } u;+};++#if !defined(s6_addr)+# define _S6_un u+# define _S6_u8 Byte+# define s6_addr _S6_un._S6_u8+#endif // !defined(s6_addr)++struct sockaddr_in6_emulation+{+ short sin6_family;+ u_short sin6_port;+ u_long sin6_flowinfo;+ in6_addr_emulation sin6_addr;+ u_long sin6_scope_id;+};++struct ipv6_mreq_emulation+{+ in6_addr_emulation ipv6mr_multiaddr;+ unsigned int ipv6mr_interface;+};++struct addrinfo_emulation+{+ int ai_flags;+ int ai_family;+ int ai_socktype;+ int ai_protocol;+ size_t ai_addrlen;+ char* ai_canonname;+ sockaddr* ai_addr;+ addrinfo_emulation* ai_next;+};++#if !defined(AI_PASSIVE)+# define AI_PASSIVE 0x1+#endif++#if !defined(AI_CANONNAME)+# define AI_CANONNAME 0x2+#endif++#if !defined(AI_NUMERICHOST)+# define AI_NUMERICHOST 0x4+#endif++#if !defined(EAI_AGAIN)+# define EAI_AGAIN WSATRY_AGAIN+#endif++#if !defined(EAI_BADFLAGS)+# define EAI_BADFLAGS WSAEINVAL+#endif++#if !defined(EAI_FAIL)+# define EAI_FAIL WSANO_RECOVERY+#endif++#if !defined(EAI_FAMILY)+# define EAI_FAMILY WSAEAFNOSUPPORT+#endif++#if !defined(EAI_MEMORY)+# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY+#endif++#if !defined(EAI_NODATA)+# define EAI_NODATA WSANO_DATA+#endif++#if !defined(EAI_NONAME)+# define EAI_NONAME WSAHOST_NOT_FOUND+#endif++#if !defined(EAI_SERVICE)+# define EAI_SERVICE WSATYPE_NOT_FOUND+#endif++#if !defined(EAI_SOCKTYPE)+# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT+#endif++#if !defined(NI_NOFQDN)+# define NI_NOFQDN 0x01+#endif++#if !defined(NI_NUMERICHOST)+# define NI_NUMERICHOST 0x02+#endif++#if !defined(NI_NAMEREQD)+# define NI_NAMEREQD 0x04+#endif++#if !defined(NI_NUMERICSERV)+# define NI_NUMERICSERV 0x08+#endif++#if !defined(NI_DGRAM)+# define NI_DGRAM 0x10+#endif++#if !defined(IPPROTO_IPV6)+# define IPPROTO_IPV6 41+#endif++#if !defined(IPV6_UNICAST_HOPS)+# define IPV6_UNICAST_HOPS 4+#endif++#if !defined(IPV6_MULTICAST_IF)+# define IPV6_MULTICAST_IF 9+#endif++#if !defined(IPV6_MULTICAST_HOPS)+# define IPV6_MULTICAST_HOPS 10+#endif++#if !defined(IPV6_MULTICAST_LOOP)+# define IPV6_MULTICAST_LOOP 11+#endif++#if !defined(IPV6_JOIN_GROUP)+# define IPV6_JOIN_GROUP 12+#endif++#if !defined(IPV6_LEAVE_GROUP)+# define IPV6_LEAVE_GROUP 13+#endif++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_OLD_WIN_SDK)++// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY.+#if !defined(IPV6_V6ONLY)+# define IPV6_V6ONLY 27+#endif++// Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6.+#if !defined(IPPROTO_ICMPV6)+# define IPPROTO_ICMPV6 58+#endif++#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++#endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/op_queue.hpp view
@@ -0,0 +1,162 @@+//+// detail/op_queue.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_OP_QUEUE_HPP+#define ASIO_DETAIL_OP_QUEUE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Operation>+class op_queue;++class op_queue_access+{+public:+ template <typename Operation>+ static Operation* next(Operation* o)+ {+ return static_cast<Operation*>(o->next_);+ }++ template <typename Operation1, typename Operation2>+ static void next(Operation1*& o1, Operation2* o2)+ {+ o1->next_ = o2;+ }++ template <typename Operation>+ static void destroy(Operation* o)+ {+ o->destroy();+ }++ template <typename Operation>+ static Operation*& front(op_queue<Operation>& q)+ {+ return q.front_;+ }++ template <typename Operation>+ static Operation*& back(op_queue<Operation>& q)+ {+ return q.back_;+ }+};++template <typename Operation>+class op_queue+ : private noncopyable+{+public:+ // Constructor.+ op_queue()+ : front_(0),+ back_(0)+ {+ }++ // Destructor destroys all operations.+ ~op_queue()+ {+ while (Operation* op = front_)+ {+ pop();+ op_queue_access::destroy(op);+ }+ }++ // Get the operation at the front of the queue.+ Operation* front()+ {+ return front_;+ }++ // Pop an operation from the front of the queue.+ void pop()+ {+ if (front_)+ {+ Operation* tmp = front_;+ front_ = op_queue_access::next(front_);+ if (front_ == 0)+ back_ = 0;+ op_queue_access::next(tmp, static_cast<Operation*>(0));+ }+ }++ // Push an operation on to the back of the queue.+ void push(Operation* h)+ {+ op_queue_access::next(h, static_cast<Operation*>(0));+ if (back_)+ {+ op_queue_access::next(back_, h);+ back_ = h;+ }+ else+ {+ front_ = back_ = h;+ }+ }++ // Push all operations from another queue on to the back of the queue. The+ // source queue may contain operations of a derived type.+ template <typename OtherOperation>+ void push(op_queue<OtherOperation>& q)+ {+ if (Operation* other_front = op_queue_access::front(q))+ {+ if (back_)+ op_queue_access::next(back_, other_front);+ else+ front_ = other_front;+ back_ = op_queue_access::back(q);+ op_queue_access::front(q) = 0;+ op_queue_access::back(q) = 0;+ }+ }++ // Whether the queue is empty.+ bool empty() const+ {+ return front_ == 0;+ }++ // Test whether an operation is already enqueued.+ bool is_enqueued(Operation* o) const+ {+ return op_queue_access::next(o) != 0 || back_ == o;+ }++private:+ friend class op_queue_access;++ // The front of the queue.+ Operation* front_;++ // The back of the queue.+ Operation* back_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_OP_QUEUE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/operation.hpp view
@@ -0,0 +1,38 @@+//+// detail/operation.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_OPERATION_HPP+#define ASIO_DETAIL_OPERATION_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_IOCP)+# include "asio/detail/win_iocp_operation.hpp"+#else+# include "asio/detail/scheduler_operation.hpp"+#endif++namespace asio {+namespace detail {++#if defined(ASIO_HAS_IOCP)+typedef win_iocp_operation operation;+#else+typedef scheduler_operation operation;+#endif++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_OPERATION_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/pipe_select_interrupter.hpp view
@@ -0,0 +1,89 @@+//+// detail/pipe_select_interrupter.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_PIPE_SELECT_INTERRUPTER_HPP+#define ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_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_WINDOWS)+#if !defined(ASIO_WINDOWS_RUNTIME)+#if !defined(__CYGWIN__)+#if !defined(__SYMBIAN32__)+#if !defined(ASIO_HAS_EVENTFD)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class pipe_select_interrupter+{+public:+ // Constructor.+ ASIO_DECL pipe_select_interrupter();++ // Destructor.+ ASIO_DECL ~pipe_select_interrupter();++ // Recreate the interrupter's descriptors. Used after a fork.+ ASIO_DECL void recreate();++ // Interrupt the select call.+ ASIO_DECL void interrupt();++ // Reset the select interrupter. Returns true if the reset was successful.+ ASIO_DECL bool reset();++ // Get the read descriptor to be passed to select.+ int read_descriptor() const+ {+ return read_descriptor_;+ }++private:+ // Open the descriptors. Throws on error.+ ASIO_DECL void open_descriptors();++ // Close the descriptors.+ ASIO_DECL void close_descriptors();++ // The read end of a connection used to interrupt the select call. This file+ // descriptor is passed to select such that when it is time to stop, a single+ // byte will be written on the other end of the connection and this+ // descriptor will become readable.+ int read_descriptor_;++ // The write end of a connection used to interrupt the select call. A single+ // byte may be written to this to wake up the select which is waiting for the+ // other end to become readable.+ int write_descriptor_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/pipe_select_interrupter.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // !defined(ASIO_HAS_EVENTFD)+#endif // !defined(__SYMBIAN32__)+#endif // !defined(__CYGWIN__)+#endif // !defined(ASIO_WINDOWS_RUNTIME)+#endif // !defined(ASIO_WINDOWS)++#endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/pop_options.hpp view
@@ -0,0 +1,141 @@+//+// detail/pop_options.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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)+//++// No header guard++#if defined(__COMO__)++// Comeau C++++#elif defined(__DMC__)++// Digital Mars C++++#elif defined(__INTEL_COMPILER) || defined(__ICL) \+ || defined(__ICC) || defined(__ECC)++// Intel C++++# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)+# if !defined(ASIO_DISABLE_VISIBILITY)+# pragma GCC visibility pop+# endif // !defined(ASIO_DISABLE_VISIBILITY)+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)++#elif defined(__clang__)++// Clang++# if defined(__OBJC__)+# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)+# if defined(ASIO_OBJC_WORKAROUND)+# undef Protocol+# undef id+# undef ASIO_OBJC_WORKAROUND+# endif+# endif+# endif++# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)+# if !defined(ASIO_DISABLE_VISIBILITY)+# pragma GCC visibility pop+# endif // !defined(ASIO_DISABLE_VISIBILITY)+# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)++# pragma GCC diagnostic pop++#elif defined(__GNUC__)++// GNU C++++# if defined(__MINGW32__) || defined(__CYGWIN__)+# pragma pack (pop)+# endif++# if defined(__OBJC__)+# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)+# if defined(ASIO_OBJC_WORKAROUND)+# undef Protocol+# undef id+# undef ASIO_OBJC_WORKAROUND+# endif+# endif+# endif++# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)+# if !defined(ASIO_DISABLE_VISIBILITY)+# pragma GCC visibility pop+# endif // !defined(ASIO_DISABLE_VISIBILITY)+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)++# pragma GCC diagnostic pop++#elif defined(__KCC)++// Kai C++++#elif defined(__sgi)++// SGI MIPSpro C++++#elif defined(__DECCXX)++// Compaq Tru64 Unix cxx++#elif defined(__ghs)++// Greenhills C++++#elif defined(__BORLANDC__) && !defined(__clang__)++// Borland C++++# pragma option pop+# pragma nopushoptwarn+# pragma nopackwarning++#elif defined(__MWERKS__)++// Metrowerks CodeWarrior++#elif defined(__SUNPRO_CC)++// Sun Workshop Compiler C++++#elif defined(__HP_aCC)++// HP aCC++#elif defined(__MRC__) || defined(__SC__)++// MPW MrCpp or SCpp++#elif defined(__IBMCPP__)++// IBM Visual Age++#elif defined(_MSC_VER)++// Microsoft Visual C+++//+// Must remain the last #elif since some other vendors (Metrowerks, for example)+// also #define _MSC_VER++# pragma warning (pop)+# pragma pack (pop)++# if defined(__cplusplus_cli) || defined(__cplusplus_winrt)+# if defined(ASIO_CLR_WORKAROUND)+# undef generic+# undef ASIO_CLR_WORKAROUND+# endif+# endif++#endif
+ link/modules/asio-standalone/asio/include/asio/detail/posix_event.hpp view
@@ -0,0 +1,175 @@+//+// detail/posix_event.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_EVENT_HPP+#define ASIO_DETAIL_POSIX_EVENT_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_PTHREADS)++#include <cstddef>+#include <pthread.h>+#include "asio/detail/assert.hpp"+#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class posix_event+ : private noncopyable+{+public:+ // Constructor.+ ASIO_DECL posix_event();++ // Destructor.+ ~posix_event()+ {+ ::pthread_cond_destroy(&cond_);+ }++ // Signal the event. (Retained for backward compatibility.)+ template <typename Lock>+ void signal(Lock& lock)+ {+ this->signal_all(lock);+ }++ // Signal all waiters.+ template <typename Lock>+ void signal_all(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ (void)lock;+ state_ |= 1;+ ::pthread_cond_broadcast(&cond_); // Ignore EINVAL.+ }++ // Unlock the mutex and signal one waiter.+ template <typename Lock>+ void unlock_and_signal_one(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ state_ |= 1;+ bool have_waiters = (state_ > 1);+ lock.unlock();+ if (have_waiters)+ ::pthread_cond_signal(&cond_); // Ignore EINVAL.+ }++ // Unlock the mutex and signal one waiter who may destroy us.+ template <typename Lock>+ void unlock_and_signal_one_for_destruction(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ state_ |= 1;+ bool have_waiters = (state_ > 1);+ if (have_waiters)+ ::pthread_cond_signal(&cond_); // Ignore EINVAL.+ lock.unlock();+ }++ // If there's a waiter, unlock the mutex and signal it.+ template <typename Lock>+ bool maybe_unlock_and_signal_one(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ state_ |= 1;+ if (state_ > 1)+ {+ lock.unlock();+ ::pthread_cond_signal(&cond_); // Ignore EINVAL.+ return true;+ }+ return false;+ }++ // Reset the event.+ template <typename Lock>+ void clear(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ (void)lock;+ state_ &= ~std::size_t(1);+ }++ // Wait for the event to become signalled.+ template <typename Lock>+ void wait(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ while ((state_ & 1) == 0)+ {+ state_ += 2;+ ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL.+ state_ -= 2;+ }+ }++ // Timed wait for the event to become signalled.+ template <typename Lock>+ bool wait_for_usec(Lock& lock, long usec)+ {+ ASIO_ASSERT(lock.locked());+ if ((state_ & 1) == 0)+ {+ state_ += 2;+ timespec ts;+#if (defined(__MACH__) && defined(__APPLE__)) \+ || (defined(__ANDROID__) && (__ANDROID_API__ < 21) \+ && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE))+ ts.tv_sec = usec / 1000000;+ ts.tv_nsec = (usec % 1000000) * 1000;+ ::pthread_cond_timedwait_relative_np(+ &cond_, &lock.mutex().mutex_, &ts); // Ignore EINVAL.+#else // (defined(__MACH__) && defined(__APPLE__))+ // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)+ // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE))+ if (::clock_gettime(CLOCK_MONOTONIC, &ts) == 0)+ {+ ts.tv_sec += usec / 1000000;+ ts.tv_nsec += (usec % 1000000) * 1000;+ ts.tv_sec += ts.tv_nsec / 1000000000;+ ts.tv_nsec = ts.tv_nsec % 1000000000;+ ::pthread_cond_timedwait(&cond_,+ &lock.mutex().mutex_, &ts); // Ignore EINVAL.+ }+#endif // (defined(__MACH__) && defined(__APPLE__))+ // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)+ // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE))+ state_ -= 2;+ }+ return (state_ & 1) != 0;+ }++private:+ ::pthread_cond_t cond_;+ std::size_t state_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/posix_event.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_PTHREADS)++#endif // ASIO_DETAIL_POSIX_EVENT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/posix_fd_set_adapter.hpp view
@@ -0,0 +1,118 @@+//+// detail/posix_fd_set_adapter.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_FD_SET_ADAPTER_HPP+#define ASIO_DETAIL_POSIX_FD_SET_ADAPTER_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_WINDOWS) \+ && !defined(__CYGWIN__) \+ && !defined(ASIO_WINDOWS_RUNTIME)++#include <cstring>+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/reactor_op_queue.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.+class posix_fd_set_adapter : noncopyable+{+public:+ posix_fd_set_adapter()+ : max_descriptor_(invalid_socket)+ {+ using namespace std; // Needed for memset on Solaris.+ FD_ZERO(&fd_set_);+ }++ void reset()+ {+ using namespace std; // Needed for memset on Solaris.+ FD_ZERO(&fd_set_);+ }++ bool set(socket_type descriptor)+ {+ if (descriptor < (socket_type)FD_SETSIZE)+ {+ if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_)+ max_descriptor_ = descriptor;+ FD_SET(descriptor, &fd_set_);+ return true;+ }+ return false;+ }++ void set(reactor_op_queue<socket_type>& operations, op_queue<operation>& ops)+ {+ reactor_op_queue<socket_type>::iterator i = operations.begin();+ while (i != operations.end())+ {+ reactor_op_queue<socket_type>::iterator op_iter = i++;+ if (!set(op_iter->first))+ {+ asio::error_code ec(error::fd_set_failure);+ operations.cancel_operations(op_iter, ops, ec);+ }+ }+ }++ bool is_set(socket_type descriptor) const+ {+ return FD_ISSET(descriptor, &fd_set_) != 0;+ }++ operator fd_set*()+ {+ return &fd_set_;+ }++ socket_type max_descriptor() const+ {+ return max_descriptor_;+ }++ void perform(reactor_op_queue<socket_type>& operations,+ op_queue<operation>& ops) const+ {+ reactor_op_queue<socket_type>::iterator i = operations.begin();+ while (i != operations.end())+ {+ reactor_op_queue<socket_type>::iterator op_iter = i++;+ if (is_set(op_iter->first))+ operations.perform_operations(op_iter, ops);+ }+ }++private:+ mutable fd_set fd_set_;+ socket_type max_descriptor_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_WINDOWS)+ // && !defined(__CYGWIN__)+ // && !defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/posix_global.hpp view
@@ -0,0 +1,80 @@+//+// detail/posix_global.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_GLOBAL_HPP+#define ASIO_DETAIL_POSIX_GLOBAL_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_PTHREADS)++#include <exception>+#include <pthread.h>++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename T>+struct posix_global_impl+{+ // Helper function to perform initialisation.+ static void do_init()+ {+ instance_.static_ptr_ = instance_.ptr_ = new T;+ }++ // Destructor automatically cleans up the global.+ ~posix_global_impl()+ {+ delete static_ptr_;+ }++ static ::pthread_once_t init_once_;+ static T* static_ptr_;+ static posix_global_impl instance_;+ T* ptr_;+};++template <typename T>+::pthread_once_t posix_global_impl<T>::init_once_ = PTHREAD_ONCE_INIT;++template <typename T>+T* posix_global_impl<T>::static_ptr_ = 0;++template <typename T>+posix_global_impl<T> posix_global_impl<T>::instance_;++template <typename T>+T& posix_global()+{+ int result = ::pthread_once(+ &posix_global_impl<T>::init_once_,+ &posix_global_impl<T>::do_init);++ if (result != 0)+ std::terminate();++ return *posix_global_impl<T>::instance_.ptr_;+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_PTHREADS)++#endif // ASIO_DETAIL_POSIX_GLOBAL_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/posix_mutex.hpp view
@@ -0,0 +1,76 @@+//+// detail/posix_mutex.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_MUTEX_HPP+#define ASIO_DETAIL_POSIX_MUTEX_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_PTHREADS)++#include <pthread.h>+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/scoped_lock.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class posix_event;++class posix_mutex+ : private noncopyable+{+public:+ typedef asio::detail::scoped_lock<posix_mutex> scoped_lock;++ // Constructor.+ ASIO_DECL posix_mutex();++ // Destructor.+ ~posix_mutex()+ {+ ::pthread_mutex_destroy(&mutex_); // Ignore EBUSY.+ }++ // Lock the mutex.+ void lock()+ {+ (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL.+ }++ // Unlock the mutex.+ void unlock()+ {+ (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL.+ }++private:+ friend class posix_event;+ ::pthread_mutex_t mutex_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/posix_mutex.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_PTHREADS)++#endif // ASIO_DETAIL_POSIX_MUTEX_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/posix_signal_blocker.hpp view
@@ -0,0 +1,85 @@+//+// detail/posix_signal_blocker.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_SIGNAL_BLOCKER_HPP+#define ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_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_PTHREADS)++#include <csignal>+#include <pthread.h>+#include <signal.h>+#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class posix_signal_blocker+ : private noncopyable+{+public:+ // Constructor blocks all signals for the calling thread.+ posix_signal_blocker()+ : blocked_(false)+ {+ sigset_t new_mask;+ sigfillset(&new_mask);+ blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);+ }++ // Destructor restores the previous signal mask.+ ~posix_signal_blocker()+ {+ if (blocked_)+ pthread_sigmask(SIG_SETMASK, &old_mask_, 0);+ }++ // Block all signals for the calling thread.+ void block()+ {+ if (!blocked_)+ {+ sigset_t new_mask;+ sigfillset(&new_mask);+ blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);+ }+ }++ // Restore the previous signal mask.+ void unblock()+ {+ if (blocked_)+ blocked_ = (pthread_sigmask(SIG_SETMASK, &old_mask_, 0) != 0);+ }++private:+ // Have signals been blocked.+ bool blocked_;++ // The previous signal mask.+ sigset_t old_mask_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_PTHREADS)++#endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/posix_static_mutex.hpp view
@@ -0,0 +1,64 @@+//+// detail/posix_static_mutex.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_STATIC_MUTEX_HPP+#define ASIO_DETAIL_POSIX_STATIC_MUTEX_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_PTHREADS)++#include <pthread.h>+#include "asio/detail/scoped_lock.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++struct posix_static_mutex+{+ typedef asio::detail::scoped_lock<posix_static_mutex> scoped_lock;++ // Initialise the mutex.+ void init()+ {+ // Nothing to do.+ }++ // Lock the mutex.+ void lock()+ {+ (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL.+ }++ // Unlock the mutex.+ void unlock()+ {+ (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL.+ }++ ::pthread_mutex_t mutex_;+};++#define ASIO_POSIX_STATIC_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER }++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_PTHREADS)++#endif // ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/posix_thread.hpp view
@@ -0,0 +1,109 @@+//+// detail/posix_thread.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_THREAD_HPP+#define ASIO_DETAIL_POSIX_THREAD_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_PTHREADS)++#include <cstddef>+#include <pthread.h>+#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++extern "C"+{+ ASIO_DECL void* asio_detail_posix_thread_function(void* arg);+}++class posix_thread+ : private noncopyable+{+public:+ // Constructor.+ template <typename Function>+ posix_thread(Function f, unsigned int = 0)+ : joined_(false)+ {+ start_thread(new func<Function>(f));+ }++ // Destructor.+ ASIO_DECL ~posix_thread();++ // Wait for the thread to exit.+ ASIO_DECL void join();++ // Get number of CPUs.+ ASIO_DECL static std::size_t hardware_concurrency();++private:+ friend void* asio_detail_posix_thread_function(void* arg);++ class func_base+ {+ public:+ virtual ~func_base() {}+ virtual void run() = 0;+ };++ struct auto_func_base_ptr+ {+ func_base* ptr;+ ~auto_func_base_ptr() { delete ptr; }+ };++ template <typename Function>+ class func+ : public func_base+ {+ public:+ func(Function f)+ : f_(f)+ {+ }++ virtual void run()+ {+ f_();+ }++ private:+ Function f_;+ };++ ASIO_DECL void start_thread(func_base* arg);++ ::pthread_t thread_;+ bool joined_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/posix_thread.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_PTHREADS)++#endif // ASIO_DETAIL_POSIX_THREAD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/posix_tss_ptr.hpp view
@@ -0,0 +1,79 @@+//+// detail/posix_tss_ptr.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_TSS_PTR_HPP+#define ASIO_DETAIL_POSIX_TSS_PTR_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_PTHREADS)++#include <pthread.h>+#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Helper function to create thread-specific storage.+ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key);++template <typename T>+class posix_tss_ptr+ : private noncopyable+{+public:+ // Constructor.+ posix_tss_ptr()+ {+ posix_tss_ptr_create(tss_key_);+ }++ // Destructor.+ ~posix_tss_ptr()+ {+ ::pthread_key_delete(tss_key_);+ }++ // Get the value.+ operator T*() const+ {+ return static_cast<T*>(::pthread_getspecific(tss_key_));+ }++ // Set the value.+ void operator=(T* value)+ {+ ::pthread_setspecific(tss_key_, value);+ }++private:+ // Thread-specific storage to allow unlocked access to determine whether a+ // thread is a member of the pool.+ pthread_key_t tss_key_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/posix_tss_ptr.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_PTHREADS)++#endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/push_options.hpp view
@@ -0,0 +1,185 @@+//+// detail/push_options.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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)+//++// No header guard++#if defined(__COMO__)++// Comeau C++++#elif defined(__DMC__)++// Digital Mars C++++#elif defined(__INTEL_COMPILER) || defined(__ICL) \+ || defined(__ICC) || defined(__ECC)++// Intel C++++# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)+# if !defined(ASIO_DISABLE_VISIBILITY)+# pragma GCC visibility push (default)+# endif // !defined(ASIO_DISABLE_VISIBILITY)+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)++#elif defined(__clang__)++// Clang++# if defined(__OBJC__)+# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)+# if !defined(ASIO_DISABLE_OBJC_WORKAROUND)+# if !defined(Protocol) && !defined(id)+# define Protocol cpp_Protocol+# define id cpp_id+# define ASIO_OBJC_WORKAROUND+# endif+# endif+# endif+# endif++# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)+# if !defined(ASIO_DISABLE_VISIBILITY)+# pragma GCC visibility push (default)+# endif // !defined(ASIO_DISABLE_VISIBILITY)+# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)++# pragma GCC diagnostic push+# pragma GCC diagnostic ignored "-Wnon-virtual-dtor"++#elif defined(__GNUC__)++// GNU C++++# if defined(__MINGW32__) || defined(__CYGWIN__)+# pragma pack (push, 8)+# endif++# if defined(__OBJC__)+# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)+# if !defined(ASIO_DISABLE_OBJC_WORKAROUND)+# if !defined(Protocol) && !defined(id)+# define Protocol cpp_Protocol+# define id cpp_id+# define ASIO_OBJC_WORKAROUND+# endif+# endif+# endif+# endif++# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)+# if !defined(ASIO_DISABLE_VISIBILITY)+# pragma GCC visibility push (default)+# endif // !defined(ASIO_DISABLE_VISIBILITY)+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)++# pragma GCC diagnostic push+# pragma GCC diagnostic ignored "-Wnon-virtual-dtor"+# if (__GNUC__ >= 7)+# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"+# endif // (__GNUC__ >= 7)++#elif defined(__KCC)++// Kai C++++#elif defined(__sgi)++// SGI MIPSpro C++++#elif defined(__DECCXX)++// Compaq Tru64 Unix cxx++#elif defined(__ghs)++// Greenhills C++++#elif defined(__BORLANDC__) && !defined(__clang__)++// Borland C++++# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi-+# pragma nopushoptwarn+# pragma nopackwarning+# if !defined(__MT__)+# error Multithreaded RTL must be selected.+# endif // !defined(__MT__)++#elif defined(__MWERKS__)++// Metrowerks CodeWarrior++#elif defined(__SUNPRO_CC)++// Sun Workshop Compiler C++++#elif defined(__HP_aCC)++// HP aCC++#elif defined(__MRC__) || defined(__SC__)++// MPW MrCpp or SCpp++#elif defined(__IBMCPP__)++// IBM Visual Age++#elif defined(_MSC_VER)++// Microsoft Visual C+++//+// Must remain the last #elif since some other vendors (Metrowerks, for example)+// also #define _MSC_VER++# pragma warning (disable:4103)+# pragma warning (push)+# pragma warning (disable:4127)+# pragma warning (disable:4180)+# pragma warning (disable:4244)+# pragma warning (disable:4355)+# pragma warning (disable:4510)+# pragma warning (disable:4512)+# pragma warning (disable:4610)+# pragma warning (disable:4675)+# if (_MSC_VER < 1600)+// Visual Studio 2008 generates spurious warnings about unused parameters.+# pragma warning (disable:4100)+# endif // (_MSC_VER < 1600)+# if defined(_M_IX86) && defined(_Wp64)+// The /Wp64 option is broken. If you want to check 64 bit portability, use a+// 64 bit compiler!+# pragma warning (disable:4311)+# pragma warning (disable:4312)+# endif // defined(_M_IX86) && defined(_Wp64)+# pragma pack (push, 8)+// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler+// has a tendency to incorrectly optimise away some calls to member template+// functions, even though those functions contain code that should not be+// optimised away! Therefore we will always disable this optimisation option+// for the MSVC6 compiler.+# if (_MSC_VER < 1300)+# pragma optimize ("g", off)+# endif+# if !defined(_MT)+# error Multithreaded RTL must be selected.+# endif // !defined(_MT)++# if defined(__cplusplus_cli) || defined(__cplusplus_winrt)+# if !defined(ASIO_DISABLE_CLR_WORKAROUND)+# if !defined(generic)+# define generic cpp_generic+# define ASIO_CLR_WORKAROUND+# endif+# endif+# endif++#endif
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_descriptor_service.hpp view
@@ -0,0 +1,416 @@+//+// detail/reactive_descriptor_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_DESCRIPTOR_SERVICE_HPP+#define ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_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_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)++#include "asio/buffer.hpp"+#include "asio/execution_context.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/descriptor_ops.hpp"+#include "asio/detail/descriptor_read_op.hpp"+#include "asio/detail/descriptor_write_op.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/reactive_null_buffers_op.hpp"+#include "asio/detail/reactive_wait_op.hpp"+#include "asio/detail/reactor.hpp"+#include "asio/posix/descriptor_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class reactive_descriptor_service :+ public execution_context_service_base<reactive_descriptor_service>+{+public:+ // The native type of a descriptor.+ typedef int native_handle_type;++ // The implementation type of the descriptor.+ class implementation_type+ : private asio::detail::noncopyable+ {+ public:+ // Default constructor.+ implementation_type()+ : descriptor_(-1),+ state_(0)+ {+ }++ private:+ // Only this service will have access to the internal values.+ friend class reactive_descriptor_service;++ // The native descriptor representation.+ int descriptor_;++ // The current state of the descriptor.+ descriptor_ops::state_type state_;++ // Per-descriptor data used by the reactor.+ reactor::per_descriptor_data reactor_data_;+ };++ // Constructor.+ ASIO_DECL reactive_descriptor_service(execution_context& context);++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Construct a new descriptor implementation.+ ASIO_DECL void construct(implementation_type& impl);++ // Move-construct a new descriptor implementation.+ ASIO_DECL void move_construct(implementation_type& impl,+ implementation_type& other_impl) ASIO_NOEXCEPT;++ // Move-assign from another descriptor implementation.+ ASIO_DECL void move_assign(implementation_type& impl,+ reactive_descriptor_service& other_service,+ implementation_type& other_impl);++ // Destroy a descriptor implementation.+ ASIO_DECL void destroy(implementation_type& impl);++ // Assign a native descriptor to a descriptor implementation.+ ASIO_DECL asio::error_code assign(implementation_type& impl,+ const native_handle_type& native_descriptor,+ asio::error_code& ec);++ // Determine whether the descriptor is open.+ bool is_open(const implementation_type& impl) const+ {+ return impl.descriptor_ != -1;+ }++ // Destroy a descriptor implementation.+ ASIO_DECL asio::error_code close(implementation_type& impl,+ asio::error_code& ec);++ // Get the native descriptor representation.+ native_handle_type native_handle(const implementation_type& impl) const+ {+ return impl.descriptor_;+ }++ // Release ownership of the native descriptor representation.+ ASIO_DECL native_handle_type release(implementation_type& impl);++ // Cancel all operations associated with the descriptor.+ ASIO_DECL asio::error_code cancel(implementation_type& impl,+ asio::error_code& ec);++ // Perform an IO control command on the descriptor.+ template <typename IO_Control_Command>+ asio::error_code io_control(implementation_type& impl,+ IO_Control_Command& command, asio::error_code& ec)+ {+ descriptor_ops::ioctl(impl.descriptor_, impl.state_,+ command.name(), static_cast<ioctl_arg_type*>(command.data()), ec);+ return ec;+ }++ // Gets the non-blocking mode of the descriptor.+ bool non_blocking(const implementation_type& impl) const+ {+ return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0;+ }++ // Sets the non-blocking mode of the descriptor.+ asio::error_code non_blocking(implementation_type& impl,+ bool mode, asio::error_code& ec)+ {+ descriptor_ops::set_user_non_blocking(+ impl.descriptor_, impl.state_, mode, ec);+ return ec;+ }++ // Gets the non-blocking mode of the native descriptor implementation.+ bool native_non_blocking(const implementation_type& impl) const+ {+ return (impl.state_ & descriptor_ops::internal_non_blocking) != 0;+ }++ // Sets the non-blocking mode of the native descriptor implementation.+ asio::error_code native_non_blocking(implementation_type& impl,+ bool mode, asio::error_code& ec)+ {+ descriptor_ops::set_internal_non_blocking(+ impl.descriptor_, impl.state_, mode, ec);+ return ec;+ }++ // Wait for the descriptor to become ready to read, ready to write, or to have+ // pending error conditions.+ asio::error_code wait(implementation_type& impl,+ posix::descriptor_base::wait_type w, asio::error_code& ec)+ {+ switch (w)+ {+ case posix::descriptor_base::wait_read:+ descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);+ break;+ case posix::descriptor_base::wait_write:+ descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);+ break;+ case posix::descriptor_base::wait_error:+ descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec);+ break;+ default:+ ec = asio::error::invalid_argument;+ break;+ }++ return ec;+ }++ // Asynchronously wait for the descriptor to become ready to read, ready to+ // write, or to have pending error conditions.+ template <typename Handler, typename IoExecutor>+ void async_wait(implementation_type& impl,+ posix::descriptor_base::wait_type w,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_wait_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",+ &impl, impl.descriptor_, "async_wait"));++ int op_type;+ switch (w)+ {+ case posix::descriptor_base::wait_read:+ op_type = reactor::read_op;+ break;+ case posix::descriptor_base::wait_write:+ op_type = reactor::write_op;+ break;+ case posix::descriptor_base::wait_error:+ op_type = reactor::except_op;+ break;+ default:+ p.p->ec_ = asio::error::invalid_argument;+ reactor_.post_immediate_completion(p.p, is_continuation);+ p.v = p.p = 0;+ return;+ }++ start_op(impl, op_type, p.p, is_continuation, false, false);+ p.v = p.p = 0;+ }++ // Write some data to the descriptor.+ template <typename ConstBufferSequence>+ size_t write_some(implementation_type& impl,+ const ConstBufferSequence& buffers, asio::error_code& ec)+ {+ typedef buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence> bufs_type;++ if (bufs_type::is_single_buffer)+ {+ return descriptor_ops::sync_write1(impl.descriptor_,+ impl.state_, bufs_type::first(buffers).data(),+ bufs_type::first(buffers).size(), ec);+ }+ else+ {+ bufs_type bufs(buffers);++ return descriptor_ops::sync_write(impl.descriptor_, impl.state_,+ bufs.buffers(), bufs.count(), bufs.all_empty(), ec);+ }+ }++ // Wait until data can be written without blocking.+ size_t write_some(implementation_type& impl,+ const null_buffers&, asio::error_code& ec)+ {+ // Wait for descriptor to become ready.+ descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);++ return 0;+ }++ // Start an asynchronous write. The data being sent must be valid for the+ // lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_write_some(implementation_type& impl,+ const ConstBufferSequence& buffers, Handler& handler,+ const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef descriptor_write_op<ConstBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",+ &impl, impl.descriptor_, "async_write_some"));++ start_op(impl, reactor::write_op, p.p, is_continuation, true,+ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::all_empty(buffers));+ p.v = p.p = 0;+ }++ // Start an asynchronous wait until data can be written without blocking.+ template <typename Handler, typename IoExecutor>+ void async_write_some(implementation_type& impl,+ const null_buffers&, Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",+ &impl, impl.descriptor_, "async_write_some(null_buffers)"));++ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);+ p.v = p.p = 0;+ }++ // Read some data from the stream. Returns the number of bytes read.+ template <typename MutableBufferSequence>+ size_t read_some(implementation_type& impl,+ const MutableBufferSequence& buffers, asio::error_code& ec)+ {+ typedef buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs_type;++ if (bufs_type::is_single_buffer)+ {+ return descriptor_ops::sync_read1(impl.descriptor_,+ impl.state_, bufs_type::first(buffers).data(),+ bufs_type::first(buffers).size(), ec);+ }+ else+ {+ bufs_type bufs(buffers);++ return descriptor_ops::sync_read(impl.descriptor_, impl.state_,+ bufs.buffers(), bufs.count(), bufs.all_empty(), ec);+ }+ }++ // Wait until data can be read without blocking.+ size_t read_some(implementation_type& impl,+ const null_buffers&, asio::error_code& ec)+ {+ // Wait for descriptor to become ready.+ descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);++ return 0;+ }++ // Start an asynchronous read. The buffer for the data being read must be+ // valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_read_some(implementation_type& impl,+ const MutableBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef descriptor_read_op<MutableBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",+ &impl, impl.descriptor_, "async_read_some"));++ start_op(impl, reactor::read_op, p.p, is_continuation, true,+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::all_empty(buffers));+ p.v = p.p = 0;+ }++ // Wait until data can be read without blocking.+ template <typename Handler, typename IoExecutor>+ void async_read_some(implementation_type& impl,+ const null_buffers&, Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",+ &impl, impl.descriptor_, "async_read_some(null_buffers)"));++ start_op(impl, reactor::read_op, p.p, is_continuation, false, false);+ p.v = p.p = 0;+ }++private:+ // Start the asynchronous operation.+ ASIO_DECL void start_op(implementation_type& impl, int op_type,+ reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);++ // The selector that performs event demultiplexing for the service.+ reactor& reactor_;++ // Cached success value to avoid accessing category singleton.+ const asio::error_code success_ec_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/reactive_descriptor_service.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)++#endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_null_buffers_op.hpp view
@@ -0,0 +1,98 @@+//+// detail/reactive_null_buffers_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_NULL_BUFFERS_OP_HPP+#define ASIO_DETAIL_REACTIVE_NULL_BUFFERS_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/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename IoExecutor>+class reactive_null_buffers_op : public reactor_op+{+public:+ ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op);++ reactive_null_buffers_op(const asio::error_code& success_ec,+ Handler& handler, const IoExecutor& io_ex)+ : reactor_op(success_ec, &reactive_null_buffers_op::do_perform,+ &reactive_null_buffers_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static status do_perform(reactor_op*)+ {+ return done;+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_serial_port_service.hpp view
@@ -0,0 +1,237 @@+//+// detail/reactive_serial_port_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_REACTIVE_SERIAL_PORT_SERVICE_HPP+#define ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_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_SERIAL_PORT)+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++#include <string>+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/serial_port_base.hpp"+#include "asio/detail/descriptor_ops.hpp"+#include "asio/detail/reactive_descriptor_service.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Extend reactive_descriptor_service to provide serial port support.+class reactive_serial_port_service :+ public execution_context_service_base<reactive_serial_port_service>+{+public:+ // The native type of a serial port.+ typedef reactive_descriptor_service::native_handle_type native_handle_type;++ // The implementation type of the serial port.+ typedef reactive_descriptor_service::implementation_type implementation_type;++ ASIO_DECL reactive_serial_port_service(execution_context& context);++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Construct a new serial port implementation.+ void construct(implementation_type& impl)+ {+ descriptor_service_.construct(impl);+ }++ // Move-construct a new serial port implementation.+ void move_construct(implementation_type& impl,+ implementation_type& other_impl)+ {+ descriptor_service_.move_construct(impl, other_impl);+ }++ // Move-assign from another serial port implementation.+ void move_assign(implementation_type& impl,+ reactive_serial_port_service& other_service,+ implementation_type& other_impl)+ {+ descriptor_service_.move_assign(impl,+ other_service.descriptor_service_, other_impl);+ }++ // Destroy a serial port implementation.+ void destroy(implementation_type& impl)+ {+ descriptor_service_.destroy(impl);+ }++ // Open the serial port using the specified device name.+ ASIO_DECL asio::error_code open(implementation_type& impl,+ const std::string& device, asio::error_code& ec);++ // Assign a native descriptor to a serial port implementation.+ asio::error_code assign(implementation_type& impl,+ const native_handle_type& native_descriptor,+ asio::error_code& ec)+ {+ return descriptor_service_.assign(impl, native_descriptor, ec);+ }++ // Determine whether the serial port is open.+ bool is_open(const implementation_type& impl) const+ {+ return descriptor_service_.is_open(impl);+ }++ // Destroy a serial port implementation.+ asio::error_code close(implementation_type& impl,+ asio::error_code& ec)+ {+ return descriptor_service_.close(impl, ec);+ }++ // Get the native serial port representation.+ native_handle_type native_handle(implementation_type& impl)+ {+ return descriptor_service_.native_handle(impl);+ }++ // Cancel all operations associated with the serial port.+ asio::error_code cancel(implementation_type& impl,+ asio::error_code& ec)+ {+ return descriptor_service_.cancel(impl, ec);+ }++ // Set an option on the serial port.+ template <typename SettableSerialPortOption>+ asio::error_code set_option(implementation_type& impl,+ const SettableSerialPortOption& option, asio::error_code& ec)+ {+ return do_set_option(impl,+ &reactive_serial_port_service::store_option<SettableSerialPortOption>,+ &option, ec);+ }++ // Get an option from the serial port.+ template <typename GettableSerialPortOption>+ asio::error_code get_option(const implementation_type& impl,+ GettableSerialPortOption& option, asio::error_code& ec) const+ {+ return do_get_option(impl,+ &reactive_serial_port_service::load_option<GettableSerialPortOption>,+ &option, ec);+ }++ // Send a break sequence to the serial port.+ asio::error_code send_break(implementation_type& impl,+ asio::error_code& ec)+ {+ int result = ::tcsendbreak(descriptor_service_.native_handle(impl), 0);+ descriptor_ops::get_last_error(ec, result < 0);+ return ec;+ }++ // Write the given data. Returns the number of bytes sent.+ template <typename ConstBufferSequence>+ size_t write_some(implementation_type& impl,+ const ConstBufferSequence& buffers, asio::error_code& ec)+ {+ return descriptor_service_.write_some(impl, buffers, ec);+ }++ // Start an asynchronous write. The data being written must be valid for the+ // lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_write_some(implementation_type& impl,+ const ConstBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ {+ descriptor_service_.async_write_some(impl, buffers, handler, io_ex);+ }++ // Read some data. Returns the number of bytes received.+ template <typename MutableBufferSequence>+ size_t read_some(implementation_type& impl,+ const MutableBufferSequence& buffers, asio::error_code& ec)+ {+ return descriptor_service_.read_some(impl, buffers, ec);+ }++ // Start an asynchronous read. The buffer for the data being received must be+ // valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_read_some(implementation_type& impl,+ const MutableBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ {+ descriptor_service_.async_read_some(impl, buffers, handler, io_ex);+ }++private:+ // Function pointer type for storing a serial port option.+ typedef asio::error_code (*store_function_type)(+ const void*, termios&, asio::error_code&);++ // Helper function template to store a serial port option.+ template <typename SettableSerialPortOption>+ static asio::error_code store_option(const void* option,+ termios& storage, asio::error_code& ec)+ {+ static_cast<const SettableSerialPortOption*>(option)->store(storage, ec);+ return ec;+ }++ // Helper function to set a serial port option.+ ASIO_DECL asio::error_code do_set_option(+ implementation_type& impl, store_function_type store,+ const void* option, asio::error_code& ec);++ // Function pointer type for loading a serial port option.+ typedef asio::error_code (*load_function_type)(+ void*, const termios&, asio::error_code&);++ // Helper function template to load a serial port option.+ template <typename GettableSerialPortOption>+ static asio::error_code load_option(void* option,+ const termios& storage, asio::error_code& ec)+ {+ static_cast<GettableSerialPortOption*>(option)->load(storage, ec);+ return ec;+ }++ // Helper function to get a serial port option.+ ASIO_DECL asio::error_code do_get_option(+ const implementation_type& impl, load_function_type load,+ void* option, asio::error_code& ec) const;++ // The implementation used for initiating asynchronous operations.+ reactive_descriptor_service descriptor_service_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/reactive_serial_port_service.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)+#endif // defined(ASIO_HAS_SERIAL_PORT)++#endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_accept_op.hpp view
@@ -0,0 +1,242 @@+//+// detail/reactive_socket_accept_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_SOCKET_ACCEPT_OP_HPP+#define ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_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/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_holder.hpp"+#include "asio/detail/socket_ops.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Socket, typename Protocol>+class reactive_socket_accept_op_base : public reactor_op+{+public:+ reactive_socket_accept_op_base(const asio::error_code& success_ec,+ socket_type socket, socket_ops::state_type state, Socket& peer,+ const Protocol& protocol, typename Protocol::endpoint* peer_endpoint,+ func_type complete_func)+ : reactor_op(success_ec,+ &reactive_socket_accept_op_base::do_perform, complete_func),+ socket_(socket),+ state_(state),+ peer_(peer),+ protocol_(protocol),+ peer_endpoint_(peer_endpoint),+ addrlen_(peer_endpoint ? peer_endpoint->capacity() : 0)+ {+ }++ static status do_perform(reactor_op* base)+ {+ reactive_socket_accept_op_base* o(+ static_cast<reactive_socket_accept_op_base*>(base));++ socket_type new_socket = invalid_socket;+ status result = socket_ops::non_blocking_accept(o->socket_,+ o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0,+ o->peer_endpoint_ ? &o->addrlen_ : 0, o->ec_, new_socket)+ ? done : not_done;+ o->new_socket_.reset(new_socket);++ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_accept", o->ec_));++ return result;+ }++ void do_assign()+ {+ if (new_socket_.get() != invalid_socket)+ {+ if (peer_endpoint_)+ peer_endpoint_->resize(addrlen_);+ peer_.assign(protocol_, new_socket_.get(), ec_);+ if (!ec_)+ new_socket_.release();+ }+ }++private:+ socket_type socket_;+ socket_ops::state_type state_;+ socket_holder new_socket_;+ Socket& peer_;+ Protocol protocol_;+ typename Protocol::endpoint* peer_endpoint_;+ std::size_t addrlen_;+};++template <typename Socket, typename Protocol,+ typename Handler, typename IoExecutor>+class reactive_socket_accept_op :+ public reactive_socket_accept_op_base<Socket, Protocol>+{+public:+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op);++ reactive_socket_accept_op(const asio::error_code& success_ec,+ socket_type socket, socket_ops::state_type state, Socket& peer,+ const Protocol& protocol, typename Protocol::endpoint* peer_endpoint,+ Handler& handler, const IoExecutor& io_ex)+ : reactive_socket_accept_op_base<Socket, Protocol>(+ success_ec, socket, state, peer, protocol, peer_endpoint,+ &reactive_socket_accept_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ // On success, assign new connection to peer socket object.+ if (owner)+ o->do_assign();++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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::binder1<Handler, asio::error_code>+ handler(o->handler_, o->ec_);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++#if defined(ASIO_HAS_MOVE)++template <typename Protocol, typename PeerIoExecutor,+ typename Handler, typename IoExecutor>+class reactive_socket_move_accept_op :+ private Protocol::socket::template rebind_executor<PeerIoExecutor>::other,+ public reactive_socket_accept_op_base<+ typename Protocol::socket::template rebind_executor<PeerIoExecutor>::other,+ Protocol>+{+public:+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op);++ reactive_socket_move_accept_op(const asio::error_code& success_ec,+ const PeerIoExecutor& peer_io_ex, socket_type socket,+ socket_ops::state_type state, const Protocol& protocol,+ typename Protocol::endpoint* peer_endpoint, Handler& handler,+ const IoExecutor& io_ex)+ : peer_socket_type(peer_io_ex),+ reactive_socket_accept_op_base<peer_socket_type, Protocol>(+ success_ec, socket, state, *this, protocol, peer_endpoint,+ &reactive_socket_move_accept_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ reactive_socket_move_accept_op* o(+ static_cast<reactive_socket_move_accept_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ // On success, assign new connection to peer socket object.+ if (owner)+ o->do_assign();++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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::move_binder2<Handler,+ asio::error_code, peer_socket_type>+ handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_,+ ASIO_MOVE_CAST(peer_socket_type)(*o));+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ typedef typename Protocol::socket::template+ rebind_executor<PeerIoExecutor>::other peer_socket_type;++ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++#endif // defined(ASIO_HAS_MOVE)++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_connect_op.hpp view
@@ -0,0 +1,123 @@+//+// detail/reactive_socket_connect_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_SOCKET_CONNECT_OP_HPP+#define ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_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/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_ops.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class reactive_socket_connect_op_base : public reactor_op+{+public:+ reactive_socket_connect_op_base(const asio::error_code& success_ec,+ socket_type socket, func_type complete_func)+ : reactor_op(success_ec,+ &reactive_socket_connect_op_base::do_perform, complete_func),+ socket_(socket)+ {+ }++ static status do_perform(reactor_op* base)+ {+ reactive_socket_connect_op_base* o(+ static_cast<reactive_socket_connect_op_base*>(base));++ status result = socket_ops::non_blocking_connect(+ o->socket_, o->ec_) ? done : not_done;++ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_connect", o->ec_));++ return result;+ }++private:+ socket_type socket_;+};++template <typename Handler, typename IoExecutor>+class reactive_socket_connect_op : public reactive_socket_connect_op_base+{+public:+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op);++ reactive_socket_connect_op(const asio::error_code& success_ec,+ socket_type socket, Handler& handler, const IoExecutor& io_ex)+ : reactive_socket_connect_op_base(success_ec, socket,+ &reactive_socket_connect_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ reactive_socket_connect_op* o+ (static_cast<reactive_socket_connect_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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::binder1<Handler, asio::error_code>+ handler(o->handler_, o->ec_);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recv_op.hpp view
@@ -0,0 +1,159 @@+//+// detail/reactive_socket_recv_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_SOCKET_RECV_OP_HPP+#define ASIO_DETAIL_REACTIVE_SOCKET_RECV_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/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_ops.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename MutableBufferSequence>+class reactive_socket_recv_op_base : public reactor_op+{+public:+ reactive_socket_recv_op_base(const asio::error_code& success_ec,+ socket_type socket, socket_ops::state_type state,+ const MutableBufferSequence& buffers,+ socket_base::message_flags flags, func_type complete_func)+ : reactor_op(success_ec,+ &reactive_socket_recv_op_base::do_perform, complete_func),+ socket_(socket),+ state_(state),+ buffers_(buffers),+ flags_(flags)+ {+ }++ static status do_perform(reactor_op* base)+ {+ reactive_socket_recv_op_base* o(+ static_cast<reactive_socket_recv_op_base*>(base));++ typedef buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs_type;++ status result;+ if (bufs_type::is_single_buffer)+ {+ result = socket_ops::non_blocking_recv1(o->socket_,+ bufs_type::first(o->buffers_).data(),+ bufs_type::first(o->buffers_).size(), o->flags_,+ (o->state_ & socket_ops::stream_oriented) != 0,+ o->ec_, o->bytes_transferred_) ? done : not_done;+ }+ else+ {+ bufs_type bufs(o->buffers_);+ result = socket_ops::non_blocking_recv(o->socket_,+ bufs.buffers(), bufs.count(), o->flags_,+ (o->state_ & socket_ops::stream_oriented) != 0,+ o->ec_, o->bytes_transferred_) ? done : not_done;+ }++ if (result == done)+ if ((o->state_ & socket_ops::stream_oriented) != 0)+ if (o->bytes_transferred_ == 0)+ result = done_and_exhausted;++ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recv",+ o->ec_, o->bytes_transferred_));++ return result;+ }++private:+ socket_type socket_;+ socket_ops::state_type state_;+ MutableBufferSequence buffers_;+ socket_base::message_flags flags_;+};++template <typename MutableBufferSequence, typename Handler, typename IoExecutor>+class reactive_socket_recv_op :+ public reactive_socket_recv_op_base<MutableBufferSequence>+{+public:+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op);++ reactive_socket_recv_op(const asio::error_code& success_ec,+ socket_type socket, socket_ops::state_type state,+ const MutableBufferSequence& buffers, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ : reactive_socket_recv_op_base<MutableBufferSequence>(success_ec, socket,+ state, buffers, flags, &reactive_socket_recv_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recvfrom_op.hpp view
@@ -0,0 +1,164 @@+//+// detail/reactive_socket_recvfrom_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_SOCKET_RECVFROM_OP_HPP+#define ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_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/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_ops.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename MutableBufferSequence, typename Endpoint>+class reactive_socket_recvfrom_op_base : public reactor_op+{+public:+ reactive_socket_recvfrom_op_base(const asio::error_code& success_ec,+ socket_type socket, int protocol_type,+ const MutableBufferSequence& buffers, Endpoint& endpoint,+ socket_base::message_flags flags, func_type complete_func)+ : reactor_op(success_ec,+ &reactive_socket_recvfrom_op_base::do_perform, complete_func),+ socket_(socket),+ protocol_type_(protocol_type),+ buffers_(buffers),+ sender_endpoint_(endpoint),+ flags_(flags)+ {+ }++ static status do_perform(reactor_op* base)+ {+ reactive_socket_recvfrom_op_base* o(+ static_cast<reactive_socket_recvfrom_op_base*>(base));++ typedef buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs_type;++ std::size_t addr_len = o->sender_endpoint_.capacity();+ status result;+ if (bufs_type::is_single_buffer)+ {+ result = socket_ops::non_blocking_recvfrom1(+ o->socket_, bufs_type::first(o->buffers_).data(),+ bufs_type::first(o->buffers_).size(), o->flags_,+ o->sender_endpoint_.data(), &addr_len,+ o->ec_, o->bytes_transferred_) ? done : not_done;+ }+ else+ {+ bufs_type bufs(o->buffers_);+ result = socket_ops::non_blocking_recvfrom(o->socket_,+ bufs.buffers(), bufs.count(), o->flags_,+ o->sender_endpoint_.data(), &addr_len,+ o->ec_, o->bytes_transferred_) ? done : not_done;+ }++ if (result && !o->ec_)+ o->sender_endpoint_.resize(addr_len);++ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvfrom",+ o->ec_, o->bytes_transferred_));++ return result;+ }++private:+ socket_type socket_;+ int protocol_type_;+ MutableBufferSequence buffers_;+ Endpoint& sender_endpoint_;+ socket_base::message_flags flags_;+};++template <typename MutableBufferSequence, typename Endpoint,+ typename Handler, typename IoExecutor>+class reactive_socket_recvfrom_op :+ public reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>+{+public:+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op);++ reactive_socket_recvfrom_op(const asio::error_code& success_ec,+ socket_type socket, int protocol_type,+ const MutableBufferSequence& buffers, Endpoint& endpoint,+ socket_base::message_flags flags, Handler& handler,+ const IoExecutor& io_ex)+ : reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>(+ success_ec, socket, protocol_type, buffers, endpoint, flags,+ &reactive_socket_recvfrom_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ reactive_socket_recvfrom_op* o(+ static_cast<reactive_socket_recvfrom_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_recvmsg_op.hpp view
@@ -0,0 +1,145 @@+//+// detail/reactive_socket_recvmsg_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_SOCKET_RECVMSG_OP_HPP+#define ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_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/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/socket_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename MutableBufferSequence>+class reactive_socket_recvmsg_op_base : public reactor_op+{+public:+ reactive_socket_recvmsg_op_base(const asio::error_code& success_ec,+ socket_type socket, const MutableBufferSequence& buffers,+ socket_base::message_flags in_flags,+ socket_base::message_flags& out_flags, func_type complete_func)+ : reactor_op(success_ec,+ &reactive_socket_recvmsg_op_base::do_perform, complete_func),+ socket_(socket),+ buffers_(buffers),+ in_flags_(in_flags),+ out_flags_(out_flags)+ {+ }++ static status do_perform(reactor_op* base)+ {+ reactive_socket_recvmsg_op_base* o(+ static_cast<reactive_socket_recvmsg_op_base*>(base));++ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs(o->buffers_);++ status result = socket_ops::non_blocking_recvmsg(o->socket_,+ bufs.buffers(), bufs.count(),+ o->in_flags_, o->out_flags_,+ o->ec_, o->bytes_transferred_) ? done : not_done;++ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvmsg",+ o->ec_, o->bytes_transferred_));++ return result;+ }++private:+ socket_type socket_;+ MutableBufferSequence buffers_;+ socket_base::message_flags in_flags_;+ socket_base::message_flags& out_flags_;+};++template <typename MutableBufferSequence, typename Handler, typename IoExecutor>+class reactive_socket_recvmsg_op :+ public reactive_socket_recvmsg_op_base<MutableBufferSequence>+{+public:+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op);++ reactive_socket_recvmsg_op(const asio::error_code& success_ec,+ socket_type socket, const MutableBufferSequence& buffers,+ socket_base::message_flags in_flags,+ socket_base::message_flags& out_flags, Handler& handler,+ const IoExecutor& io_ex)+ : reactive_socket_recvmsg_op_base<MutableBufferSequence>(+ success_ec, socket, buffers, in_flags, out_flags,+ &reactive_socket_recvmsg_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ reactive_socket_recvmsg_op* o(+ static_cast<reactive_socket_recvmsg_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_send_op.hpp view
@@ -0,0 +1,162 @@+//+// detail/reactive_socket_send_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_SOCKET_SEND_OP_HPP+#define ASIO_DETAIL_REACTIVE_SOCKET_SEND_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/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_ops.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename ConstBufferSequence>+class reactive_socket_send_op_base : public reactor_op+{+public:+ reactive_socket_send_op_base(const asio::error_code& success_ec,+ socket_type socket, socket_ops::state_type state,+ const ConstBufferSequence& buffers,+ socket_base::message_flags flags, func_type complete_func)+ : reactor_op(success_ec,+ &reactive_socket_send_op_base::do_perform, complete_func),+ socket_(socket),+ state_(state),+ buffers_(buffers),+ flags_(flags)+ {+ }++ static status do_perform(reactor_op* base)+ {+ reactive_socket_send_op_base* o(+ static_cast<reactive_socket_send_op_base*>(base));++ typedef buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence> bufs_type;++ status result;+ if (bufs_type::is_single_buffer)+ {+ result = socket_ops::non_blocking_send1(o->socket_,+ bufs_type::first(o->buffers_).data(),+ bufs_type::first(o->buffers_).size(), o->flags_,+ o->ec_, o->bytes_transferred_) ? done : not_done;++ if (result == done)+ if ((o->state_ & socket_ops::stream_oriented) != 0)+ if (o->bytes_transferred_ < bufs_type::first(o->buffers_).size())+ result = done_and_exhausted;+ }+ else+ {+ bufs_type bufs(o->buffers_);+ result = socket_ops::non_blocking_send(o->socket_,+ bufs.buffers(), bufs.count(), o->flags_,+ o->ec_, o->bytes_transferred_) ? done : not_done;++ if (result == done)+ if ((o->state_ & socket_ops::stream_oriented) != 0)+ if (o->bytes_transferred_ < bufs.total_size())+ result = done_and_exhausted;+ }++ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_send",+ o->ec_, o->bytes_transferred_));++ return result;+ }++private:+ socket_type socket_;+ socket_ops::state_type state_;+ ConstBufferSequence buffers_;+ socket_base::message_flags flags_;+};++template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+class reactive_socket_send_op :+ public reactive_socket_send_op_base<ConstBufferSequence>+{+public:+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op);++ reactive_socket_send_op(const asio::error_code& success_ec,+ socket_type socket, socket_ops::state_type state,+ const ConstBufferSequence& buffers, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ : reactive_socket_send_op_base<ConstBufferSequence>(success_ec, socket,+ state, buffers, flags, &reactive_socket_send_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_sendto_op.hpp view
@@ -0,0 +1,156 @@+//+// detail/reactive_socket_sendto_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_SOCKET_SENDTO_OP_HPP+#define ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_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/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_ops.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename ConstBufferSequence, typename Endpoint>+class reactive_socket_sendto_op_base : public reactor_op+{+public:+ reactive_socket_sendto_op_base(const asio::error_code& success_ec,+ socket_type socket, const ConstBufferSequence& buffers,+ const Endpoint& endpoint, socket_base::message_flags flags,+ func_type complete_func)+ : reactor_op(success_ec,+ &reactive_socket_sendto_op_base::do_perform, complete_func),+ socket_(socket),+ buffers_(buffers),+ destination_(endpoint),+ flags_(flags)+ {+ }++ static status do_perform(reactor_op* base)+ {+ reactive_socket_sendto_op_base* o(+ static_cast<reactive_socket_sendto_op_base*>(base));++ typedef buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence> bufs_type;++ status result;+ if (bufs_type::is_single_buffer)+ {+ result = socket_ops::non_blocking_sendto1(o->socket_,+ bufs_type::first(o->buffers_).data(),+ bufs_type::first(o->buffers_).size(), o->flags_,+ o->destination_.data(), o->destination_.size(),+ o->ec_, o->bytes_transferred_) ? done : not_done;+ }+ else+ {+ bufs_type bufs(o->buffers_);+ result = socket_ops::non_blocking_sendto(o->socket_,+ bufs.buffers(), bufs.count(), o->flags_,+ o->destination_.data(), o->destination_.size(),+ o->ec_, o->bytes_transferred_) ? done : not_done;+ }++ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_sendto",+ o->ec_, o->bytes_transferred_));++ return result;+ }++private:+ socket_type socket_;+ ConstBufferSequence buffers_;+ Endpoint destination_;+ socket_base::message_flags flags_;+};++template <typename ConstBufferSequence, typename Endpoint,+ typename Handler, typename IoExecutor>+class reactive_socket_sendto_op :+ public reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>+{+public:+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op);++ reactive_socket_sendto_op(const asio::error_code& success_ec,+ socket_type socket, const ConstBufferSequence& buffers,+ const Endpoint& endpoint, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ : reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>(+ success_ec, socket, buffers, endpoint, flags,+ &reactive_socket_sendto_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_service.hpp view
@@ -0,0 +1,528 @@+//+// detail/reactive_socket_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_SOCKET_SERVICE_HPP+#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_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_IOCP)++#include "asio/buffer.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/socket_base.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/reactive_null_buffers_op.hpp"+#include "asio/detail/reactive_socket_accept_op.hpp"+#include "asio/detail/reactive_socket_connect_op.hpp"+#include "asio/detail/reactive_socket_recvfrom_op.hpp"+#include "asio/detail/reactive_socket_sendto_op.hpp"+#include "asio/detail/reactive_socket_service_base.hpp"+#include "asio/detail/reactor.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_holder.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Protocol>+class reactive_socket_service :+ public execution_context_service_base<reactive_socket_service<Protocol> >,+ public reactive_socket_service_base+{+public:+ // The protocol type.+ typedef Protocol protocol_type;++ // The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ // The native type of a socket.+ typedef socket_type native_handle_type;++ // The implementation type of the socket.+ struct implementation_type :+ reactive_socket_service_base::base_implementation_type+ {+ // Default constructor.+ implementation_type()+ : protocol_(endpoint_type().protocol())+ {+ }++ // The protocol associated with the socket.+ protocol_type protocol_;+ };++ // Constructor.+ reactive_socket_service(execution_context& context)+ : execution_context_service_base<+ reactive_socket_service<Protocol> >(context),+ reactive_socket_service_base(context)+ {+ }++ // Destroy all user-defined handler objects owned by the service.+ void shutdown()+ {+ this->base_shutdown();+ }++ // Move-construct a new socket implementation.+ void move_construct(implementation_type& impl,+ implementation_type& other_impl) ASIO_NOEXCEPT+ {+ this->base_move_construct(impl, other_impl);++ impl.protocol_ = other_impl.protocol_;+ other_impl.protocol_ = endpoint_type().protocol();+ }++ // Move-assign from another socket implementation.+ void move_assign(implementation_type& impl,+ reactive_socket_service_base& other_service,+ implementation_type& other_impl)+ {+ this->base_move_assign(impl, other_service, other_impl);++ impl.protocol_ = other_impl.protocol_;+ other_impl.protocol_ = endpoint_type().protocol();+ }++ // Move-construct a new socket implementation from another protocol type.+ template <typename Protocol1>+ void converting_move_construct(implementation_type& impl,+ reactive_socket_service<Protocol1>&,+ typename reactive_socket_service<+ Protocol1>::implementation_type& other_impl)+ {+ this->base_move_construct(impl, other_impl);++ impl.protocol_ = protocol_type(other_impl.protocol_);+ other_impl.protocol_ = typename Protocol1::endpoint().protocol();+ }++ // Open a new socket implementation.+ asio::error_code open(implementation_type& impl,+ const protocol_type& protocol, asio::error_code& ec)+ {+ if (!do_open(impl, protocol.family(),+ protocol.type(), protocol.protocol(), ec))+ impl.protocol_ = protocol;+ return ec;+ }++ // Assign a native socket to a socket implementation.+ asio::error_code assign(implementation_type& impl,+ const protocol_type& protocol, const native_handle_type& native_socket,+ asio::error_code& ec)+ {+ if (!do_assign(impl, protocol.type(), native_socket, ec))+ impl.protocol_ = protocol;+ return ec;+ }++ // Get the native socket representation.+ native_handle_type native_handle(implementation_type& impl)+ {+ return impl.socket_;+ }++ // Bind the socket to the specified local endpoint.+ asio::error_code bind(implementation_type& impl,+ const endpoint_type& endpoint, asio::error_code& ec)+ {+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);+ return ec;+ }++ // Set a socket option.+ template <typename Option>+ asio::error_code set_option(implementation_type& impl,+ const Option& option, asio::error_code& ec)+ {+ socket_ops::setsockopt(impl.socket_, impl.state_,+ option.level(impl.protocol_), option.name(impl.protocol_),+ option.data(impl.protocol_), option.size(impl.protocol_), ec);+ return ec;+ }++ // Set a socket option.+ template <typename Option>+ asio::error_code get_option(const implementation_type& impl,+ Option& option, asio::error_code& ec) const+ {+ std::size_t size = option.size(impl.protocol_);+ socket_ops::getsockopt(impl.socket_, impl.state_,+ option.level(impl.protocol_), option.name(impl.protocol_),+ option.data(impl.protocol_), &size, ec);+ if (!ec)+ option.resize(impl.protocol_, size);+ return ec;+ }++ // Get the local endpoint.+ endpoint_type local_endpoint(const implementation_type& impl,+ asio::error_code& ec) const+ {+ endpoint_type endpoint;+ std::size_t addr_len = endpoint.capacity();+ if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))+ return endpoint_type();+ endpoint.resize(addr_len);+ return endpoint;+ }++ // Get the remote endpoint.+ endpoint_type remote_endpoint(const implementation_type& impl,+ asio::error_code& ec) const+ {+ endpoint_type endpoint;+ std::size_t addr_len = endpoint.capacity();+ if (socket_ops::getpeername(impl.socket_,+ endpoint.data(), &addr_len, false, ec))+ return endpoint_type();+ endpoint.resize(addr_len);+ return endpoint;+ }++ // Disable sends or receives on the socket.+ asio::error_code shutdown(base_implementation_type& impl,+ socket_base::shutdown_type what, asio::error_code& ec)+ {+ socket_ops::shutdown(impl.socket_, what, ec);+ return ec;+ }++ // Send a datagram to the specified endpoint. Returns the number of bytes+ // sent.+ template <typename ConstBufferSequence>+ size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,+ const endpoint_type& destination, socket_base::message_flags flags,+ asio::error_code& ec)+ {+ typedef buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence> bufs_type;++ if (bufs_type::is_single_buffer)+ {+ return socket_ops::sync_sendto1(impl.socket_, impl.state_,+ bufs_type::first(buffers).data(),+ bufs_type::first(buffers).size(), flags,+ destination.data(), destination.size(), ec);+ }+ else+ {+ bufs_type bufs(buffers);+ return socket_ops::sync_sendto(impl.socket_, impl.state_,+ bufs.buffers(), bufs.count(), flags,+ destination.data(), destination.size(), ec);+ }+ }++ // Wait until data can be sent without blocking.+ size_t send_to(implementation_type& impl, const null_buffers&,+ const endpoint_type&, socket_base::message_flags,+ asio::error_code& ec)+ {+ // Wait for socket to become ready.+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);++ return 0;+ }++ // Start an asynchronous send. The data being sent must be valid for the+ // lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_send_to(implementation_type& impl,+ const ConstBufferSequence& buffers,+ const endpoint_type& destination, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_socket_sendto_op<ConstBufferSequence,+ endpoint_type, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, impl.socket_,+ buffers, destination, flags, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_send_to"));++ start_op(impl, reactor::write_op, p.p, is_continuation, true, false);+ p.v = p.p = 0;+ }++ // Start an asynchronous wait until data can be sent without blocking.+ template <typename Handler, typename IoExecutor>+ void async_send_to(implementation_type& impl, const null_buffers&,+ const endpoint_type&, socket_base::message_flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_send_to(null_buffers)"));++ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);+ p.v = p.p = 0;+ }++ // Receive a datagram with the endpoint of the sender. Returns the number of+ // bytes received.+ template <typename MutableBufferSequence>+ size_t receive_from(implementation_type& impl,+ const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint, socket_base::message_flags flags,+ asio::error_code& ec)+ {+ typedef buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs_type;++ std::size_t addr_len = sender_endpoint.capacity();+ std::size_t bytes_recvd;+ if (bufs_type::is_single_buffer)+ {+ bytes_recvd = socket_ops::sync_recvfrom1(impl.socket_,+ impl.state_, bufs_type::first(buffers).data(),+ bufs_type::first(buffers).size(), flags,+ sender_endpoint.data(), &addr_len, ec);+ }+ else+ {+ bufs_type bufs(buffers);+ bytes_recvd = socket_ops::sync_recvfrom(+ impl.socket_, impl.state_, bufs.buffers(), bufs.count(),+ flags, sender_endpoint.data(), &addr_len, ec);+ }++ if (!ec)+ sender_endpoint.resize(addr_len);++ return bytes_recvd;+ }++ // Wait until data can be received without blocking.+ size_t receive_from(implementation_type& impl, const null_buffers&,+ endpoint_type& sender_endpoint, socket_base::message_flags,+ asio::error_code& ec)+ {+ // Wait for socket to become ready.+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);++ // Reset endpoint since it can be given no sensible value at this time.+ sender_endpoint = endpoint_type();++ return 0;+ }++ // Start an asynchronous receive. The buffer for the data being received and+ // the sender_endpoint object must both be valid for the lifetime of the+ // asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_receive_from(implementation_type& impl,+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,+ socket_base::message_flags flags, Handler& handler,+ const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_socket_recvfrom_op<MutableBufferSequence,+ endpoint_type, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ int protocol = impl.protocol_.type();+ p.p = new (p.v) op(success_ec_, impl.socket_, protocol,+ buffers, sender_endpoint, flags, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_receive_from"));++ start_op(impl,+ (flags & socket_base::message_out_of_band)+ ? reactor::except_op : reactor::read_op,+ p.p, is_continuation, true, false);+ p.v = p.p = 0;+ }++ // Wait until data can be received without blocking.+ template <typename Handler, typename IoExecutor>+ void async_receive_from(implementation_type& impl, const null_buffers&,+ endpoint_type& sender_endpoint, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_receive_from(null_buffers)"));++ // Reset endpoint since it can be given no sensible value at this time.+ sender_endpoint = endpoint_type();++ start_op(impl,+ (flags & socket_base::message_out_of_band)+ ? reactor::except_op : reactor::read_op,+ p.p, is_continuation, false, false);+ p.v = p.p = 0;+ }++ // Accept a new connection.+ template <typename Socket>+ asio::error_code accept(implementation_type& impl,+ Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec)+ {+ // We cannot accept a socket that is already open.+ if (peer.is_open())+ {+ ec = asio::error::already_open;+ return ec;+ }++ std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;+ socket_holder new_socket(socket_ops::sync_accept(impl.socket_,+ impl.state_, peer_endpoint ? peer_endpoint->data() : 0,+ peer_endpoint ? &addr_len : 0, ec));++ // On success, assign new connection to peer socket object.+ if (new_socket.get() != invalid_socket)+ {+ if (peer_endpoint)+ peer_endpoint->resize(addr_len);+ peer.assign(impl.protocol_, new_socket.get(), ec);+ if (!ec)+ new_socket.release();+ }++ return ec;+ }++ // Start an asynchronous accept. The peer and peer_endpoint objects must be+ // valid until the accept's handler is invoked.+ template <typename Socket, typename Handler, typename IoExecutor>+ void async_accept(implementation_type& impl, Socket& peer,+ endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_socket_accept_op<Socket, Protocol, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_,+ peer, impl.protocol_, peer_endpoint, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_accept"));++ start_accept_op(impl, p.p, is_continuation, peer.is_open());+ p.v = p.p = 0;+ }++#if defined(ASIO_HAS_MOVE)+ // Start an asynchronous accept. The peer_endpoint object must be valid until+ // the accept's handler is invoked.+ template <typename PeerIoExecutor, typename Handler, typename IoExecutor>+ void async_move_accept(implementation_type& impl,+ const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_socket_move_accept_op<Protocol,+ PeerIoExecutor, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_,+ impl.state_, impl.protocol_, peer_endpoint, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_accept"));++ start_accept_op(impl, p.p, is_continuation, false);+ p.v = p.p = 0;+ }+#endif // defined(ASIO_HAS_MOVE)++ // Connect the socket to the specified endpoint.+ asio::error_code connect(implementation_type& impl,+ const endpoint_type& peer_endpoint, asio::error_code& ec)+ {+ socket_ops::sync_connect(impl.socket_,+ peer_endpoint.data(), peer_endpoint.size(), ec);+ return ec;+ }++ // Start an asynchronous connect.+ template <typename Handler, typename IoExecutor>+ void async_connect(implementation_type& impl,+ const endpoint_type& peer_endpoint,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_socket_connect_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, impl.socket_, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_connect"));++ start_connect_op(impl, p.p, is_continuation,+ peer_endpoint.data(), peer_endpoint.size());+ p.v = p.p = 0;+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_socket_service_base.hpp view
@@ -0,0 +1,541 @@+//+// detail/reactive_socket_service_base.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_SOCKET_SERVICE_BASE_HPP+#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_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_IOCP) \+ && !defined(ASIO_WINDOWS_RUNTIME)++#include "asio/buffer.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/socket_base.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactive_null_buffers_op.hpp"+#include "asio/detail/reactive_socket_recv_op.hpp"+#include "asio/detail/reactive_socket_recvmsg_op.hpp"+#include "asio/detail/reactive_socket_send_op.hpp"+#include "asio/detail/reactive_wait_op.hpp"+#include "asio/detail/reactor.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_holder.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class reactive_socket_service_base+{+public:+ // The native type of a socket.+ typedef socket_type native_handle_type;++ // The implementation type of the socket.+ struct base_implementation_type+ {+ // The native socket representation.+ socket_type socket_;++ // The current state of the socket.+ socket_ops::state_type state_;++ // Per-descriptor data used by the reactor.+ reactor::per_descriptor_data reactor_data_;+ };++ // Constructor.+ ASIO_DECL reactive_socket_service_base(execution_context& context);++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void base_shutdown();++ // Construct a new socket implementation.+ ASIO_DECL void construct(base_implementation_type& impl);++ // Move-construct a new socket implementation.+ ASIO_DECL void base_move_construct(base_implementation_type& impl,+ base_implementation_type& other_impl) ASIO_NOEXCEPT;++ // Move-assign from another socket implementation.+ ASIO_DECL void base_move_assign(base_implementation_type& impl,+ reactive_socket_service_base& other_service,+ base_implementation_type& other_impl);++ // Destroy a socket implementation.+ ASIO_DECL void destroy(base_implementation_type& impl);++ // Determine whether the socket is open.+ bool is_open(const base_implementation_type& impl) const+ {+ return impl.socket_ != invalid_socket;+ }++ // Destroy a socket implementation.+ ASIO_DECL asio::error_code close(+ base_implementation_type& impl, asio::error_code& ec);++ // Release ownership of the socket.+ ASIO_DECL socket_type release(+ base_implementation_type& impl, asio::error_code& ec);++ // Get the native socket representation.+ native_handle_type native_handle(base_implementation_type& impl)+ {+ return impl.socket_;+ }++ // Cancel all operations associated with the socket.+ ASIO_DECL asio::error_code cancel(+ base_implementation_type& impl, asio::error_code& ec);++ // Determine whether the socket is at the out-of-band data mark.+ bool at_mark(const base_implementation_type& impl,+ asio::error_code& ec) const+ {+ return socket_ops::sockatmark(impl.socket_, ec);+ }++ // Determine the number of bytes available for reading.+ std::size_t available(const base_implementation_type& impl,+ asio::error_code& ec) const+ {+ return socket_ops::available(impl.socket_, ec);+ }++ // Place the socket into the state where it will listen for new connections.+ asio::error_code listen(base_implementation_type& impl,+ int backlog, asio::error_code& ec)+ {+ socket_ops::listen(impl.socket_, backlog, ec);+ return ec;+ }++ // Perform an IO control command on the socket.+ template <typename IO_Control_Command>+ asio::error_code io_control(base_implementation_type& impl,+ IO_Control_Command& command, asio::error_code& ec)+ {+ socket_ops::ioctl(impl.socket_, impl.state_, command.name(),+ static_cast<ioctl_arg_type*>(command.data()), ec);+ return ec;+ }++ // Gets the non-blocking mode of the socket.+ bool non_blocking(const base_implementation_type& impl) const+ {+ return (impl.state_ & socket_ops::user_set_non_blocking) != 0;+ }++ // Sets the non-blocking mode of the socket.+ asio::error_code non_blocking(base_implementation_type& impl,+ bool mode, asio::error_code& ec)+ {+ socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);+ return ec;+ }++ // Gets the non-blocking mode of the native socket implementation.+ bool native_non_blocking(const base_implementation_type& impl) const+ {+ return (impl.state_ & socket_ops::internal_non_blocking) != 0;+ }++ // Sets the non-blocking mode of the native socket implementation.+ asio::error_code native_non_blocking(base_implementation_type& impl,+ bool mode, asio::error_code& ec)+ {+ socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);+ return ec;+ }++ // Wait for the socket to become ready to read, ready to write, or to have+ // pending error conditions.+ asio::error_code wait(base_implementation_type& impl,+ socket_base::wait_type w, asio::error_code& ec)+ {+ switch (w)+ {+ case socket_base::wait_read:+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);+ break;+ case socket_base::wait_write:+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);+ break;+ case socket_base::wait_error:+ socket_ops::poll_error(impl.socket_, impl.state_, -1, ec);+ break;+ default:+ ec = asio::error::invalid_argument;+ break;+ }++ return ec;+ }++ // Asynchronously wait for the socket to become ready to read, ready to+ // write, or to have pending error conditions.+ template <typename Handler, typename IoExecutor>+ void async_wait(base_implementation_type& impl,+ socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_wait_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_wait"));++ int op_type;+ switch (w)+ {+ case socket_base::wait_read:+ op_type = reactor::read_op;+ break;+ case socket_base::wait_write:+ op_type = reactor::write_op;+ break;+ case socket_base::wait_error:+ op_type = reactor::except_op;+ break;+ default:+ p.p->ec_ = asio::error::invalid_argument;+ reactor_.post_immediate_completion(p.p, is_continuation);+ p.v = p.p = 0;+ return;+ }++ start_op(impl, op_type, p.p, is_continuation, false, false);+ p.v = p.p = 0;+ }++ // Send the given data to the peer.+ template <typename ConstBufferSequence>+ size_t send(base_implementation_type& impl,+ const ConstBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ typedef buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence> bufs_type;++ if (bufs_type::is_single_buffer)+ {+ return socket_ops::sync_send1(impl.socket_,+ impl.state_, bufs_type::first(buffers).data(),+ bufs_type::first(buffers).size(), flags, ec);+ }+ else+ {+ bufs_type bufs(buffers);+ return socket_ops::sync_send(impl.socket_, impl.state_,+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);+ }+ }++ // Wait until data can be sent without blocking.+ size_t send(base_implementation_type& impl, const null_buffers&,+ socket_base::message_flags, asio::error_code& ec)+ {+ // Wait for socket to become ready.+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);++ return 0;+ }++ // Start an asynchronous send. The data being sent must be valid for the+ // lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_send(base_implementation_type& impl,+ const ConstBufferSequence& buffers, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_socket_send_op<+ ConstBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, impl.socket_,+ impl.state_, buffers, flags, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_send"));++ start_op(impl, reactor::write_op, p.p, is_continuation, true,+ ((impl.state_ & socket_ops::stream_oriented)+ && buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::all_empty(buffers)));+ p.v = p.p = 0;+ }++ // Start an asynchronous wait until data can be sent without blocking.+ template <typename Handler, typename IoExecutor>+ void async_send(base_implementation_type& impl, const null_buffers&,+ socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_send(null_buffers)"));++ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);+ p.v = p.p = 0;+ }++ // Receive some data from the peer. Returns the number of bytes received.+ template <typename MutableBufferSequence>+ size_t receive(base_implementation_type& impl,+ const MutableBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ typedef buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs_type;++ if (bufs_type::is_single_buffer)+ {+ return socket_ops::sync_recv1(impl.socket_,+ impl.state_, bufs_type::first(buffers).data(),+ bufs_type::first(buffers).size(), flags, ec);+ }+ else+ {+ bufs_type bufs(buffers);+ return socket_ops::sync_recv(impl.socket_, impl.state_,+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);+ }+ }++ // Wait until data can be received without blocking.+ size_t receive(base_implementation_type& impl, const null_buffers&,+ socket_base::message_flags, asio::error_code& ec)+ {+ // Wait for socket to become ready.+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);++ return 0;+ }++ // Start an asynchronous receive. The buffer for the data being received+ // must be valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_receive(base_implementation_type& impl,+ const MutableBufferSequence& buffers, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_socket_recv_op<+ MutableBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, impl.socket_,+ impl.state_, buffers, flags, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_receive"));++ start_op(impl,+ (flags & socket_base::message_out_of_band)+ ? reactor::except_op : reactor::read_op,+ p.p, is_continuation,+ (flags & socket_base::message_out_of_band) == 0,+ ((impl.state_ & socket_ops::stream_oriented)+ && buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::all_empty(buffers)));+ p.v = p.p = 0;+ }++ // Wait until data can be received without blocking.+ template <typename Handler, typename IoExecutor>+ void async_receive(base_implementation_type& impl,+ const null_buffers&, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_receive(null_buffers)"));++ start_op(impl,+ (flags & socket_base::message_out_of_band)+ ? reactor::except_op : reactor::read_op,+ p.p, is_continuation, false, false);+ p.v = p.p = 0;+ }++ // Receive some data with associated flags. Returns the number of bytes+ // received.+ template <typename MutableBufferSequence>+ size_t receive_with_flags(base_implementation_type& impl,+ const MutableBufferSequence& buffers,+ socket_base::message_flags in_flags,+ socket_base::message_flags& out_flags, asio::error_code& ec)+ {+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs(buffers);++ return socket_ops::sync_recvmsg(impl.socket_, impl.state_,+ bufs.buffers(), bufs.count(), in_flags, out_flags, ec);+ }++ // Wait until data can be received without blocking.+ size_t receive_with_flags(base_implementation_type& impl,+ const null_buffers&, socket_base::message_flags,+ socket_base::message_flags& out_flags, asio::error_code& ec)+ {+ // Wait for socket to become ready.+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);++ // Clear out_flags, since we cannot give it any other sensible value when+ // performing a null_buffers operation.+ out_flags = 0;++ return 0;+ }++ // Start an asynchronous receive. The buffer for the data being received+ // must be valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_receive_with_flags(base_implementation_type& impl,+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,+ socket_base::message_flags& out_flags, Handler& handler,+ const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_socket_recvmsg_op<+ MutableBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, impl.socket_,+ buffers, in_flags, out_flags, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_receive_with_flags"));++ start_op(impl,+ (in_flags & socket_base::message_out_of_band)+ ? reactor::except_op : reactor::read_op,+ p.p, is_continuation,+ (in_flags & socket_base::message_out_of_band) == 0, false);+ p.v = p.p = 0;+ }++ // Wait until data can be received without blocking.+ template <typename Handler, typename IoExecutor>+ void async_receive_with_flags(base_implementation_type& impl,+ const null_buffers&, socket_base::message_flags in_flags,+ socket_base::message_flags& out_flags, Handler& handler,+ const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(success_ec_, handler, io_ex);++ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",+ &impl, impl.socket_, "async_receive_with_flags(null_buffers)"));++ // Clear out_flags, since we cannot give it any other sensible value when+ // performing a null_buffers operation.+ out_flags = 0;++ start_op(impl,+ (in_flags & socket_base::message_out_of_band)+ ? reactor::except_op : reactor::read_op,+ p.p, is_continuation, false, false);+ p.v = p.p = 0;+ }++protected:+ // Open a new socket implementation.+ ASIO_DECL asio::error_code do_open(+ base_implementation_type& impl, int af,+ int type, int protocol, asio::error_code& ec);++ // Assign a native socket to a socket implementation.+ ASIO_DECL asio::error_code do_assign(+ base_implementation_type& impl, int type,+ const native_handle_type& native_socket, asio::error_code& ec);++ // Start the asynchronous read or write operation.+ ASIO_DECL void start_op(base_implementation_type& impl, int op_type,+ reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);++ // Start the asynchronous accept operation.+ ASIO_DECL void start_accept_op(base_implementation_type& impl,+ reactor_op* op, bool is_continuation, bool peer_is_open);++ // Start the asynchronous connect operation.+ ASIO_DECL void start_connect_op(base_implementation_type& impl,+ reactor_op* op, bool is_continuation,+ const socket_addr_type* addr, size_t addrlen);++ // The selector that performs event demultiplexing for the service.+ reactor& reactor_;++ // Cached success value to avoid accessing category singleton.+ const asio::error_code success_ec_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/reactive_socket_service_base.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // !defined(ASIO_HAS_IOCP)+ // && !defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactive_wait_op.hpp view
@@ -0,0 +1,98 @@+//+// detail/reactive_wait_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTIVE_WAIT_OP_HPP+#define ASIO_DETAIL_REACTIVE_WAIT_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/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename IoExecutor>+class reactive_wait_op : public reactor_op+{+public:+ ASIO_DEFINE_HANDLER_PTR(reactive_wait_op);++ reactive_wait_op(const asio::error_code& success_ec,+ Handler& handler, const IoExecutor& io_ex)+ : reactor_op(success_ec, &reactive_wait_op::do_perform,+ &reactive_wait_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static status do_perform(reactor_op*)+ {+ return done;+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ reactive_wait_op* o(static_cast<reactive_wait_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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::binder1<Handler, asio::error_code>+ handler(o->handler_, o->ec_);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_REACTIVE_WAIT_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactor.hpp view
@@ -0,0 +1,32 @@+//+// detail/reactor.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTOR_HPP+#define ASIO_DETAIL_REACTOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/reactor_fwd.hpp"++#if defined(ASIO_HAS_EPOLL)+# include "asio/detail/epoll_reactor.hpp"+#elif defined(ASIO_HAS_KQUEUE)+# include "asio/detail/kqueue_reactor.hpp"+#elif defined(ASIO_HAS_DEV_POLL)+# include "asio/detail/dev_poll_reactor.hpp"+#elif defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME)+# include "asio/detail/null_reactor.hpp"+#else+# include "asio/detail/select_reactor.hpp"+#endif++#endif // ASIO_DETAIL_REACTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactor_fwd.hpp view
@@ -0,0 +1,40 @@+//+// detail/reactor_fwd.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTOR_FWD_HPP+#define ASIO_DETAIL_REACTOR_FWD_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++namespace asio {+namespace detail {++#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME)+typedef class null_reactor reactor;+#elif defined(ASIO_HAS_IOCP)+typedef class select_reactor reactor;+#elif defined(ASIO_HAS_EPOLL)+typedef class epoll_reactor reactor;+#elif defined(ASIO_HAS_KQUEUE)+typedef class kqueue_reactor reactor;+#elif defined(ASIO_HAS_DEV_POLL)+typedef class dev_poll_reactor reactor;+#else+typedef class select_reactor reactor;+#endif++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_REACTOR_FWD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactor_op.hpp view
@@ -0,0 +1,67 @@+//+// detail/reactor_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTOR_OP_HPP+#define ASIO_DETAIL_REACTOR_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/operation.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class reactor_op+ : public operation+{+public:+ // The error code to be passed to the completion handler.+ asio::error_code ec_;++ // The number of bytes transferred, to be passed to the completion handler.+ std::size_t bytes_transferred_;++ // Status returned by perform function. May be used to decide whether it is+ // worth performing more operations on the descriptor immediately.+ enum status { not_done, done, done_and_exhausted };++ // Perform the operation. Returns true if it is finished.+ status perform()+ {+ return perform_func_(this);+ }++protected:+ typedef status (*perform_func_type)(reactor_op*);++ reactor_op(const asio::error_code& success_ec,+ perform_func_type perform_func, func_type complete_func)+ : operation(complete_func),+ ec_(success_ec),+ bytes_transferred_(0),+ perform_func_(perform_func)+ {+ }++private:+ perform_func_type perform_func_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_REACTOR_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/reactor_op_queue.hpp view
@@ -0,0 +1,168 @@+//+// detail/reactor_op_queue.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REACTOR_OP_QUEUE_HPP+#define ASIO_DETAIL_REACTOR_OP_QUEUE_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/hash_map.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Descriptor>+class reactor_op_queue+ : private noncopyable+{+public:+ typedef Descriptor key_type;++ struct mapped_type : op_queue<reactor_op>+ {+ mapped_type() {}+ mapped_type(const mapped_type&) {}+ void operator=(const mapped_type&) {}+ };++ typedef typename hash_map<key_type, mapped_type>::value_type value_type;+ typedef typename hash_map<key_type, mapped_type>::iterator iterator;++ // Constructor.+ reactor_op_queue()+ : operations_()+ {+ }++ // Obtain iterators to all registered descriptors.+ iterator begin() { return operations_.begin(); }+ iterator end() { return operations_.end(); }++ // Add a new operation to the queue. Returns true if this is the only+ // operation for the given descriptor, in which case the reactor's event+ // demultiplexing function call may need to be interrupted and restarted.+ bool enqueue_operation(Descriptor descriptor, reactor_op* op)+ {+ std::pair<iterator, bool> entry =+ operations_.insert(value_type(descriptor, mapped_type()));+ entry.first->second.push(op);+ return entry.second;+ }++ // Cancel all operations associated with the descriptor identified by the+ // supplied iterator. Any operations pending for the descriptor will be+ // cancelled. Returns true if any operations were cancelled, in which case+ // the reactor's event demultiplexing function may need to be interrupted and+ // restarted.+ bool cancel_operations(iterator i, op_queue<operation>& ops,+ const asio::error_code& ec =+ asio::error::operation_aborted)+ {+ if (i != operations_.end())+ {+ while (reactor_op* op = i->second.front())+ {+ op->ec_ = ec;+ i->second.pop();+ ops.push(op);+ }+ operations_.erase(i);+ return true;+ }++ return false;+ }++ // Cancel all operations associated with the descriptor. Any operations+ // pending for the descriptor will be cancelled. Returns true if any+ // operations were cancelled, in which case the reactor's event+ // demultiplexing function may need to be interrupted and restarted.+ bool cancel_operations(Descriptor descriptor, op_queue<operation>& ops,+ const asio::error_code& ec =+ asio::error::operation_aborted)+ {+ return this->cancel_operations(operations_.find(descriptor), ops, ec);+ }++ // Whether there are no operations in the queue.+ bool empty() const+ {+ return operations_.empty();+ }++ // Determine whether there are any operations associated with the descriptor.+ bool has_operation(Descriptor descriptor) const+ {+ return operations_.find(descriptor) != operations_.end();+ }++ // Perform the operations corresponding to the descriptor identified by the+ // supplied iterator. Returns true if there are still unfinished operations+ // queued for the descriptor.+ bool perform_operations(iterator i, op_queue<operation>& ops)+ {+ if (i != operations_.end())+ {+ while (reactor_op* op = i->second.front())+ {+ if (op->perform())+ {+ i->second.pop();+ ops.push(op);+ }+ else+ {+ return true;+ }+ }+ operations_.erase(i);+ }+ return false;+ }++ // Perform the operations corresponding to the descriptor. Returns true if+ // there are still unfinished operations queued for the descriptor.+ bool perform_operations(Descriptor descriptor, op_queue<operation>& ops)+ {+ return this->perform_operations(operations_.find(descriptor), ops);+ }++ // Get all operations owned by the queue.+ void get_all_operations(op_queue<operation>& ops)+ {+ iterator i = operations_.begin();+ while (i != operations_.end())+ {+ iterator op_iter = i++;+ ops.push(op_iter->second);+ operations_.erase(op_iter);+ }+ }++private:+ // The operations that are currently executing asynchronously.+ hash_map<key_type, mapped_type> operations_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/recycling_allocator.hpp view
@@ -0,0 +1,106 @@+//+// detail/recycling_allocator.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_RECYCLING_ALLOCATOR_HPP+#define ASIO_DETAIL_RECYCLING_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/memory.hpp"+#include "asio/detail/thread_context.hpp"+#include "asio/detail/thread_info_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename T, typename Purpose = thread_info_base::default_tag>+class recycling_allocator+{+public:+ typedef T value_type;++ template <typename U>+ struct rebind+ {+ typedef recycling_allocator<U, Purpose> other;+ };++ recycling_allocator()+ {+ }++ template <typename U>+ recycling_allocator(const recycling_allocator<U, Purpose>&)+ {+ }++ T* allocate(std::size_t n)+ {+ typedef thread_context::thread_call_stack call_stack;+ void* p = thread_info_base::allocate(Purpose(),+ call_stack::top(), sizeof(T) * n);+ return static_cast<T*>(p);+ }++ void deallocate(T* p, std::size_t n)+ {+ typedef thread_context::thread_call_stack call_stack;+ thread_info_base::deallocate(Purpose(),+ call_stack::top(), p, sizeof(T) * n);+ }+};++template <typename Purpose>+class recycling_allocator<void, Purpose>+{+public:+ typedef void value_type;++ template <typename U>+ struct rebind+ {+ typedef recycling_allocator<U, Purpose> other;+ };++ recycling_allocator()+ {+ }++ template <typename U>+ recycling_allocator(const recycling_allocator<U, Purpose>&)+ {+ }+};++template <typename Allocator, typename Purpose>+struct get_recycling_allocator+{+ typedef Allocator type;+ static type get(const Allocator& a) { return a; }+};++template <typename T, typename Purpose>+struct get_recycling_allocator<std::allocator<T>, Purpose>+{+ typedef recycling_allocator<T, Purpose> type;+ static type get(const std::allocator<T>&) { return type(); }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/regex_fwd.hpp view
@@ -0,0 +1,35 @@+//+// detail/regex_fwd.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REGEX_FWD_HPP+#define ASIO_DETAIL_REGEX_FWD_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#if defined(ASIO_HAS_BOOST_REGEX)++#include <boost/regex_fwd.hpp>+#include <boost/regex/v4/match_flags.hpp>++namespace boost {++template <class BidiIterator>+struct sub_match;++template <class BidiIterator, class Allocator>+class match_results;++} // namespace boost++#endif // defined(ASIO_HAS_BOOST_REGEX)++#endif // ASIO_DETAIL_REGEX_FWD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/resolve_endpoint_op.hpp view
@@ -0,0 +1,140 @@+//+// detail/resolve_endpoint_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_RESOLVER_ENDPOINT_OP_HPP+#define ASIO_DETAIL_RESOLVER_ENDPOINT_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/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/resolve_op.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/error.hpp"+#include "asio/ip/basic_resolver_results.hpp"++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#else // defined(ASIO_HAS_IOCP)+# include "asio/detail/scheduler.hpp"+#endif // defined(ASIO_HAS_IOCP)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Protocol, typename Handler, typename IoExecutor>+class resolve_endpoint_op : public resolve_op+{+public:+ ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op);++ typedef typename Protocol::endpoint endpoint_type;+ typedef asio::ip::basic_resolver_results<Protocol> results_type;++#if defined(ASIO_HAS_IOCP)+ typedef class win_iocp_io_context scheduler_impl;+#else+ typedef class scheduler scheduler_impl;+#endif++ resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token,+ const endpoint_type& endpoint, scheduler_impl& sched,+ Handler& handler, const IoExecutor& io_ex)+ : resolve_op(&resolve_endpoint_op::do_complete),+ cancel_token_(cancel_token),+ endpoint_(endpoint),+ scheduler_(sched),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the operation object.+ resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ if (owner && owner != &o->scheduler_)+ {+ // The operation is being run on the worker io_context. Time to perform+ // the resolver operation.+ + // Perform the blocking endpoint resolution operation.+ char host_name[NI_MAXHOST];+ char service_name[NI_MAXSERV];+ socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(),+ o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV,+ o->endpoint_.protocol().type(), o->ec_);+ o->results_ = results_type::create(o->endpoint_, host_name, service_name);++ // Pass operation back to main io_context for completion.+ o->scheduler_.post_deferred_completion(o);+ p.v = p.p = 0;+ }+ else+ {+ // The operation has been returned to the main io_context. The completion+ // handler is ready to be delivered.++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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, results_type>+ handler(o->handler_, o->ec_, o->results_);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }+ }++private:+ socket_ops::weak_cancel_token_type cancel_token_;+ endpoint_type endpoint_;+ scheduler_impl& scheduler_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+ results_type results_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/resolve_op.hpp view
@@ -0,0 +1,45 @@+//+// detail/resolve_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_RESOLVE_OP_HPP+#define ASIO_DETAIL_RESOLVE_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/error.hpp"+#include "asio/detail/operation.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class resolve_op : public operation+{+public:+ // The error code to be passed to the completion handler.+ asio::error_code ec_;++protected:+ resolve_op(func_type complete_func)+ : operation(complete_func)+ {+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_RESOLVE_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/resolve_query_op.hpp view
@@ -0,0 +1,150 @@+//+// detail/resolve_query_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_RESOLVE_QUERY_OP_HPP+#define ASIO_DETAIL_RESOLVE_QUERY_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/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/resolve_op.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/error.hpp"+#include "asio/ip/basic_resolver_query.hpp"+#include "asio/ip/basic_resolver_results.hpp"++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#else // defined(ASIO_HAS_IOCP)+# include "asio/detail/scheduler.hpp"+#endif // defined(ASIO_HAS_IOCP)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Protocol, typename Handler, typename IoExecutor>+class resolve_query_op : public resolve_op+{+public:+ ASIO_DEFINE_HANDLER_PTR(resolve_query_op);++ typedef asio::ip::basic_resolver_query<Protocol> query_type;+ typedef asio::ip::basic_resolver_results<Protocol> results_type;++#if defined(ASIO_HAS_IOCP)+ typedef class win_iocp_io_context scheduler_impl;+#else+ typedef class scheduler scheduler_impl;+#endif++ resolve_query_op(socket_ops::weak_cancel_token_type cancel_token,+ const query_type& query, scheduler_impl& sched,+ Handler& handler, const IoExecutor& io_ex)+ : resolve_op(&resolve_query_op::do_complete),+ cancel_token_(cancel_token),+ query_(query),+ scheduler_(sched),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex),+ addrinfo_(0)+ {+ }++ ~resolve_query_op()+ {+ if (addrinfo_)+ socket_ops::freeaddrinfo(addrinfo_);+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the operation object.+ resolve_query_op* o(static_cast<resolve_query_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ if (owner && owner != &o->scheduler_)+ {+ // The operation is being run on the worker io_context. Time to perform+ // the resolver operation.+ + // Perform the blocking host resolution operation.+ socket_ops::background_getaddrinfo(o->cancel_token_,+ o->query_.host_name().c_str(), o->query_.service_name().c_str(),+ o->query_.hints(), &o->addrinfo_, o->ec_);++ // Pass operation back to main io_context for completion.+ o->scheduler_.post_deferred_completion(o);+ p.v = p.p = 0;+ }+ else+ {+ // The operation has been returned to the main io_context. The completion+ // handler is ready to be delivered.++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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, results_type>+ handler(o->handler_, o->ec_, results_type());+ p.h = asio::detail::addressof(handler.handler_);+ if (o->addrinfo_)+ {+ handler.arg2_ = results_type::create(o->addrinfo_,+ o->query_.host_name(), o->query_.service_name());+ }+ p.reset();++ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }+ }++private:+ socket_ops::weak_cancel_token_type cancel_token_;+ query_type query_;+ scheduler_impl& scheduler_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+ asio::detail::addrinfo_type* addrinfo_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_RESOLVE_QUERY_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/resolver_service.hpp view
@@ -0,0 +1,145 @@+//+// detail/resolver_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_RESOLVER_SERVICE_HPP+#define ASIO_DETAIL_RESOLVER_SERVICE_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_WINDOWS_RUNTIME)++#include "asio/ip/basic_resolver_query.hpp"+#include "asio/ip/basic_resolver_results.hpp"+#include "asio/detail/concurrency_hint.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/resolve_endpoint_op.hpp"+#include "asio/detail/resolve_query_op.hpp"+#include "asio/detail/resolver_service_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Protocol>+class resolver_service :+ public execution_context_service_base<resolver_service<Protocol> >,+ public resolver_service_base+{+public:+ // The implementation type of the resolver. A cancellation token is used to+ // indicate to the background thread that the operation has been cancelled.+ typedef socket_ops::shared_cancel_token_type implementation_type;++ // The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ // The query type.+ typedef asio::ip::basic_resolver_query<Protocol> query_type;++ // The results type.+ typedef asio::ip::basic_resolver_results<Protocol> results_type;++ // Constructor.+ resolver_service(execution_context& context)+ : execution_context_service_base<resolver_service<Protocol> >(context),+ resolver_service_base(context)+ {+ }++ // Destroy all user-defined handler objects owned by the service.+ void shutdown()+ {+ this->base_shutdown();+ }++ // Perform any fork-related housekeeping.+ void notify_fork(execution_context::fork_event fork_ev)+ {+ this->base_notify_fork(fork_ev);+ }++ // Resolve a query to a list of entries.+ results_type resolve(implementation_type&, const query_type& query,+ asio::error_code& ec)+ {+ asio::detail::addrinfo_type* address_info = 0;++ socket_ops::getaddrinfo(query.host_name().c_str(),+ query.service_name().c_str(), query.hints(), &address_info, ec);+ auto_addrinfo auto_address_info(address_info);++ return ec ? results_type() : results_type::create(+ address_info, query.host_name(), query.service_name());+ }++ // Asynchronously resolve a query to a list of entries.+ template <typename Handler, typename IoExecutor>+ void async_resolve(implementation_type& impl, const query_type& query,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef resolve_query_op<Protocol, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl, query, scheduler_, handler, io_ex);++ ASIO_HANDLER_CREATION((scheduler_.context(),+ *p.p, "resolver", &impl, 0, "async_resolve"));++ start_resolve_op(p.p);+ p.v = p.p = 0;+ }++ // Resolve an endpoint to a list of entries.+ results_type resolve(implementation_type&,+ const endpoint_type& endpoint, asio::error_code& ec)+ {+ char host_name[NI_MAXHOST];+ char service_name[NI_MAXSERV];+ socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(),+ host_name, NI_MAXHOST, service_name, NI_MAXSERV,+ endpoint.protocol().type(), ec);++ return ec ? results_type() : results_type::create(+ endpoint, host_name, service_name);+ }++ // Asynchronously resolve an endpoint to a list of entries.+ template <typename Handler, typename IoExecutor>+ void async_resolve(implementation_type& impl, const endpoint_type& endpoint,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef resolve_endpoint_op<Protocol, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl, endpoint, scheduler_, handler, io_ex);++ ASIO_HANDLER_CREATION((scheduler_.context(),+ *p.p, "resolver", &impl, 0, "async_resolve"));++ start_resolve_op(p.p);+ p.v = p.p = 0;+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/resolver_service_base.hpp view
@@ -0,0 +1,143 @@+//+// detail/resolver_service_base.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_RESOLVER_SERVICE_BASE_HPP+#define ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/resolve_op.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/scoped_ptr.hpp"+#include "asio/detail/thread.hpp"++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#else // defined(ASIO_HAS_IOCP)+# include "asio/detail/scheduler.hpp"+#endif // defined(ASIO_HAS_IOCP)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class resolver_service_base+{+public:+ // The implementation type of the resolver. A cancellation token is used to+ // indicate to the background thread that the operation has been cancelled.+ typedef socket_ops::shared_cancel_token_type implementation_type;++ // Constructor.+ ASIO_DECL resolver_service_base(execution_context& context);++ // Destructor.+ ASIO_DECL ~resolver_service_base();++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void base_shutdown();++ // Perform any fork-related housekeeping.+ ASIO_DECL void base_notify_fork(+ execution_context::fork_event fork_ev);++ // Construct a new resolver implementation.+ ASIO_DECL void construct(implementation_type& impl);++ // Destroy a resolver implementation.+ ASIO_DECL void destroy(implementation_type&);++ // Move-construct a new resolver implementation.+ ASIO_DECL void move_construct(implementation_type& impl,+ implementation_type& other_impl);++ // Move-assign from another resolver implementation.+ ASIO_DECL void move_assign(implementation_type& impl,+ resolver_service_base& other_service,+ implementation_type& other_impl);++ // Cancel pending asynchronous operations.+ ASIO_DECL void cancel(implementation_type& impl);++protected:+ // Helper function to start an asynchronous resolve operation.+ ASIO_DECL void start_resolve_op(resolve_op* op);++#if !defined(ASIO_WINDOWS_RUNTIME)+ // Helper class to perform exception-safe cleanup of addrinfo objects.+ class auto_addrinfo+ : private asio::detail::noncopyable+ {+ public:+ explicit auto_addrinfo(asio::detail::addrinfo_type* ai)+ : ai_(ai)+ {+ }++ ~auto_addrinfo()+ {+ if (ai_)+ socket_ops::freeaddrinfo(ai_);+ }++ operator asio::detail::addrinfo_type*()+ {+ return ai_;+ }++ private:+ asio::detail::addrinfo_type* ai_;+ };+#endif // !defined(ASIO_WINDOWS_RUNTIME)++ // Helper class to run the work scheduler in a thread.+ class work_scheduler_runner;++ // Start the work scheduler if it's not already running.+ ASIO_DECL void start_work_thread();++ // The scheduler implementation used to post completions.+#if defined(ASIO_HAS_IOCP)+ typedef class win_iocp_io_context scheduler_impl;+#else+ typedef class scheduler scheduler_impl;+#endif+ scheduler_impl& scheduler_;++private:+ // Mutex to protect access to internal data.+ asio::detail::mutex mutex_;++ // Private scheduler used for performing asynchronous host resolution.+ asio::detail::scoped_ptr<scheduler_impl> work_scheduler_;++ // Thread used for running the work io_context's run loop.+ asio::detail::scoped_ptr<asio::detail::thread> work_thread_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/resolver_service_base.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/scheduler.hpp view
@@ -0,0 +1,232 @@+//+// detail/scheduler.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SCHEDULER_HPP+#define ASIO_DETAIL_SCHEDULER_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include "asio/error_code.hpp"+#include "asio/execution_context.hpp"+#include "asio/detail/atomic_count.hpp"+#include "asio/detail/conditionally_enabled_event.hpp"+#include "asio/detail/conditionally_enabled_mutex.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/reactor_fwd.hpp"+#include "asio/detail/scheduler_operation.hpp"+#include "asio/detail/thread.hpp"+#include "asio/detail/thread_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++struct scheduler_thread_info;++class scheduler+ : public execution_context_service_base<scheduler>,+ public thread_context+{+public:+ typedef scheduler_operation operation;++ // Constructor. Specifies the number of concurrent threads that are likely to+ // run the scheduler. If set to 1 certain optimisation are performed.+ ASIO_DECL scheduler(asio::execution_context& ctx,+ int concurrency_hint = 0, bool own_thread = true);++ // Destructor.+ ASIO_DECL ~scheduler();++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Initialise the task, if required.+ ASIO_DECL void init_task();++ // Run the event loop until interrupted or no more work.+ ASIO_DECL std::size_t run(asio::error_code& ec);++ // Run until interrupted or one operation is performed.+ ASIO_DECL std::size_t run_one(asio::error_code& ec);++ // Run until timeout, interrupted, or one operation is performed.+ ASIO_DECL std::size_t wait_one(+ long usec, asio::error_code& ec);++ // Poll for operations without blocking.+ ASIO_DECL std::size_t poll(asio::error_code& ec);++ // Poll for one operation without blocking.+ ASIO_DECL std::size_t poll_one(asio::error_code& ec);++ // Interrupt the event processing loop.+ ASIO_DECL void stop();++ // Determine whether the scheduler is stopped.+ ASIO_DECL bool stopped() const;++ // Restart in preparation for a subsequent run invocation.+ ASIO_DECL void restart();++ // Notify that some work has started.+ void work_started()+ {+ ++outstanding_work_;+ }++ // Used to compensate for a forthcoming work_finished call. Must be called+ // from within a scheduler-owned thread.+ ASIO_DECL void compensating_work_started();++ // Notify that some work has finished.+ void work_finished()+ {+ if (--outstanding_work_ == 0)+ stop();+ }++ // Return whether a handler can be dispatched immediately.+ bool can_dispatch()+ {+ return thread_call_stack::contains(this) != 0;+ }++ /// Capture the current exception so it can be rethrown from a run function.+ ASIO_DECL void capture_current_exception();++ // Request invocation of the given operation and return immediately. Assumes+ // that work_started() has not yet been called for the operation.+ ASIO_DECL void post_immediate_completion(+ operation* op, bool is_continuation);++ // Request invocation of the given operations and return immediately. Assumes+ // that work_started() has not yet been called for the operations.+ ASIO_DECL void post_immediate_completions(std::size_t n,+ op_queue<operation>& ops, bool is_continuation);++ // Request invocation of the given operation and return immediately. Assumes+ // that work_started() was previously called for the operation.+ ASIO_DECL void post_deferred_completion(operation* op);++ // Request invocation of the given operations and return immediately. Assumes+ // that work_started() was previously called for each operation.+ ASIO_DECL void post_deferred_completions(op_queue<operation>& ops);++ // Enqueue the given operation following a failed attempt to dispatch the+ // operation for immediate invocation.+ ASIO_DECL void do_dispatch(operation* op);++ // Process unfinished operations as part of a shutdownoperation. Assumes that+ // work_started() was previously called for the operations.+ ASIO_DECL void abandon_operations(op_queue<operation>& ops);++ // Get the concurrency hint that was used to initialise the scheduler.+ int concurrency_hint() const+ {+ return concurrency_hint_;+ }++private:+ // The mutex type used by this scheduler.+ typedef conditionally_enabled_mutex mutex;++ // The event type used by this scheduler.+ typedef conditionally_enabled_event event;++ // Structure containing thread-specific data.+ typedef scheduler_thread_info thread_info;++ // Run at most one operation. May block.+ ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock,+ thread_info& this_thread, const asio::error_code& ec);++ // Run at most one operation with a timeout. May block.+ ASIO_DECL std::size_t do_wait_one(mutex::scoped_lock& lock,+ thread_info& this_thread, long usec, const asio::error_code& ec);++ // Poll for at most one operation.+ ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock,+ thread_info& this_thread, const asio::error_code& ec);++ // Stop the task and all idle threads.+ ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock);++ // Wake a single idle thread, or the task, and always unlock the mutex.+ ASIO_DECL void wake_one_thread_and_unlock(+ mutex::scoped_lock& lock);++ // Helper class to run the scheduler in its own thread.+ class thread_function;+ friend class thread_function;++ // Helper class to perform task-related operations on block exit.+ struct task_cleanup;+ friend struct task_cleanup;++ // Helper class to call work-related operations on block exit.+ struct work_cleanup;+ friend struct work_cleanup;++ // Whether to optimise for single-threaded use cases.+ const bool one_thread_;++ // Mutex to protect access to internal data.+ mutable mutex mutex_;++ // Event to wake up blocked threads.+ event wakeup_event_;++ // The task to be run by this service.+ reactor* task_;++ // Operation object to represent the position of the task in the queue.+ struct task_operation : operation+ {+ task_operation() : operation(0) {}+ } task_operation_;++ // Whether the task has been interrupted.+ bool task_interrupted_;++ // The count of unfinished work.+ atomic_count outstanding_work_;++ // The queue of handlers that are ready to be delivered.+ op_queue<operation> op_queue_;++ // Flag to indicate that the dispatcher has been stopped.+ bool stopped_;++ // Flag to indicate that the dispatcher has been shut down.+ bool shutdown_;++ // The concurrency hint used to initialise the scheduler.+ const int concurrency_hint_;++ // The thread that is running the scheduler.+ asio::detail::thread* thread_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/scheduler.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_SCHEDULER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/scheduler_operation.hpp view
@@ -0,0 +1,78 @@+//+// detail/scheduler_operation.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SCHEDULER_OPERATION_HPP+#define ASIO_DETAIL_SCHEDULER_OPERATION_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/error_code.hpp"+#include "asio/detail/handler_tracking.hpp"+#include "asio/detail/op_queue.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class scheduler;++// Base class for all operations. A function pointer is used instead of virtual+// functions to avoid the associated overhead.+class scheduler_operation ASIO_INHERIT_TRACKED_HANDLER+{+public:+ typedef scheduler_operation operation_type;++ void complete(void* owner, const asio::error_code& ec,+ std::size_t bytes_transferred)+ {+ func_(owner, this, ec, bytes_transferred);+ }++ void destroy()+ {+ func_(0, this, asio::error_code(), 0);+ }++protected:+ typedef void (*func_type)(void*,+ scheduler_operation*,+ const asio::error_code&, std::size_t);++ scheduler_operation(func_type func)+ : next_(0),+ func_(func),+ task_result_(0)+ {+ }++ // Prevents deletion through this type.+ ~scheduler_operation()+ {+ }++private:+ friend class op_queue_access;+ scheduler_operation* next_;+ func_type func_;+protected:+ friend class scheduler;+ unsigned int task_result_; // Passed into bytes transferred.+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_SCHEDULER_OPERATION_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/scheduler_thread_info.hpp view
@@ -0,0 +1,40 @@+//+// detail/scheduler_thread_info.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SCHEDULER_THREAD_INFO_HPP+#define ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/op_queue.hpp"+#include "asio/detail/thread_info_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class scheduler;+class scheduler_operation;++struct scheduler_thread_info : public thread_info_base+{+ op_queue<scheduler_operation> private_op_queue;+ long private_outstanding_work;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/scoped_lock.hpp view
@@ -0,0 +1,101 @@+//+// detail/scoped_lock.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SCOPED_LOCK_HPP+#define ASIO_DETAIL_SCOPED_LOCK_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Helper class to lock and unlock a mutex automatically.+template <typename Mutex>+class scoped_lock+ : private noncopyable+{+public:+ // Tag type used to distinguish constructors.+ enum adopt_lock_t { adopt_lock };++ // Constructor adopts a lock that is already held.+ scoped_lock(Mutex& m, adopt_lock_t)+ : mutex_(m),+ locked_(true)+ {+ }++ // Constructor acquires the lock.+ explicit scoped_lock(Mutex& m)+ : mutex_(m)+ {+ mutex_.lock();+ locked_ = true;+ }++ // Destructor releases the lock.+ ~scoped_lock()+ {+ if (locked_)+ mutex_.unlock();+ }++ // Explicitly acquire the lock.+ void lock()+ {+ if (!locked_)+ {+ mutex_.lock();+ locked_ = true;+ }+ }++ // Explicitly release the lock.+ void unlock()+ {+ if (locked_)+ {+ mutex_.unlock();+ locked_ = false;+ }+ }++ // Test whether the lock is held.+ bool locked() const+ {+ return locked_;+ }++ // Get the underlying mutex.+ Mutex& mutex()+ {+ return mutex_;+ }++private:+ // The underlying mutex.+ Mutex& mutex_;++ // Whether the mutex is currently locked or unlocked.+ bool locked_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_SCOPED_LOCK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/scoped_ptr.hpp view
@@ -0,0 +1,87 @@+//+// detail/scoped_ptr.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SCOPED_PTR_HPP+#define ASIO_DETAIL_SCOPED_PTR_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 {+namespace detail {++template <typename T>+class scoped_ptr+{+public:+ // Constructor.+ explicit scoped_ptr(T* p = 0)+ : p_(p)+ {+ }++ // Destructor.+ ~scoped_ptr()+ {+ delete p_;+ }++ // Access.+ T* get()+ {+ return p_;+ }++ // Access.+ T* operator->()+ {+ return p_;+ }++ // Dereference.+ T& operator*()+ {+ return *p_;+ }++ // Reset pointer.+ void reset(T* p = 0)+ {+ delete p_;+ p_ = p;+ }++ // Release ownership of the pointer.+ T* release()+ {+ T* tmp = p_;+ p_ = 0;+ return tmp;+ }++private:+ // Disallow copying and assignment.+ scoped_ptr(const scoped_ptr&);+ scoped_ptr& operator=(const scoped_ptr&);++ T* p_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_SCOPED_PTR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/select_interrupter.hpp view
@@ -0,0 +1,46 @@+//+// detail/select_interrupter.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SELECT_INTERRUPTER_HPP+#define ASIO_DETAIL_SELECT_INTERRUPTER_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_WINDOWS_RUNTIME)++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)+# include "asio/detail/socket_select_interrupter.hpp"+#elif defined(ASIO_HAS_EVENTFD)+# include "asio/detail/eventfd_select_interrupter.hpp"+#else+# include "asio/detail/pipe_select_interrupter.hpp"+#endif++namespace asio {+namespace detail {++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)+typedef socket_select_interrupter select_interrupter;+#elif defined(ASIO_HAS_EVENTFD)+typedef eventfd_select_interrupter select_interrupter;+#else+typedef pipe_select_interrupter select_interrupter;+#endif++} // namespace detail+} // namespace asio++#endif // !defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/select_reactor.hpp view
@@ -0,0 +1,238 @@+//+// detail/select_reactor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SELECT_REACTOR_HPP+#define ASIO_DETAIL_SELECT_REACTOR_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_IOCP) \+ || (!defined(ASIO_HAS_DEV_POLL) \+ && !defined(ASIO_HAS_EPOLL) \+ && !defined(ASIO_HAS_KQUEUE) \+ && !defined(ASIO_WINDOWS_RUNTIME))++#include <cstddef>+#include "asio/detail/fd_set_adapter.hpp"+#include "asio/detail/limits.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/reactor_op_queue.hpp"+#include "asio/detail/select_interrupter.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/timer_queue_base.hpp"+#include "asio/detail/timer_queue_set.hpp"+#include "asio/detail/wait_op.hpp"+#include "asio/execution_context.hpp"++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/thread.hpp"+#endif // defined(ASIO_HAS_IOCP)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class select_reactor+ : public execution_context_service_base<select_reactor>+{+public:+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ enum op_types { read_op = 0, write_op = 1, except_op = 2,+ max_select_ops = 3, connect_op = 3, max_ops = 4 };+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ enum op_types { read_op = 0, write_op = 1, except_op = 2,+ max_select_ops = 3, connect_op = 1, max_ops = 3 };+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++ // Per-descriptor data.+ struct per_descriptor_data+ {+ };++ // Constructor.+ ASIO_DECL select_reactor(asio::execution_context& ctx);++ // Destructor.+ ASIO_DECL ~select_reactor();++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Recreate internal descriptors following a fork.+ ASIO_DECL void notify_fork(+ asio::execution_context::fork_event fork_ev);++ // Initialise the task, but only if the reactor is not in its own thread.+ ASIO_DECL void init_task();++ // Register a socket with the reactor. Returns 0 on success, system error+ // code on failure.+ ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);++ // Register a descriptor with an associated single operation. Returns 0 on+ // success, system error code on failure.+ ASIO_DECL int register_internal_descriptor(+ int op_type, socket_type descriptor,+ per_descriptor_data& descriptor_data, reactor_op* op);++ // Post a reactor operation for immediate completion.+ void post_immediate_completion(reactor_op* op, bool is_continuation)+ {+ scheduler_.post_immediate_completion(op, is_continuation);+ }++ // Start a new operation. The reactor operation will be performed when the+ // given descriptor is flagged as ready, or an error has occurred.+ ASIO_DECL void start_op(int op_type, socket_type descriptor,+ per_descriptor_data&, reactor_op* op, bool is_continuation, bool);++ // Cancel all operations associated with the given descriptor. The+ // handlers associated with the descriptor will be invoked with the+ // operation_aborted error.+ ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);++ // Cancel any operations that are running against the descriptor and remove+ // its registration from the reactor. The reactor resources associated with+ // the descriptor must be released by calling cleanup_descriptor_data.+ ASIO_DECL void deregister_descriptor(socket_type descriptor,+ per_descriptor_data&, bool closing);++ // Remove the descriptor's registration from the reactor. The reactor+ // resources associated with the descriptor must be released by calling+ // cleanup_descriptor_data.+ ASIO_DECL void deregister_internal_descriptor(+ socket_type descriptor, per_descriptor_data&);++ // Perform any post-deregistration cleanup tasks associated with the+ // descriptor data.+ ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&);++ // Move descriptor registration from one descriptor_data object to another.+ ASIO_DECL void move_descriptor(socket_type descriptor,+ per_descriptor_data& target_descriptor_data,+ per_descriptor_data& source_descriptor_data);++ // Add a new timer queue to the reactor.+ template <typename Time_Traits>+ void add_timer_queue(timer_queue<Time_Traits>& queue);++ // Remove a timer queue from the reactor.+ template <typename Time_Traits>+ void remove_timer_queue(timer_queue<Time_Traits>& queue);++ // Schedule a new operation in the given timer queue to expire at the+ // specified absolute time.+ template <typename Time_Traits>+ void schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);++ // Cancel the timer operations associated with the given token. Returns the+ // number of operations that have been posted or dispatched.+ template <typename Time_Traits>+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());++ // Move the timer operations associated with the given timer.+ template <typename Time_Traits>+ void move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& target,+ typename timer_queue<Time_Traits>::per_timer_data& source);++ // Run select once until interrupted or events are ready to be dispatched.+ ASIO_DECL void run(long usec, op_queue<operation>& ops);++ // Interrupt the select loop.+ ASIO_DECL void interrupt();++private:+#if defined(ASIO_HAS_IOCP)+ // Run the select loop in the thread.+ ASIO_DECL void run_thread();+#endif // defined(ASIO_HAS_IOCP)++ // Helper function to add a new timer queue.+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);++ // Helper function to remove a timer queue.+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);++ // Get the timeout value for the select call.+ ASIO_DECL timeval* get_timeout(long usec, timeval& tv);++ // Cancel all operations associated with the given descriptor. This function+ // does not acquire the select_reactor's mutex.+ ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,+ const asio::error_code& ec);++ // The scheduler implementation used to post completions.+# if defined(ASIO_HAS_IOCP)+ typedef class win_iocp_io_context scheduler_type;+# else // defined(ASIO_HAS_IOCP)+ typedef class scheduler scheduler_type;+# endif // defined(ASIO_HAS_IOCP)+ scheduler_type& scheduler_;++ // Mutex to protect access to internal data.+ asio::detail::mutex mutex_;++ // The interrupter is used to break a blocking select call.+ select_interrupter interrupter_;++ // The queues of read, write and except operations.+ reactor_op_queue<socket_type> op_queue_[max_ops];++ // The file descriptor sets to be passed to the select system call.+ fd_set_adapter fd_sets_[max_select_ops];++ // The timer queues.+ timer_queue_set timer_queues_;++#if defined(ASIO_HAS_IOCP)+ // Helper class to run the reactor loop in a thread.+ class thread_function;+ friend class thread_function;++ // Does the reactor loop thread need to stop.+ bool stop_thread_;++ // The thread that is running the reactor loop.+ asio::detail::thread* thread_;+#endif // defined(ASIO_HAS_IOCP)++ // Whether the service has been shut down.+ bool shutdown_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/detail/impl/select_reactor.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/select_reactor.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_IOCP)+ // || (!defined(ASIO_HAS_DEV_POLL)+ // && !defined(ASIO_HAS_EPOLL)+ // && !defined(ASIO_HAS_KQUEUE)+ // && !defined(ASIO_WINDOWS_RUNTIME))++#endif // ASIO_DETAIL_SELECT_REACTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/service_registry.hpp view
@@ -0,0 +1,164 @@+//+// detail/service_registry.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SERVICE_REGISTRY_HPP+#define ASIO_DETAIL_SERVICE_REGISTRY_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <typeinfo>+#include "asio/detail/mutex.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++class io_context;++namespace detail {++template <typename T>+class typeid_wrapper {};++class service_registry+ : private noncopyable+{+public:+ // Constructor.+ ASIO_DECL service_registry(execution_context& owner);++ // Destructor.+ ASIO_DECL ~service_registry();++ // Shutdown all services.+ ASIO_DECL void shutdown_services();++ // Destroy all services.+ ASIO_DECL void destroy_services();++ // Notify all services of a fork event.+ ASIO_DECL void notify_fork(execution_context::fork_event fork_ev);++ // Get the service object corresponding to the specified service type. Will+ // create a new service object automatically if no such object already+ // exists. Ownership of the service object is not transferred to the caller.+ template <typename Service>+ Service& use_service();++ // Get the service object corresponding to the specified service type. Will+ // create a new service object automatically if no such object already+ // exists. Ownership of the service object is not transferred to the caller.+ // This overload is used for backwards compatibility with services that+ // inherit from io_context::service.+ template <typename Service>+ Service& use_service(io_context& owner);++ // Add a service object. Throws on error, in which case ownership of the+ // object is retained by the caller.+ template <typename Service>+ void add_service(Service* new_service);++ // Check whether a service object of the specified type already exists.+ template <typename Service>+ bool has_service() const;++private:+ // Initalise a service's key when the key_type typedef is not available.+ template <typename Service>+ static void init_key(execution_context::service::key& key, ...);++#if !defined(ASIO_NO_TYPEID)+ // Initalise a service's key when the key_type typedef is available.+ template <typename Service>+ static void init_key(execution_context::service::key& key,+ typename enable_if<+ is_base_of<typename Service::key_type, Service>::value>::type*);+#endif // !defined(ASIO_NO_TYPEID)++ // Initialise a service's key based on its id.+ ASIO_DECL static void init_key_from_id(+ execution_context::service::key& key,+ const execution_context::id& id);++#if !defined(ASIO_NO_TYPEID)+ // Initialise a service's key based on its id.+ template <typename Service>+ static void init_key_from_id(execution_context::service::key& key,+ const service_id<Service>& /*id*/);+#endif // !defined(ASIO_NO_TYPEID)++ // Check if a service matches the given id.+ ASIO_DECL static bool keys_match(+ const execution_context::service::key& key1,+ const execution_context::service::key& key2);++ // The type of a factory function used for creating a service instance.+ typedef execution_context::service*(*factory_type)(void*);++ // Factory function for creating a service instance.+ template <typename Service, typename Owner>+ static execution_context::service* create(void* owner);++ // Destroy a service instance.+ ASIO_DECL static void destroy(execution_context::service* service);++ // Helper class to manage service pointers.+ struct auto_service_ptr;+ friend struct auto_service_ptr;+ struct auto_service_ptr+ {+ execution_context::service* ptr_;+ ~auto_service_ptr() { destroy(ptr_); }+ };++ // Get the service object corresponding to the specified service key. Will+ // create a new service object automatically if no such object already+ // exists. Ownership of the service object is not transferred to the caller.+ ASIO_DECL execution_context::service* do_use_service(+ const execution_context::service::key& key,+ factory_type factory, void* owner);++ // Add a service object. Throws on error, in which case ownership of the+ // object is retained by the caller.+ ASIO_DECL void do_add_service(+ const execution_context::service::key& key,+ execution_context::service* new_service);++ // Check whether a service object with the specified key already exists.+ ASIO_DECL bool do_has_service(+ const execution_context::service::key& key) const;++ // Mutex to protect access to internal data.+ mutable asio::detail::mutex mutex_;++ // The owner of this service registry and the services it contains.+ execution_context& owner_;++ // The first service in the list of contained services.+ execution_context::service* first_service_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/detail/impl/service_registry.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/service_registry.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/signal_blocker.hpp view
@@ -0,0 +1,44 @@+//+// detail/signal_blocker.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SIGNAL_BLOCKER_HPP+#define ASIO_DETAIL_SIGNAL_BLOCKER_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_THREADS) || defined(ASIO_WINDOWS) \+ || defined(ASIO_WINDOWS_RUNTIME) \+ || defined(__CYGWIN__) || defined(__SYMBIAN32__)+# include "asio/detail/null_signal_blocker.hpp"+#elif defined(ASIO_HAS_PTHREADS)+# include "asio/detail/posix_signal_blocker.hpp"+#else+# error Only Windows and POSIX are supported!+#endif++namespace asio {+namespace detail {++#if !defined(ASIO_HAS_THREADS) || defined(ASIO_WINDOWS) \+ || defined(ASIO_WINDOWS_RUNTIME) \+ || defined(__CYGWIN__) || defined(__SYMBIAN32__)+typedef null_signal_blocker signal_blocker;+#elif defined(ASIO_HAS_PTHREADS)+typedef posix_signal_blocker signal_blocker;+#endif++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/signal_handler.hpp view
@@ -0,0 +1,90 @@+//+// detail/signal_handler.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SIGNAL_HANDLER_HPP+#define ASIO_DETAIL_SIGNAL_HANDLER_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/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/signal_op.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename IoExecutor>+class signal_handler : public signal_op+{+public:+ ASIO_DEFINE_HANDLER_PTR(signal_handler);++ signal_handler(Handler& h, const IoExecutor& io_ex)+ : signal_op(&signal_handler::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(h)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ signal_handler* h(static_cast<signal_handler*>(base));+ ptr p = { asio::detail::addressof(h->handler_), h, h };++ ASIO_HANDLER_COMPLETION((*h));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ h->work_));++ // 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, int>+ handler(h->handler_, h->ec_, h->signal_number_);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_SIGNAL_HANDLER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/signal_init.hpp view
@@ -0,0 +1,47 @@+//+// detail/signal_init.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SIGNAL_INIT_HPP+#define ASIO_DETAIL_SIGNAL_INIT_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_WINDOWS) && !defined(__CYGWIN__)++#include <csignal>++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <int Signal = SIGPIPE>+class signal_init+{+public:+ // Constructor.+ signal_init()+ {+ std::signal(Signal, SIG_IGN);+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++#endif // ASIO_DETAIL_SIGNAL_INIT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/signal_op.hpp view
@@ -0,0 +1,49 @@+//+// detail/signal_op.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SIGNAL_OP_HPP+#define ASIO_DETAIL_SIGNAL_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/operation.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class signal_op+ : public operation+{+public:+ // The error code to be passed to the completion handler.+ asio::error_code ec_;++ // The signal number to be passed to the completion handler.+ int signal_number_;++protected:+ signal_op(func_type func)+ : operation(func),+ signal_number_(0)+ {+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_SIGNAL_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/signal_set_service.hpp view
@@ -0,0 +1,229 @@+//+// detail/signal_set_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SIGNAL_SET_SERVICE_HPP+#define ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <cstddef>+#include <signal.h>+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/signal_handler.hpp"+#include "asio/detail/signal_op.hpp"+#include "asio/detail/socket_types.hpp"++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#else // defined(ASIO_HAS_IOCP)+# include "asio/detail/scheduler.hpp"+#endif // defined(ASIO_HAS_IOCP)++#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)+# include "asio/detail/reactor.hpp"+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++#if defined(NSIG) && (NSIG > 0)+enum { max_signal_number = NSIG };+#else+enum { max_signal_number = 128 };+#endif++extern ASIO_DECL struct signal_state* get_signal_state();++extern "C" ASIO_DECL void asio_signal_handler(int signal_number);++class signal_set_service :+ public execution_context_service_base<signal_set_service>+{+public:+ // Type used for tracking an individual signal registration.+ class registration+ {+ public:+ // Default constructor.+ registration()+ : signal_number_(0),+ queue_(0),+ undelivered_(0),+ next_in_table_(0),+ prev_in_table_(0),+ next_in_set_(0)+ {+ }++ private:+ // Only this service will have access to the internal values.+ friend class signal_set_service;++ // The signal number that is registered.+ int signal_number_;++ // The waiting signal handlers.+ op_queue<signal_op>* queue_;++ // The number of undelivered signals.+ std::size_t undelivered_;++ // Pointers to adjacent registrations in the registrations_ table.+ registration* next_in_table_;+ registration* prev_in_table_;++ // Link to next registration in the signal set.+ registration* next_in_set_;+ };++ // The implementation type of the signal_set.+ class implementation_type+ {+ public:+ // Default constructor.+ implementation_type()+ : signals_(0)+ {+ }++ private:+ // Only this service will have access to the internal values.+ friend class signal_set_service;++ // The pending signal handlers.+ op_queue<signal_op> queue_;++ // Linked list of registered signals.+ registration* signals_;+ };++ // Constructor.+ ASIO_DECL signal_set_service(execution_context& context);++ // Destructor.+ ASIO_DECL ~signal_set_service();++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Perform fork-related housekeeping.+ ASIO_DECL void notify_fork(+ asio::execution_context::fork_event fork_ev);++ // Construct a new signal_set implementation.+ ASIO_DECL void construct(implementation_type& impl);++ // Destroy a signal_set implementation.+ ASIO_DECL void destroy(implementation_type& impl);++ // Add a signal to a signal_set.+ ASIO_DECL asio::error_code add(implementation_type& impl,+ int signal_number, asio::error_code& ec);++ // Remove a signal to a signal_set.+ ASIO_DECL asio::error_code remove(implementation_type& impl,+ int signal_number, asio::error_code& ec);++ // Remove all signals from a signal_set.+ ASIO_DECL asio::error_code clear(implementation_type& impl,+ asio::error_code& ec);++ // Cancel all operations associated with the signal set.+ ASIO_DECL asio::error_code cancel(implementation_type& impl,+ asio::error_code& ec);++ // Start an asynchronous operation to wait for a signal to be delivered.+ template <typename Handler, typename IoExecutor>+ void async_wait(implementation_type& impl,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef signal_handler<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(handler, io_ex);++ ASIO_HANDLER_CREATION((scheduler_.context(),+ *p.p, "signal_set", &impl, 0, "async_wait"));++ start_wait_op(impl, p.p);+ p.v = p.p = 0;+ }++ // Deliver notification that a particular signal occurred.+ ASIO_DECL static void deliver_signal(int signal_number);++private:+ // Helper function to add a service to the global signal state.+ ASIO_DECL static void add_service(signal_set_service* service);++ // Helper function to remove a service from the global signal state.+ ASIO_DECL static void remove_service(signal_set_service* service);++ // Helper function to create the pipe descriptors.+ ASIO_DECL static void open_descriptors();++ // Helper function to close the pipe descriptors.+ ASIO_DECL static void close_descriptors();++ // Helper function to start a wait operation.+ ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op);++ // The scheduler used for dispatching handlers.+#if defined(ASIO_HAS_IOCP)+ typedef class win_iocp_io_context scheduler_impl;+#else+ typedef class scheduler scheduler_impl;+#endif+ scheduler_impl& scheduler_;++#if !defined(ASIO_WINDOWS) \+ && !defined(ASIO_WINDOWS_RUNTIME) \+ && !defined(__CYGWIN__)+ // The type used for registering for pipe reactor notifications.+ class pipe_read_op;++ // The reactor used for waiting for pipe readiness.+ reactor& reactor_;++ // The per-descriptor reactor data used for the pipe.+ reactor::per_descriptor_data reactor_data_;+#endif // !defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_RUNTIME)+ // && !defined(__CYGWIN__)++ // A mapping from signal number to the registered signal sets.+ registration* registrations_[max_signal_number];++ // Pointers to adjacent services in linked list.+ signal_set_service* next_;+ signal_set_service* prev_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/signal_set_service.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/socket_holder.hpp view
@@ -0,0 +1,98 @@+//+// detail/socket_holder.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_HOLDER_HPP+#define ASIO_DETAIL_SOCKET_HOLDER_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/noncopyable.hpp"+#include "asio/detail/socket_ops.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Implement the resource acquisition is initialisation idiom for sockets.+class socket_holder+ : private noncopyable+{+public:+ // Construct as an uninitialised socket.+ socket_holder()+ : socket_(invalid_socket)+ {+ }++ // Construct to take ownership of the specified socket.+ explicit socket_holder(socket_type s)+ : socket_(s)+ {+ }++ // Destructor.+ ~socket_holder()+ {+ if (socket_ != invalid_socket)+ {+ asio::error_code ec;+ socket_ops::state_type state = 0;+ socket_ops::close(socket_, state, true, ec);+ }+ }++ // Get the underlying socket.+ socket_type get() const+ {+ return socket_;+ }++ // Reset to an uninitialised socket.+ void reset()+ {+ if (socket_ != invalid_socket)+ {+ asio::error_code ec;+ socket_ops::state_type state = 0;+ socket_ops::close(socket_, state, true, ec);+ socket_ = invalid_socket;+ }+ }++ // Reset to take ownership of the specified socket.+ void reset(socket_type s)+ {+ reset();+ socket_ = s;+ }++ // Release ownership of the socket.+ socket_type release()+ {+ socket_type tmp = socket_;+ socket_ = invalid_socket;+ return tmp;+ }++private:+ // The underlying socket.+ socket_type socket_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_SOCKET_HOLDER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/socket_ops.hpp view
@@ -0,0 +1,383 @@+//+// detail/socket_ops.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_OPS_HPP+#define ASIO_DETAIL_SOCKET_OPS_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include "asio/error_code.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {+namespace socket_ops {++// Socket state bits.+enum+{+ // The user wants a non-blocking socket.+ user_set_non_blocking = 1,++ // The socket has been set non-blocking.+ internal_non_blocking = 2,++ // Helper "state" used to determine whether the socket is non-blocking.+ non_blocking = user_set_non_blocking | internal_non_blocking,++ // User wants connection_aborted errors, which are disabled by default.+ enable_connection_aborted = 4,++ // The user set the linger option. Needs to be checked when closing.+ user_set_linger = 8,++ // The socket is stream-oriented.+ stream_oriented = 16,++ // The socket is datagram-oriented.+ datagram_oriented = 32,++ // The socket may have been dup()-ed.+ possible_dup = 64+};++typedef unsigned char state_type;++struct noop_deleter { void operator()(void*) {} };+typedef shared_ptr<void> shared_cancel_token_type;+typedef weak_ptr<void> weak_cancel_token_type;++#if !defined(ASIO_WINDOWS_RUNTIME)++ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr,+ std::size_t* addrlen, asio::error_code& ec);++ASIO_DECL socket_type sync_accept(socket_type s,+ state_type state, socket_addr_type* addr,+ std::size_t* addrlen, asio::error_code& ec);++#if defined(ASIO_HAS_IOCP)++ASIO_DECL void complete_iocp_accept(socket_type s,+ void* output_buffer, DWORD address_length,+ socket_addr_type* addr, std::size_t* addrlen,+ socket_type new_socket, asio::error_code& ec);++#else // defined(ASIO_HAS_IOCP)++ASIO_DECL bool non_blocking_accept(socket_type s,+ state_type state, socket_addr_type* addr, std::size_t* addrlen,+ asio::error_code& ec, socket_type& new_socket);++#endif // defined(ASIO_HAS_IOCP)++ASIO_DECL int bind(socket_type s, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec);++ASIO_DECL int close(socket_type s, state_type& state,+ bool destruction, asio::error_code& ec);++ASIO_DECL bool set_user_non_blocking(socket_type s,+ state_type& state, bool value, asio::error_code& ec);++ASIO_DECL bool set_internal_non_blocking(socket_type s,+ state_type& state, bool value, asio::error_code& ec);++ASIO_DECL int shutdown(socket_type s,+ int what, asio::error_code& ec);++ASIO_DECL int connect(socket_type s, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec);++ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec);++#if defined(ASIO_HAS_IOCP)++ASIO_DECL void complete_iocp_connect(socket_type s,+ asio::error_code& ec);++#endif // defined(ASIO_HAS_IOCP)++ASIO_DECL bool non_blocking_connect(socket_type s,+ asio::error_code& ec);++ASIO_DECL int socketpair(int af, int type, int protocol,+ socket_type sv[2], asio::error_code& ec);++ASIO_DECL bool sockatmark(socket_type s, asio::error_code& ec);++ASIO_DECL size_t available(socket_type s, asio::error_code& ec);++ASIO_DECL int listen(socket_type s,+ int backlog, asio::error_code& ec);++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+typedef WSABUF buf;+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+typedef iovec buf;+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++ASIO_DECL void init_buf(buf& b, void* data, size_t size);++ASIO_DECL void init_buf(buf& b, const void* data, size_t size);++ASIO_DECL signed_size_type recv(socket_type s, buf* bufs,+ size_t count, int flags, asio::error_code& ec);++ASIO_DECL signed_size_type recv1(socket_type s,+ void* data, size_t size, int flags, asio::error_code& ec);++ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs,+ size_t count, int flags, bool all_empty, asio::error_code& ec);++ASIO_DECL size_t sync_recv1(socket_type s, state_type state,+ void* data, size_t size, int flags, asio::error_code& ec);++#if defined(ASIO_HAS_IOCP)++ASIO_DECL void complete_iocp_recv(state_type state,+ const weak_cancel_token_type& cancel_token, bool all_empty,+ asio::error_code& ec, size_t bytes_transferred);++#else // defined(ASIO_HAS_IOCP)++ASIO_DECL bool non_blocking_recv(socket_type s,+ buf* bufs, size_t count, int flags, bool is_stream,+ asio::error_code& ec, size_t& bytes_transferred);++ASIO_DECL bool non_blocking_recv1(socket_type s,+ void* data, size_t size, int flags, bool is_stream,+ asio::error_code& ec, size_t& bytes_transferred);++#endif // defined(ASIO_HAS_IOCP)++ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs,+ size_t count, int flags, socket_addr_type* addr,+ std::size_t* addrlen, asio::error_code& ec);++ASIO_DECL signed_size_type recvfrom1(socket_type s, void* data,+ size_t size, int flags, socket_addr_type* addr,+ std::size_t* addrlen, asio::error_code& ec);++ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state,+ buf* bufs, size_t count, int flags, socket_addr_type* addr,+ std::size_t* addrlen, asio::error_code& ec);++ASIO_DECL size_t sync_recvfrom1(socket_type s, state_type state,+ void* data, size_t size, int flags, socket_addr_type* addr,+ std::size_t* addrlen, asio::error_code& ec);++#if defined(ASIO_HAS_IOCP)++ASIO_DECL void complete_iocp_recvfrom(+ const weak_cancel_token_type& cancel_token,+ asio::error_code& ec);++#else // defined(ASIO_HAS_IOCP)++ASIO_DECL bool non_blocking_recvfrom(socket_type s,+ buf* bufs, size_t count, int flags,+ socket_addr_type* addr, std::size_t* addrlen,+ asio::error_code& ec, size_t& bytes_transferred);++ASIO_DECL bool non_blocking_recvfrom1(socket_type s,+ void* data, size_t size, int flags,+ socket_addr_type* addr, std::size_t* addrlen,+ asio::error_code& ec, size_t& bytes_transferred);++#endif // defined(ASIO_HAS_IOCP)++ASIO_DECL signed_size_type recvmsg(socket_type s, buf* bufs,+ size_t count, int in_flags, int& out_flags,+ asio::error_code& ec);++ASIO_DECL size_t sync_recvmsg(socket_type s, state_type state,+ buf* bufs, size_t count, int in_flags, int& out_flags,+ asio::error_code& ec);++#if defined(ASIO_HAS_IOCP)++ASIO_DECL void complete_iocp_recvmsg(+ const weak_cancel_token_type& cancel_token,+ asio::error_code& ec);++#else // defined(ASIO_HAS_IOCP)++ASIO_DECL bool non_blocking_recvmsg(socket_type s,+ buf* bufs, size_t count, int in_flags, int& out_flags,+ asio::error_code& ec, size_t& bytes_transferred);++#endif // defined(ASIO_HAS_IOCP)++ASIO_DECL signed_size_type send(socket_type s, const buf* bufs,+ size_t count, int flags, asio::error_code& ec);++ASIO_DECL signed_size_type send1(socket_type s,+ const void* data, size_t size, int flags, asio::error_code& ec);++ASIO_DECL size_t sync_send(socket_type s, state_type state,+ const buf* bufs, size_t count, int flags,+ bool all_empty, asio::error_code& ec);++ASIO_DECL size_t sync_send1(socket_type s, state_type state,+ const void* data, size_t size, int flags, asio::error_code& ec);++#if defined(ASIO_HAS_IOCP)++ASIO_DECL void complete_iocp_send(+ const weak_cancel_token_type& cancel_token,+ asio::error_code& ec);++#else // defined(ASIO_HAS_IOCP)++ASIO_DECL bool non_blocking_send(socket_type s,+ const buf* bufs, size_t count, int flags,+ asio::error_code& ec, size_t& bytes_transferred);++ASIO_DECL bool non_blocking_send1(socket_type s,+ const void* data, size_t size, int flags,+ asio::error_code& ec, size_t& bytes_transferred);++#endif // defined(ASIO_HAS_IOCP)++ASIO_DECL signed_size_type sendto(socket_type s, const buf* bufs,+ size_t count, int flags, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec);++ASIO_DECL signed_size_type sendto1(socket_type s, const void* data,+ size_t size, int flags, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec);++ASIO_DECL size_t sync_sendto(socket_type s, state_type state,+ const buf* bufs, size_t count, int flags, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec);++ASIO_DECL size_t sync_sendto1(socket_type s, state_type state,+ const void* data, size_t size, int flags, const socket_addr_type* addr,+ std::size_t addrlen, asio::error_code& ec);++#if !defined(ASIO_HAS_IOCP)++ASIO_DECL bool non_blocking_sendto(socket_type s,+ const buf* bufs, size_t count, int flags,+ const socket_addr_type* addr, std::size_t addrlen,+ asio::error_code& ec, size_t& bytes_transferred);++ASIO_DECL bool non_blocking_sendto1(socket_type s,+ const void* data, size_t size, int flags,+ const socket_addr_type* addr, std::size_t addrlen,+ asio::error_code& ec, size_t& bytes_transferred);++#endif // !defined(ASIO_HAS_IOCP)++ASIO_DECL socket_type socket(int af, int type, int protocol,+ asio::error_code& ec);++ASIO_DECL int setsockopt(socket_type s, state_type& state,+ int level, int optname, const void* optval,+ std::size_t optlen, asio::error_code& ec);++ASIO_DECL int getsockopt(socket_type s, state_type state,+ int level, int optname, void* optval,+ size_t* optlen, asio::error_code& ec);++ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr,+ std::size_t* addrlen, bool cached, asio::error_code& ec);++ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr,+ std::size_t* addrlen, asio::error_code& ec);++ASIO_DECL int ioctl(socket_type s, state_type& state,+ int cmd, ioctl_arg_type* arg, asio::error_code& ec);++ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds,+ fd_set* exceptfds, timeval* timeout, asio::error_code& ec);++ASIO_DECL int poll_read(socket_type s,+ state_type state, int msec, asio::error_code& ec);++ASIO_DECL int poll_write(socket_type s,+ state_type state, int msec, asio::error_code& ec);++ASIO_DECL int poll_error(socket_type s,+ state_type state, int msec, asio::error_code& ec);++ASIO_DECL int poll_connect(socket_type s,+ int msec, asio::error_code& ec);++#endif // !defined(ASIO_WINDOWS_RUNTIME)++ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest,+ size_t length, unsigned long scope_id, asio::error_code& ec);++ASIO_DECL int inet_pton(int af, const char* src, void* dest,+ unsigned long* scope_id, asio::error_code& ec);++ASIO_DECL int gethostname(char* name,+ int namelen, asio::error_code& ec);++#if !defined(ASIO_WINDOWS_RUNTIME)++ASIO_DECL asio::error_code getaddrinfo(const char* host,+ const char* service, const addrinfo_type& hints,+ addrinfo_type** result, asio::error_code& ec);++ASIO_DECL asio::error_code background_getaddrinfo(+ const weak_cancel_token_type& cancel_token, const char* host,+ const char* service, const addrinfo_type& hints,+ addrinfo_type** result, asio::error_code& ec);++ASIO_DECL void freeaddrinfo(addrinfo_type* ai);++ASIO_DECL asio::error_code getnameinfo(+ const socket_addr_type* addr, std::size_t addrlen,+ char* host, std::size_t hostlen, char* serv,+ std::size_t servlen, int flags, asio::error_code& ec);++ASIO_DECL asio::error_code sync_getnameinfo(+ const socket_addr_type* addr, std::size_t addrlen,+ char* host, std::size_t hostlen, char* serv,+ std::size_t servlen, int sock_type, asio::error_code& ec);++ASIO_DECL asio::error_code background_getnameinfo(+ const weak_cancel_token_type& cancel_token,+ const socket_addr_type* addr, std::size_t addrlen,+ char* host, std::size_t hostlen, char* serv,+ std::size_t servlen, int sock_type, asio::error_code& ec);++#endif // !defined(ASIO_WINDOWS_RUNTIME)++ASIO_DECL u_long_type network_to_host_long(u_long_type value);++ASIO_DECL u_long_type host_to_network_long(u_long_type value);++ASIO_DECL u_short_type network_to_host_short(u_short_type value);++ASIO_DECL u_short_type host_to_network_short(u_short_type value);++} // namespace socket_ops+} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/socket_ops.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_SOCKET_OPS_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/socket_option.hpp view
@@ -0,0 +1,316 @@+//+// detail/socket_option.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_OPTION_HPP+#define ASIO_DETAIL_SOCKET_OPTION_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include <stdexcept>+#include "asio/detail/socket_types.hpp"+#include "asio/detail/throw_exception.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {+namespace socket_option {++// Helper template for implementing boolean-based options.+template <int Level, int Name>+class boolean+{+public:+ // Default constructor.+ boolean()+ : value_(0)+ {+ }++ // Construct with a specific option value.+ explicit boolean(bool v)+ : value_(v ? 1 : 0)+ {+ }++ // Set the current value of the boolean.+ boolean& operator=(bool v)+ {+ value_ = v ? 1 : 0;+ return *this;+ }++ // Get the current value of the boolean.+ bool value() const+ {+ return !!value_;+ }++ // Convert to bool.+ operator bool() const+ {+ return !!value_;+ }++ // Test for false.+ bool operator!() const+ {+ return !value_;+ }++ // Get the level of the socket option.+ template <typename Protocol>+ int level(const Protocol&) const+ {+ return Level;+ }++ // Get the name of the socket option.+ template <typename Protocol>+ int name(const Protocol&) const+ {+ return Name;+ }++ // Get the address of the boolean data.+ template <typename Protocol>+ int* data(const Protocol&)+ {+ return &value_;+ }++ // Get the address of the boolean data.+ template <typename Protocol>+ const int* data(const Protocol&) const+ {+ return &value_;+ }++ // Get the size of the boolean data.+ template <typename Protocol>+ std::size_t size(const Protocol&) const+ {+ return sizeof(value_);+ }++ // Set the size of the boolean data.+ template <typename Protocol>+ void resize(const Protocol&, std::size_t s)+ {+ // On some platforms (e.g. Windows Vista), the getsockopt function will+ // return the size of a boolean socket option as one byte, even though a+ // four byte integer was passed in.+ switch (s)+ {+ case sizeof(char):+ value_ = *reinterpret_cast<char*>(&value_) ? 1 : 0;+ break;+ case sizeof(value_):+ break;+ default:+ {+ std::length_error ex("boolean socket option resize");+ asio::detail::throw_exception(ex);+ }+ }+ }++private:+ int value_;+};++// Helper template for implementing integer options.+template <int Level, int Name>+class integer+{+public:+ // Default constructor.+ integer()+ : value_(0)+ {+ }++ // Construct with a specific option value.+ explicit integer(int v)+ : value_(v)+ {+ }++ // Set the value of the int option.+ integer& operator=(int v)+ {+ value_ = v;+ return *this;+ }++ // Get the current value of the int option.+ int value() const+ {+ return value_;+ }++ // Get the level of the socket option.+ template <typename Protocol>+ int level(const Protocol&) const+ {+ return Level;+ }++ // Get the name of the socket option.+ template <typename Protocol>+ int name(const Protocol&) const+ {+ return Name;+ }++ // Get the address of the int data.+ template <typename Protocol>+ int* data(const Protocol&)+ {+ return &value_;+ }++ // Get the address of the int data.+ template <typename Protocol>+ const int* data(const Protocol&) const+ {+ return &value_;+ }++ // Get the size of the int data.+ template <typename Protocol>+ std::size_t size(const Protocol&) const+ {+ return sizeof(value_);+ }++ // Set the size of the int data.+ template <typename Protocol>+ void resize(const Protocol&, std::size_t s)+ {+ if (s != sizeof(value_))+ {+ std::length_error ex("integer socket option resize");+ asio::detail::throw_exception(ex);+ }+ }++private:+ int value_;+};++// Helper template for implementing linger options.+template <int Level, int Name>+class linger+{+public:+ // Default constructor.+ linger()+ {+ value_.l_onoff = 0;+ value_.l_linger = 0;+ }++ // Construct with specific option values.+ linger(bool e, int t)+ {+ enabled(e);+ timeout ASIO_PREVENT_MACRO_SUBSTITUTION(t);+ }++ // Set the value for whether linger is enabled.+ void enabled(bool value)+ {+ value_.l_onoff = value ? 1 : 0;+ }++ // Get the value for whether linger is enabled.+ bool enabled() const+ {+ return value_.l_onoff != 0;+ }++ // Set the value for the linger timeout.+ void timeout ASIO_PREVENT_MACRO_SUBSTITUTION(int value)+ {+#if defined(WIN32)+ value_.l_linger = static_cast<u_short>(value);+#else+ value_.l_linger = value;+#endif+ }++ // Get the value for the linger timeout.+ int timeout ASIO_PREVENT_MACRO_SUBSTITUTION() const+ {+ return static_cast<int>(value_.l_linger);+ }++ // Get the level of the socket option.+ template <typename Protocol>+ int level(const Protocol&) const+ {+ return Level;+ }++ // Get the name of the socket option.+ template <typename Protocol>+ int name(const Protocol&) const+ {+ return Name;+ }++ // Get the address of the linger data.+ template <typename Protocol>+ detail::linger_type* data(const Protocol&)+ {+ return &value_;+ }++ // Get the address of the linger data.+ template <typename Protocol>+ const detail::linger_type* data(const Protocol&) const+ {+ return &value_;+ }++ // Get the size of the linger data.+ template <typename Protocol>+ std::size_t size(const Protocol&) const+ {+ return sizeof(value_);+ }++ // Set the size of the int data.+ template <typename Protocol>+ void resize(const Protocol&, std::size_t s)+ {+ if (s != sizeof(value_))+ {+ std::length_error ex("linger socket option resize");+ asio::detail::throw_exception(ex);+ }+ }++private:+ detail::linger_type value_;+};++} // namespace socket_option+} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_SOCKET_OPTION_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/socket_select_interrupter.hpp view
@@ -0,0 +1,91 @@+//+// detail/socket_select_interrupter.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_SELECT_INTERRUPTER_HPP+#define ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_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_WINDOWS_RUNTIME)++#if defined(ASIO_WINDOWS) \+ || defined(__CYGWIN__) \+ || defined(__SYMBIAN32__)++#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class socket_select_interrupter+{+public:+ // Constructor.+ ASIO_DECL socket_select_interrupter();++ // Destructor.+ ASIO_DECL ~socket_select_interrupter();++ // Recreate the interrupter's descriptors. Used after a fork.+ ASIO_DECL void recreate();++ // Interrupt the select call.+ ASIO_DECL void interrupt();++ // Reset the select interrupter. Returns true if the reset was successful.+ ASIO_DECL bool reset();++ // Get the read descriptor to be passed to select.+ socket_type read_descriptor() const+ {+ return read_descriptor_;+ }++private:+ // Open the descriptors. Throws on error.+ ASIO_DECL void open_descriptors();++ // Close the descriptors.+ ASIO_DECL void close_descriptors();++ // The read end of a connection used to interrupt the select call. This file+ // descriptor is passed to select such that when it is time to stop, a single+ // byte will be written on the other end of the connection and this+ // descriptor will become readable.+ socket_type read_descriptor_;++ // The write end of a connection used to interrupt the select call. A single+ // byte may be written to this to wake up the select which is waiting for the+ // other end to become readable.+ socket_type write_descriptor_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/socket_select_interrupter.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_WINDOWS)+ // || defined(__CYGWIN__)+ // || defined(__SYMBIAN32__)++#endif // !defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/socket_types.hpp view
@@ -0,0 +1,416 @@+//+// detail/socket_types.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_TYPES_HPP+#define ASIO_DETAIL_SOCKET_TYPES_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_WINDOWS_RUNTIME)+// Empty.+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)+# error WinSock.h has already been included+# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)+# if defined(__BORLANDC__)+# include <stdlib.h> // Needed for __errno+# if !defined(_WSPIAPI_H_)+# define _WSPIAPI_H_+# define ASIO_WSPIAPI_H_DEFINED+# endif // !defined(_WSPIAPI_H_)+# endif // defined(__BORLANDC__)+# include <winsock2.h>+# include <ws2tcpip.h>+# if defined(WINAPI_FAMILY)+# if ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0)+# include <windows.h>+# endif // ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0)+# endif // defined(WINAPI_FAMILY)+# if !defined(ASIO_WINDOWS_APP)+# include <mswsock.h>+# endif // !defined(ASIO_WINDOWS_APP)+# if defined(ASIO_WSPIAPI_H_DEFINED)+# undef _WSPIAPI_H_+# undef ASIO_WSPIAPI_H_DEFINED+# endif // defined(ASIO_WSPIAPI_H_DEFINED)+# if !defined(ASIO_NO_DEFAULT_LINKED_LIBS)+# if defined(UNDER_CE)+# pragma comment(lib, "ws2.lib")+# elif defined(_MSC_VER) || defined(__BORLANDC__)+# pragma comment(lib, "ws2_32.lib")+# if !defined(ASIO_WINDOWS_APP)+# pragma comment(lib, "mswsock.lib")+# endif // !defined(ASIO_WINDOWS_APP)+# endif // defined(_MSC_VER) || defined(__BORLANDC__)+# endif // !defined(ASIO_NO_DEFAULT_LINKED_LIBS)+# include "asio/detail/old_win_sdk_compat.hpp"+#else+# include <sys/ioctl.h>+# if (defined(__MACH__) && defined(__APPLE__)) \+ || defined(__FreeBSD__) || defined(__NetBSD__) \+ || defined(__OpenBSD__) || defined(__linux__) \+ || defined(__EMSCRIPTEN__)+# include <poll.h>+# elif !defined(__SYMBIAN32__)+# include <sys/poll.h>+# endif+# include <sys/types.h>+# include <sys/stat.h>+# include <fcntl.h>+# if defined(__hpux)+# include <sys/time.h>+# endif+# if !defined(__hpux) || defined(__SELECT)+# include <sys/select.h>+# endif+# include <sys/socket.h>+# include <sys/uio.h>+# include <sys/un.h>+# include <netinet/in.h>+# if !defined(__SYMBIAN32__)+# include <netinet/tcp.h>+# endif+# include <arpa/inet.h>+# include <netdb.h>+# include <net/if.h>+# include <limits.h>+# if defined(__sun)+# include <sys/filio.h>+# include <sys/sockio.h>+# endif+#endif++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++#if defined(ASIO_WINDOWS_RUNTIME)+const int max_addr_v4_str_len = 256;+const int max_addr_v6_str_len = 256;+typedef unsigned __int32 u_long_type;+typedef unsigned __int16 u_short_type;+struct in4_addr_type { u_long_type s_addr; };+struct in4_mreq_type { in4_addr_type imr_multiaddr, imr_interface; };+struct in6_addr_type { unsigned char s6_addr[16]; };+struct in6_mreq_type { in6_addr_type ipv6mr_multiaddr;+ unsigned long ipv6mr_interface; };+struct socket_addr_type { int sa_family; };+struct sockaddr_in4_type { int sin_family;+ in4_addr_type sin_addr; u_short_type sin_port; };+struct sockaddr_in6_type { int sin6_family;+ in6_addr_type sin6_addr; u_short_type sin6_port;+ u_long_type sin6_flowinfo; u_long_type sin6_scope_id; };+struct sockaddr_storage_type { int ss_family;+ unsigned char ss_bytes[128 - sizeof(int)]; };+struct addrinfo_type { int ai_flags;+ int ai_family, ai_socktype, ai_protocol;+ int ai_addrlen; const void* ai_addr;+ const char* ai_canonname; addrinfo_type* ai_next; };+struct linger_type { u_short_type l_onoff, l_linger; };+typedef u_long_type ioctl_arg_type;+typedef int signed_size_type;+# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c+# define ASIO_OS_DEF_AF_UNSPEC 0+# define ASIO_OS_DEF_AF_INET 2+# define ASIO_OS_DEF_AF_INET6 23+# define ASIO_OS_DEF_SOCK_STREAM 1+# define ASIO_OS_DEF_SOCK_DGRAM 2+# define ASIO_OS_DEF_SOCK_RAW 3+# define ASIO_OS_DEF_SOCK_SEQPACKET 5+# define ASIO_OS_DEF_IPPROTO_IP 0+# define ASIO_OS_DEF_IPPROTO_IPV6 41+# define ASIO_OS_DEF_IPPROTO_TCP 6+# define ASIO_OS_DEF_IPPROTO_UDP 17+# define ASIO_OS_DEF_IPPROTO_ICMP 1+# define ASIO_OS_DEF_IPPROTO_ICMPV6 58+# define ASIO_OS_DEF_FIONBIO 1+# define ASIO_OS_DEF_FIONREAD 2+# define ASIO_OS_DEF_INADDR_ANY 0+# define ASIO_OS_DEF_MSG_OOB 0x1+# define ASIO_OS_DEF_MSG_PEEK 0x2+# define ASIO_OS_DEF_MSG_DONTROUTE 0x4+# define ASIO_OS_DEF_MSG_EOR 0 // Not supported.+# define ASIO_OS_DEF_SHUT_RD 0x0+# define ASIO_OS_DEF_SHUT_WR 0x1+# define ASIO_OS_DEF_SHUT_RDWR 0x2+# define ASIO_OS_DEF_SOMAXCONN 0x7fffffff+# define ASIO_OS_DEF_SOL_SOCKET 0xffff+# define ASIO_OS_DEF_SO_BROADCAST 0x20+# define ASIO_OS_DEF_SO_DEBUG 0x1+# define ASIO_OS_DEF_SO_DONTROUTE 0x10+# define ASIO_OS_DEF_SO_KEEPALIVE 0x8+# define ASIO_OS_DEF_SO_LINGER 0x80+# define ASIO_OS_DEF_SO_OOBINLINE 0x100+# define ASIO_OS_DEF_SO_SNDBUF 0x1001+# define ASIO_OS_DEF_SO_RCVBUF 0x1002+# define ASIO_OS_DEF_SO_SNDLOWAT 0x1003+# define ASIO_OS_DEF_SO_RCVLOWAT 0x1004+# define ASIO_OS_DEF_SO_REUSEADDR 0x4+# define ASIO_OS_DEF_TCP_NODELAY 0x1+# define ASIO_OS_DEF_IP_MULTICAST_IF 2+# define ASIO_OS_DEF_IP_MULTICAST_TTL 3+# define ASIO_OS_DEF_IP_MULTICAST_LOOP 4+# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP 5+# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP 6+# define ASIO_OS_DEF_IP_TTL 7+# define ASIO_OS_DEF_IPV6_UNICAST_HOPS 4+# define ASIO_OS_DEF_IPV6_MULTICAST_IF 9+# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS 10+# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP 11+# define ASIO_OS_DEF_IPV6_JOIN_GROUP 12+# define ASIO_OS_DEF_IPV6_LEAVE_GROUP 13+# define ASIO_OS_DEF_AI_CANONNAME 0x2+# define ASIO_OS_DEF_AI_PASSIVE 0x1+# define ASIO_OS_DEF_AI_NUMERICHOST 0x4+# define ASIO_OS_DEF_AI_NUMERICSERV 0x8+# define ASIO_OS_DEF_AI_V4MAPPED 0x800+# define ASIO_OS_DEF_AI_ALL 0x100+# define ASIO_OS_DEF_AI_ADDRCONFIG 0x400+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+typedef SOCKET socket_type;+const SOCKET invalid_socket = INVALID_SOCKET;+const int socket_error_retval = SOCKET_ERROR;+const int max_addr_v4_str_len = 256;+const int max_addr_v6_str_len = 256;+typedef sockaddr socket_addr_type;+typedef in_addr in4_addr_type;+typedef ip_mreq in4_mreq_type;+typedef sockaddr_in sockaddr_in4_type;+# if defined(ASIO_HAS_OLD_WIN_SDK)+typedef in6_addr_emulation in6_addr_type;+typedef ipv6_mreq_emulation in6_mreq_type;+typedef sockaddr_in6_emulation sockaddr_in6_type;+typedef sockaddr_storage_emulation sockaddr_storage_type;+typedef addrinfo_emulation addrinfo_type;+# else+typedef in6_addr in6_addr_type;+typedef ipv6_mreq in6_mreq_type;+typedef sockaddr_in6 sockaddr_in6_type;+typedef sockaddr_storage sockaddr_storage_type;+typedef addrinfo addrinfo_type;+# endif+typedef ::linger linger_type;+typedef unsigned long ioctl_arg_type;+typedef u_long u_long_type;+typedef u_short u_short_type;+typedef int signed_size_type;+# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c+# define ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC+# define ASIO_OS_DEF_AF_INET AF_INET+# define ASIO_OS_DEF_AF_INET6 AF_INET6+# define ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM+# define ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM+# define ASIO_OS_DEF_SOCK_RAW SOCK_RAW+# define ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET+# define ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP+# define ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6+# define ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP+# define ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP+# define ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP+# define ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6+# define ASIO_OS_DEF_FIONBIO FIONBIO+# define ASIO_OS_DEF_FIONREAD FIONREAD+# define ASIO_OS_DEF_INADDR_ANY INADDR_ANY+# define ASIO_OS_DEF_MSG_OOB MSG_OOB+# define ASIO_OS_DEF_MSG_PEEK MSG_PEEK+# define ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE+# define ASIO_OS_DEF_MSG_EOR 0 // Not supported on Windows.+# define ASIO_OS_DEF_SHUT_RD SD_RECEIVE+# define ASIO_OS_DEF_SHUT_WR SD_SEND+# define ASIO_OS_DEF_SHUT_RDWR SD_BOTH+# define ASIO_OS_DEF_SOMAXCONN SOMAXCONN+# define ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET+# define ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST+# define ASIO_OS_DEF_SO_DEBUG SO_DEBUG+# define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE+# define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE+# define ASIO_OS_DEF_SO_LINGER SO_LINGER+# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE+# define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF+# define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF+# define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT+# define ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT+# define ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR+# define ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY+# define ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF+# define ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL+# define ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP+# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP+# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP+# define ASIO_OS_DEF_IP_TTL IP_TTL+# define ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS+# define ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF+# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS+# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP+# define ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP+# define ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP+# define ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME+# define ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE+# define ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST+# if defined(AI_NUMERICSERV)+# define ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV+# else+# define ASIO_OS_DEF_AI_NUMERICSERV 0+# endif+# if defined(AI_V4MAPPED)+# define ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED+# else+# define ASIO_OS_DEF_AI_V4MAPPED 0+# endif+# if defined(AI_ALL)+# define ASIO_OS_DEF_AI_ALL AI_ALL+# else+# define ASIO_OS_DEF_AI_ALL 0+# endif+# if defined(AI_ADDRCONFIG)+# define ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG+# else+# define ASIO_OS_DEF_AI_ADDRCONFIG 0+# endif+# if defined (_WIN32_WINNT)+const int max_iov_len = 64;+# else+const int max_iov_len = 16;+# endif+#else+typedef int socket_type;+const int invalid_socket = -1;+const int socket_error_retval = -1;+const int max_addr_v4_str_len = INET_ADDRSTRLEN;+#if defined(INET6_ADDRSTRLEN)+const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE;+#else // defined(INET6_ADDRSTRLEN)+const int max_addr_v6_str_len = 256;+#endif // defined(INET6_ADDRSTRLEN)+typedef sockaddr socket_addr_type;+typedef in_addr in4_addr_type;+# if defined(__hpux)+// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined.+struct in4_mreq_type+{+ struct in_addr imr_multiaddr;+ struct in_addr imr_interface;+};+# else+typedef ip_mreq in4_mreq_type;+# endif+typedef sockaddr_in sockaddr_in4_type;+typedef in6_addr in6_addr_type;+typedef ipv6_mreq in6_mreq_type;+typedef sockaddr_in6 sockaddr_in6_type;+typedef sockaddr_storage sockaddr_storage_type;+typedef sockaddr_un sockaddr_un_type;+typedef addrinfo addrinfo_type;+typedef ::linger linger_type;+typedef int ioctl_arg_type;+typedef uint32_t u_long_type;+typedef uint16_t u_short_type;+#if defined(ASIO_HAS_SSIZE_T)+typedef ssize_t signed_size_type;+#else // defined(ASIO_HAS_SSIZE_T)+typedef int signed_size_type;+#endif // defined(ASIO_HAS_SSIZE_T)+# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c+# define ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC+# define ASIO_OS_DEF_AF_INET AF_INET+# define ASIO_OS_DEF_AF_INET6 AF_INET6+# define ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM+# define ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM+# define ASIO_OS_DEF_SOCK_RAW SOCK_RAW+# define ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET+# define ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP+# define ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6+# define ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP+# define ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP+# define ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP+# define ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6+# define ASIO_OS_DEF_FIONBIO FIONBIO+# define ASIO_OS_DEF_FIONREAD FIONREAD+# define ASIO_OS_DEF_INADDR_ANY INADDR_ANY+# define ASIO_OS_DEF_MSG_OOB MSG_OOB+# define ASIO_OS_DEF_MSG_PEEK MSG_PEEK+# define ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE+# define ASIO_OS_DEF_MSG_EOR MSG_EOR+# define ASIO_OS_DEF_SHUT_RD SHUT_RD+# define ASIO_OS_DEF_SHUT_WR SHUT_WR+# define ASIO_OS_DEF_SHUT_RDWR SHUT_RDWR+# define ASIO_OS_DEF_SOMAXCONN SOMAXCONN+# define ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET+# define ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST+# define ASIO_OS_DEF_SO_DEBUG SO_DEBUG+# define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE+# define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE+# define ASIO_OS_DEF_SO_LINGER SO_LINGER+# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE+# define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF+# define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF+# define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT+# define ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT+# define ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR+# define ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY+# define ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF+# define ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL+# define ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP+# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP+# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP+# define ASIO_OS_DEF_IP_TTL IP_TTL+# define ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS+# define ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF+# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS+# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP+# define ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP+# define ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP+# define ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME+# define ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE+# define ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST+# if defined(AI_NUMERICSERV)+# define ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV+# else+# define ASIO_OS_DEF_AI_NUMERICSERV 0+# endif+// Note: QNX Neutrino 6.3 defines AI_V4MAPPED, AI_ALL and AI_ADDRCONFIG but+// does not implement them. Therefore they are specifically excluded here.+# if defined(AI_V4MAPPED) && !defined(__QNXNTO__)+# define ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED+# else+# define ASIO_OS_DEF_AI_V4MAPPED 0+# endif+# if defined(AI_ALL) && !defined(__QNXNTO__)+# define ASIO_OS_DEF_AI_ALL AI_ALL+# else+# define ASIO_OS_DEF_AI_ALL 0+# endif+# if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__)+# define ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG+# else+# define ASIO_OS_DEF_AI_ADDRCONFIG 0+# endif+# if defined(IOV_MAX)+const int max_iov_len = IOV_MAX;+# else+// POSIX platforms are not required to define IOV_MAX.+const int max_iov_len = 16;+# endif+#endif+const int custom_socket_option_level = 0xA5100000;+const int enable_connection_aborted_option = 1;+const int always_fail_option = 2;++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_SOCKET_TYPES_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/solaris_fenced_block.hpp view
@@ -0,0 +1,62 @@+//+// detail/solaris_fenced_block.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOLARIS_FENCED_BLOCK_HPP+#define ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if defined(__sun)++#include <atomic.h>+#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class solaris_fenced_block+ : private noncopyable+{+public:+ enum half_t { half };+ enum full_t { full };++ // Constructor for a half fenced block.+ explicit solaris_fenced_block(half_t)+ {+ }++ // Constructor for a full fenced block.+ explicit solaris_fenced_block(full_t)+ {+ membar_consumer();+ }++ // Destructor.+ ~solaris_fenced_block()+ {+ membar_producer();+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(__sun)++#endif // ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/source_location.hpp view
@@ -0,0 +1,45 @@+//+// detail/source_location.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOURCE_LOCATION_HPP+#define ASIO_DETAIL_SOURCE_LOCATION_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_SOURCE_LOCATION)++#if defined(ASIO_HAS_STD_SOURCE_LOCATION)+# include <source_location>+#elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)+# include <experimental/source_location>+#else // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)+# error ASIO_HAS_SOURCE_LOCATION is set \+ but no source_location is available+#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)++namespace asio {+namespace detail {++#if defined(ASIO_HAS_STD_SOURCE_LOCATION)+using std::source_location;+#elif defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)+using std::experimental::source_location;+#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)++} // namespace detail+} // namespace asio++#endif // defined(ASIO_HAS_SOURCE_LOCATION)++#endif // ASIO_DETAIL_SOURCE_LOCATION_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/static_mutex.hpp view
@@ -0,0 +1,52 @@+//+// detail/static_mutex.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STATIC_MUTEX_HPP+#define ASIO_DETAIL_STATIC_MUTEX_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_THREADS)+# include "asio/detail/null_static_mutex.hpp"+#elif defined(ASIO_WINDOWS)+# include "asio/detail/win_static_mutex.hpp"+#elif defined(ASIO_HAS_PTHREADS)+# include "asio/detail/posix_static_mutex.hpp"+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)+# include "asio/detail/std_static_mutex.hpp"+#else+# error Only Windows and POSIX are supported!+#endif++namespace asio {+namespace detail {++#if !defined(ASIO_HAS_THREADS)+typedef null_static_mutex static_mutex;+# define ASIO_STATIC_MUTEX_INIT ASIO_NULL_STATIC_MUTEX_INIT+#elif defined(ASIO_WINDOWS)+typedef win_static_mutex static_mutex;+# define ASIO_STATIC_MUTEX_INIT ASIO_WIN_STATIC_MUTEX_INIT+#elif defined(ASIO_HAS_PTHREADS)+typedef posix_static_mutex static_mutex;+# define ASIO_STATIC_MUTEX_INIT ASIO_POSIX_STATIC_MUTEX_INIT+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)+typedef std_static_mutex static_mutex;+# define ASIO_STATIC_MUTEX_INIT ASIO_STD_STATIC_MUTEX_INIT+#endif++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_STATIC_MUTEX_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/std_event.hpp view
@@ -0,0 +1,188 @@+//+// detail/std_event.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STD_EVENT_HPP+#define ASIO_DETAIL_STD_EVENT_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_STD_MUTEX_AND_CONDVAR)++#include <chrono>+#include <condition_variable>+#include "asio/detail/assert.hpp"+#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class std_event+ : private noncopyable+{+public:+ // Constructor.+ std_event()+ : state_(0)+ {+ }++ // Destructor.+ ~std_event()+ {+ }++ // Signal the event. (Retained for backward compatibility.)+ template <typename Lock>+ void signal(Lock& lock)+ {+ this->signal_all(lock);+ }++ // Signal all waiters.+ template <typename Lock>+ void signal_all(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ (void)lock;+ state_ |= 1;+ cond_.notify_all();+ }++ // Unlock the mutex and signal one waiter.+ template <typename Lock>+ void unlock_and_signal_one(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ state_ |= 1;+ bool have_waiters = (state_ > 1);+ lock.unlock();+ if (have_waiters)+ cond_.notify_one();+ }++ // Unlock the mutex and signal one waiter who may destroy us.+ template <typename Lock>+ void unlock_and_signal_one(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ state_ |= 1;+ bool have_waiters = (state_ > 1);+ if (have_waiters)+ cond_.notify_one();+ lock.unlock();+ }++ // If there's a waiter, unlock the mutex and signal it.+ template <typename Lock>+ bool maybe_unlock_and_signal_one(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ state_ |= 1;+ if (state_ > 1)+ {+ lock.unlock();+ cond_.notify_one();+ return true;+ }+ return false;+ }++ // Reset the event.+ template <typename Lock>+ void clear(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ (void)lock;+ state_ &= ~std::size_t(1);+ }++ // Wait for the event to become signalled.+ template <typename Lock>+ void wait(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ unique_lock_adapter u_lock(lock);+ while ((state_ & 1) == 0)+ {+ waiter w(state_);+ cond_.wait(u_lock.unique_lock_);+ }+ }++ // Timed wait for the event to become signalled.+ template <typename Lock>+ bool wait_for_usec(Lock& lock, long usec)+ {+ ASIO_ASSERT(lock.locked());+ unique_lock_adapter u_lock(lock);+ if ((state_ & 1) == 0)+ {+ waiter w(state_);+ cond_.wait_for(u_lock.unique_lock_, std::chrono::microseconds(usec));+ }+ return (state_ & 1) != 0;+ }++private:+ // Helper class to temporarily adapt a scoped_lock into a unique_lock so that+ // it can be passed to std::condition_variable::wait().+ struct unique_lock_adapter+ {+ template <typename Lock>+ explicit unique_lock_adapter(Lock& lock)+ : unique_lock_(lock.mutex().mutex_, std::adopt_lock)+ {+ }++ ~unique_lock_adapter()+ {+ unique_lock_.release();+ }++ std::unique_lock<std::mutex> unique_lock_;+ };++ // Helper to increment and decrement the state to track outstanding waiters.+ class waiter+ {+ public:+ explicit waiter(std::size_t& state)+ : state_(state)+ {+ state_ += 2;+ }++ ~waiter()+ {+ state_ -= 2;+ }++ private:+ std::size_t& state_;+ };++ std::condition_variable cond_;+ std::size_t state_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)++#endif // ASIO_DETAIL_STD_EVENT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/std_fenced_block.hpp view
@@ -0,0 +1,62 @@+//+// detail/std_fenced_block.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STD_FENCED_BLOCK_HPP+#define ASIO_DETAIL_STD_FENCED_BLOCK_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_STD_ATOMIC)++#include <atomic>+#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class std_fenced_block+ : private noncopyable+{+public:+ enum half_t { half };+ enum full_t { full };++ // Constructor for a half fenced block.+ explicit std_fenced_block(half_t)+ {+ }++ // Constructor for a full fenced block.+ explicit std_fenced_block(full_t)+ {+ std::atomic_thread_fence(std::memory_order_acquire);+ }++ // Destructor.+ ~std_fenced_block()+ {+ std::atomic_thread_fence(std::memory_order_release);+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_STD_ATOMIC)++#endif // ASIO_DETAIL_STD_FENCED_BLOCK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/std_global.hpp view
@@ -0,0 +1,70 @@+//+// detail/std_global.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STD_GLOBAL_HPP+#define ASIO_DETAIL_STD_GLOBAL_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_STD_CALL_ONCE)++#include <exception>+#include <mutex>++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename T>+struct std_global_impl+{+ // Helper function to perform initialisation.+ static void do_init()+ {+ instance_.ptr_ = new T;+ }++ // Destructor automatically cleans up the global.+ ~std_global_impl()+ {+ delete ptr_;+ }++ static std::once_flag init_once_;+ static std_global_impl instance_;+ T* ptr_;+};++template <typename T>+std::once_flag std_global_impl<T>::init_once_;++template <typename T>+std_global_impl<T> std_global_impl<T>::instance_;++template <typename T>+T& std_global()+{+ std::call_once(std_global_impl<T>::init_once_, &std_global_impl<T>::do_init);+ return *std_global_impl<T>::instance_.ptr_;+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_STD_CALL_ONCE)++#endif // ASIO_DETAIL_STD_GLOBAL_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/std_mutex.hpp view
@@ -0,0 +1,73 @@+//+// detail/std_mutex.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STD_MUTEX_HPP+#define ASIO_DETAIL_STD_MUTEX_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_STD_MUTEX_AND_CONDVAR)++#include <mutex>+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/scoped_lock.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class std_event;++class std_mutex+ : private noncopyable+{+public:+ typedef asio::detail::scoped_lock<std_mutex> scoped_lock;++ // Constructor.+ std_mutex()+ {+ }++ // Destructor.+ ~std_mutex()+ {+ }++ // Lock the mutex.+ void lock()+ {+ mutex_.lock();+ }++ // Unlock the mutex.+ void unlock()+ {+ mutex_.unlock();+ }++private:+ friend class std_event;+ std::mutex mutex_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)++#endif // ASIO_DETAIL_STD_MUTEX_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/std_static_mutex.hpp view
@@ -0,0 +1,81 @@+//+// detail/std_static_mutex.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STD_STATIC_MUTEX_HPP+#define ASIO_DETAIL_STD_STATIC_MUTEX_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_STD_MUTEX_AND_CONDVAR)++#include <mutex>+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/scoped_lock.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class std_event;++class std_static_mutex+ : private noncopyable+{+public:+ typedef asio::detail::scoped_lock<std_static_mutex> scoped_lock;++ // Constructor.+ std_static_mutex(int)+ {+ }++ // Destructor.+ ~std_static_mutex()+ {+ }++ // Initialise the mutex.+ void init()+ {+ // Nothing to do.+ }++ // Lock the mutex.+ void lock()+ {+ mutex_.lock();+ }++ // Unlock the mutex.+ void unlock()+ {+ mutex_.unlock();+ }++private:+ friend class std_event;+ std::mutex mutex_;+};++#define ASIO_STD_STATIC_MUTEX_INIT 0++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)++#endif // ASIO_DETAIL_STD_STATIC_MUTEX_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/std_thread.hpp view
@@ -0,0 +1,71 @@+//+// detail/std_thread.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STD_THREAD_HPP+#define ASIO_DETAIL_STD_THREAD_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_STD_THREAD)++#include <thread>+#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class std_thread+ : private noncopyable+{+public:+ // Constructor.+ template <typename Function>+ std_thread(Function f, unsigned int = 0)+ : thread_(f)+ {+ }++ // Destructor.+ ~std_thread()+ {+ join();+ }++ // Wait for the thread to exit.+ void join()+ {+ if (thread_.joinable())+ thread_.join();+ }++ // Get number of CPUs.+ static std::size_t hardware_concurrency()+ {+ return std::thread::hardware_concurrency();+ }++private:+ std::thread thread_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_STD_THREAD)++#endif // ASIO_DETAIL_STD_THREAD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/strand_executor_service.hpp view
@@ -0,0 +1,166 @@+//+// detail/strand_executor_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STRAND_EXECUTOR_SERVICE_HPP+#define ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_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/atomic_count.hpp"+#include "asio/detail/executor_op.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/scheduler_operation.hpp"+#include "asio/detail/scoped_ptr.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution.hpp"+#include "asio/execution_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Default service implementation for a strand.+class strand_executor_service+ : public execution_context_service_base<strand_executor_service>+{+public:+ // The underlying implementation of a strand.+ class strand_impl+ {+ public:+ ASIO_DECL ~strand_impl();++ private:+ friend class strand_executor_service;++ // Mutex to protect access to internal data.+ mutex* mutex_;++ // Indicates whether the strand is currently "locked" by a handler. This+ // means that there is a handler upcall in progress, or that the strand+ // itself has been scheduled in order to invoke some pending handlers.+ bool locked_;++ // Indicates that the strand has been shut down and will accept no further+ // handlers.+ bool shutdown_;++ // The handlers that are waiting on the strand but should not be run until+ // after the next time the strand is scheduled. This queue must only be+ // modified while the mutex is locked.+ op_queue<scheduler_operation> waiting_queue_;++ // The handlers that are ready to be run. Logically speaking, these are the+ // handlers that hold the strand's lock. The ready queue is only modified+ // from within the strand and so may be accessed without locking the mutex.+ op_queue<scheduler_operation> ready_queue_;++ // Pointers to adjacent handle implementations in linked list.+ strand_impl* next_;+ strand_impl* prev_;++ // The strand service in where the implementation is held.+ strand_executor_service* service_;+ };++ typedef shared_ptr<strand_impl> implementation_type;++ // Construct a new strand service for the specified context.+ ASIO_DECL explicit strand_executor_service(execution_context& context);++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Create a new strand_executor implementation.+ ASIO_DECL implementation_type create_implementation();++ // Request invocation of the given function.+ template <typename Executor, typename Function>+ static void execute(const implementation_type& impl, Executor& ex,+ ASIO_MOVE_ARG(Function) function,+ typename enable_if<+ can_query<Executor, execution::allocator_t<void> >::value+ >::type* = 0);++ // Request invocation of the given function.+ template <typename Executor, typename Function>+ static void execute(const implementation_type& impl, Executor& ex,+ ASIO_MOVE_ARG(Function) function,+ typename enable_if<+ !can_query<Executor, execution::allocator_t<void> >::value+ >::type* = 0);++ // Request invocation of the given function.+ template <typename Executor, typename Function, typename Allocator>+ static void dispatch(const implementation_type& impl, Executor& ex,+ ASIO_MOVE_ARG(Function) function, const Allocator& a);++ // Request invocation of the given function and return immediately.+ template <typename Executor, typename Function, typename Allocator>+ static void post(const implementation_type& impl, Executor& ex,+ ASIO_MOVE_ARG(Function) function, const Allocator& a);++ // Request invocation of the given function and return immediately.+ template <typename Executor, typename Function, typename Allocator>+ static void defer(const implementation_type& impl, Executor& ex,+ ASIO_MOVE_ARG(Function) function, const Allocator& a);++ // Determine whether the strand is running in the current thread.+ ASIO_DECL static bool running_in_this_thread(+ const implementation_type& impl);++private:+ friend class strand_impl;+ template <typename F, typename Allocator> class allocator_binder;+ template <typename Executor, typename = void> class invoker;++ // Adds a function to the strand. Returns true if it acquires the lock.+ ASIO_DECL static bool enqueue(const implementation_type& impl,+ scheduler_operation* op);++ // Helper function to request invocation of the given function.+ template <typename Executor, typename Function, typename Allocator>+ static void do_execute(const implementation_type& impl, Executor& ex,+ ASIO_MOVE_ARG(Function) function, const Allocator& a);++ // Mutex to protect access to the service-wide state.+ mutex mutex_;++ // Number of mutexes shared between all strand objects.+ enum { num_mutexes = 193 };++ // Pool of mutexes.+ scoped_ptr<mutex> mutexes_[num_mutexes];++ // Extra value used when hashing to prevent recycled memory locations from+ // getting the same mutex.+ std::size_t salt_;++ // The head of a linked list of all implementations.+ strand_impl* impl_list_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/detail/impl/strand_executor_service.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/strand_executor_service.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/strand_service.hpp view
@@ -0,0 +1,145 @@+//+// detail/strand_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STRAND_SERVICE_HPP+#define ASIO_DETAIL_STRAND_SERVICE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/io_context.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/operation.hpp"+#include "asio/detail/scoped_ptr.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Default service implementation for a strand.+class strand_service+ : public asio::detail::service_base<strand_service>+{+private:+ // Helper class to re-post the strand on exit.+ struct on_do_complete_exit;++ // Helper class to re-post the strand on exit.+ struct on_dispatch_exit;++public:++ // The underlying implementation of a strand.+ class strand_impl+ : public operation+ {+ public:+ strand_impl();++ private:+ // Only this service will have access to the internal values.+ friend class strand_service;+ friend struct on_do_complete_exit;+ friend struct on_dispatch_exit;++ // Mutex to protect access to internal data.+ asio::detail::mutex mutex_;++ // Indicates whether the strand is currently "locked" by a handler. This+ // means that there is a handler upcall in progress, or that the strand+ // itself has been scheduled in order to invoke some pending handlers.+ bool locked_;++ // The handlers that are waiting on the strand but should not be run until+ // after the next time the strand is scheduled. This queue must only be+ // modified while the mutex is locked.+ op_queue<operation> waiting_queue_;++ // The handlers that are ready to be run. Logically speaking, these are the+ // handlers that hold the strand's lock. The ready queue is only modified+ // from within the strand and so may be accessed without locking the mutex.+ op_queue<operation> ready_queue_;+ };++ typedef strand_impl* implementation_type;++ // Construct a new strand service for the specified io_context.+ ASIO_DECL explicit strand_service(asio::io_context& io_context);++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Construct a new strand implementation.+ ASIO_DECL void construct(implementation_type& impl);++ // Request the io_context to invoke the given handler.+ template <typename Handler>+ void dispatch(implementation_type& impl, Handler& handler);++ // Request the io_context to invoke the given handler and return immediately.+ template <typename Handler>+ void post(implementation_type& impl, Handler& handler);++ // Determine whether the strand is running in the current thread.+ ASIO_DECL bool running_in_this_thread(+ const implementation_type& impl) const;++private:+ // Helper function to dispatch a handler. Returns true if the handler should+ // be dispatched immediately.+ ASIO_DECL bool do_dispatch(implementation_type& impl, operation* op);++ // Helper fiunction to post a handler.+ ASIO_DECL void do_post(implementation_type& impl,+ operation* op, bool is_continuation);++ ASIO_DECL static void do_complete(void* owner,+ operation* base, const asio::error_code& ec,+ std::size_t bytes_transferred);++ // The io_context used to obtain an I/O executor.+ io_context& io_context_;++ // The io_context implementation used to post completions.+ io_context_impl& io_context_impl_;++ // Mutex to protect access to the array of implementations.+ asio::detail::mutex mutex_;++ // Number of implementations shared between all strand objects.+#if defined(ASIO_STRAND_IMPLEMENTATIONS)+ enum { num_implementations = ASIO_STRAND_IMPLEMENTATIONS };+#else // defined(ASIO_STRAND_IMPLEMENTATIONS)+ enum { num_implementations = 193 };+#endif // defined(ASIO_STRAND_IMPLEMENTATIONS)++ // Pool of implementations.+ scoped_ptr<strand_impl> implementations_[num_implementations];++ // Extra value used when hashing to prevent recycled memory locations from+ // getting the same strand implementation.+ std::size_t salt_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/detail/impl/strand_service.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/strand_service.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_STRAND_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/string_view.hpp view
@@ -0,0 +1,47 @@+//+// detail/string_view.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STRING_VIEW_HPP+#define ASIO_DETAIL_STRING_VIEW_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_STRING_VIEW)++#if defined(ASIO_HAS_STD_STRING_VIEW)+# include <string_view>+#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)+# include <experimental/string_view>+#else // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)+# error ASIO_HAS_STRING_VIEW is set but no string_view is available+#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)++namespace asio {++#if defined(ASIO_HAS_STD_STRING_VIEW)+using std::basic_string_view;+using std::string_view;+#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)+using std::experimental::basic_string_view;+using std::experimental::string_view;+#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)++} // namespace asio++# define ASIO_STRING_VIEW_PARAM asio::string_view+#else // defined(ASIO_HAS_STRING_VIEW)+# define ASIO_STRING_VIEW_PARAM const std::string&+#endif // defined(ASIO_HAS_STRING_VIEW)++#endif // ASIO_DETAIL_STRING_VIEW_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/thread.hpp view
@@ -0,0 +1,60 @@+//+// detail/thread.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_THREAD_HPP+#define ASIO_DETAIL_THREAD_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_THREADS)+# include "asio/detail/null_thread.hpp"+#elif defined(ASIO_WINDOWS)+# if defined(UNDER_CE)+# include "asio/detail/wince_thread.hpp"+# elif defined(ASIO_WINDOWS_APP)+# include "asio/detail/winapp_thread.hpp"+# else+# include "asio/detail/win_thread.hpp"+# endif+#elif defined(ASIO_HAS_PTHREADS)+# include "asio/detail/posix_thread.hpp"+#elif defined(ASIO_HAS_STD_THREAD)+# include "asio/detail/std_thread.hpp"+#else+# error Only Windows, POSIX and std::thread are supported!+#endif++namespace asio {+namespace detail {++#if !defined(ASIO_HAS_THREADS)+typedef null_thread thread;+#elif defined(ASIO_WINDOWS)+# if defined(UNDER_CE)+typedef wince_thread thread;+# elif defined(ASIO_WINDOWS_APP)+typedef winapp_thread thread;+# else+typedef win_thread thread;+# endif+#elif defined(ASIO_HAS_PTHREADS)+typedef posix_thread thread;+#elif defined(ASIO_HAS_STD_THREAD)+typedef std_thread thread;+#endif++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_THREAD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/thread_context.hpp view
@@ -0,0 +1,42 @@+//+// detail/thread_context.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_THREAD_CONTEXT_HPP+#define ASIO_DETAIL_THREAD_CONTEXT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include <climits>+#include <cstddef>+#include "asio/detail/call_stack.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class thread_info_base;++// Base class for things that manage threads (scheduler, win_iocp_io_context).+class thread_context+{+public:+ // Per-thread call stack to track the state of each thread in the context.+ typedef call_stack<thread_context, thread_info_base> thread_call_stack;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_THREAD_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/thread_group.hpp view
@@ -0,0 +1,95 @@+//+// detail/thread_group.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_THREAD_GROUP_HPP+#define ASIO_DETAIL_THREAD_GROUP_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/scoped_ptr.hpp"+#include "asio/detail/thread.hpp"++namespace asio {+namespace detail {++class thread_group+{+public:+ // Constructor initialises an empty thread group.+ thread_group()+ : first_(0)+ {+ }++ // Destructor joins any remaining threads in the group.+ ~thread_group()+ {+ join();+ }++ // Create a new thread in the group.+ template <typename Function>+ void create_thread(Function f)+ {+ first_ = new item(f, first_);+ }++ // Create new threads in the group.+ template <typename Function>+ void create_threads(Function f, std::size_t num_threads)+ {+ for (std::size_t i = 0; i < num_threads; ++i)+ create_thread(f);+ }++ // Wait for all threads in the group to exit.+ void join()+ {+ while (first_)+ {+ first_->thread_.join();+ item* tmp = first_;+ first_ = first_->next_;+ delete tmp;+ }+ }++ // Test whether the group is empty.+ bool empty() const+ {+ return first_ == 0;+ }++private:+ // Structure used to track a single thread in the group.+ struct item+ {+ template <typename Function>+ explicit item(Function f, item* next)+ : thread_(f),+ next_(next)+ {+ }++ asio::detail::thread thread_;+ item* next_;+ };++ // The first thread in the group.+ item* first_;+};++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_THREAD_GROUP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/thread_info_base.hpp view
@@ -0,0 +1,189 @@+//+// detail/thread_info_base.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_THREAD_INFO_BASE_HPP+#define ASIO_DETAIL_THREAD_INFO_BASE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <climits>+#include <cstddef>+#include "asio/detail/noncopyable.hpp"++#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \+ && !defined(ASIO_NO_EXCEPTIONS)+# include <exception>+# include "asio/multiple_exceptions.hpp"+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ // && !defined(ASIO_NO_EXCEPTIONS)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class thread_info_base+ : private noncopyable+{+public:+ struct default_tag+ {+ enum { mem_index = 0 };+ };++ struct awaitable_frame_tag+ {+ enum { mem_index = 1 };+ };++ struct executor_function_tag+ {+ enum { mem_index = 2 };+ };++ thread_info_base()+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \+ && !defined(ASIO_NO_EXCEPTIONS)+ : has_pending_exception_(0)+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ // && !defined(ASIO_NO_EXCEPTIONS)+ {+ for (int i = 0; i < max_mem_index; ++i)+ {+ // The following test for non-null pointers is technically redundant, but+ // it is significantly faster when using a tight io_context::poll() loop+ // in latency sensitive applications.+ if (reusable_memory_[i])+ reusable_memory_[i] = 0;+ }+ }++ ~thread_info_base()+ {+ for (int i = 0; i < max_mem_index; ++i)+ ::operator delete(reusable_memory_[i]);+ }++ static void* allocate(thread_info_base* this_thread, std::size_t size)+ {+ return allocate(default_tag(), this_thread, size);+ }++ static void deallocate(thread_info_base* this_thread,+ void* pointer, std::size_t size)+ {+ deallocate(default_tag(), this_thread, pointer, size);+ }++ template <typename Purpose>+ static void* allocate(Purpose, thread_info_base* this_thread,+ std::size_t size)+ {+ std::size_t chunks = (size + chunk_size - 1) / chunk_size;++ if (this_thread && this_thread->reusable_memory_[Purpose::mem_index])+ {+ void* const pointer = this_thread->reusable_memory_[Purpose::mem_index];+ this_thread->reusable_memory_[Purpose::mem_index] = 0;++ unsigned char* const mem = static_cast<unsigned char*>(pointer);+ if (static_cast<std::size_t>(mem[0]) >= chunks)+ {+ mem[size] = mem[0];+ return pointer;+ }++ ::operator delete(pointer);+ }++ void* const pointer = ::operator new(chunks * chunk_size + 1);+ unsigned char* const mem = static_cast<unsigned char*>(pointer);+ mem[size] = (chunks <= UCHAR_MAX) ? static_cast<unsigned char>(chunks) : 0;+ return pointer;+ }++ template <typename Purpose>+ static void deallocate(Purpose, thread_info_base* this_thread,+ void* pointer, std::size_t size)+ {+ if (size <= chunk_size * UCHAR_MAX)+ {+ if (this_thread && this_thread->reusable_memory_[Purpose::mem_index] == 0)+ {+ unsigned char* const mem = static_cast<unsigned char*>(pointer);+ mem[0] = mem[size];+ this_thread->reusable_memory_[Purpose::mem_index] = pointer;+ return;+ }+ }++ ::operator delete(pointer);+ }++ void capture_current_exception()+ {+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \+ && !defined(ASIO_NO_EXCEPTIONS)+ switch (has_pending_exception_)+ {+ case 0:+ has_pending_exception_ = 1;+ pending_exception_ = std::current_exception();+ break;+ case 1:+ has_pending_exception_ = 2;+ pending_exception_ =+ std::make_exception_ptr<multiple_exceptions>(+ multiple_exceptions(pending_exception_));+ default:+ break;+ }+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ // && !defined(ASIO_NO_EXCEPTIONS)+ }++ void rethrow_pending_exception()+ {+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \+ && !defined(ASIO_NO_EXCEPTIONS)+ if (has_pending_exception_ > 0)+ {+ has_pending_exception_ = 0;+ std::exception_ptr ex(+ ASIO_MOVE_CAST(std::exception_ptr)(+ pending_exception_));+ std::rethrow_exception(ex);+ }+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ // && !defined(ASIO_NO_EXCEPTIONS)+ }++private:+ enum { chunk_size = 4 };+ enum { max_mem_index = 3 };+ void* reusable_memory_[max_mem_index];++#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \+ && !defined(ASIO_NO_EXCEPTIONS)+ int has_pending_exception_;+ std::exception_ptr pending_exception_;+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ // && !defined(ASIO_NO_EXCEPTIONS)+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_THREAD_INFO_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/throw_error.hpp view
@@ -0,0 +1,53 @@+//+// detail/throw_error.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_THROW_ERROR_HPP+#define ASIO_DETAIL_THROW_ERROR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/error_code.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++ASIO_DECL void do_throw_error(const asio::error_code& err);++ASIO_DECL void do_throw_error(const asio::error_code& err,+ const char* location);++inline void throw_error(const asio::error_code& err)+{+ if (err)+ do_throw_error(err);+}++inline void throw_error(const asio::error_code& err,+ const char* location)+{+ if (err)+ do_throw_error(err, location);+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/throw_error.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_THROW_ERROR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/throw_exception.hpp view
@@ -0,0 +1,51 @@+//+// detail/throw_exception.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_THROW_EXCEPTION_HPP+#define ASIO_DETAIL_THROW_EXCEPTION_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_BOOST_THROW_EXCEPTION)+# include <boost/throw_exception.hpp>+#endif // defined(ASIO_BOOST_THROW_EXCEPTION)++namespace asio {+namespace detail {++#if defined(ASIO_HAS_BOOST_THROW_EXCEPTION)+using boost::throw_exception;+#else // defined(ASIO_HAS_BOOST_THROW_EXCEPTION)++// Declare the throw_exception function for all targets.+template <typename Exception>+void throw_exception(const Exception& e);++// Only define the throw_exception function when exceptions are enabled.+// Otherwise, it is up to the application to provide a definition of this+// function.+# if !defined(ASIO_NO_EXCEPTIONS)+template <typename Exception>+void throw_exception(const Exception& e)+{+ throw e;+}+# endif // !defined(ASIO_NO_EXCEPTIONS)++#endif // defined(ASIO_HAS_BOOST_THROW_EXCEPTION)++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_THROW_EXCEPTION_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/timer_queue.hpp view
@@ -0,0 +1,360 @@+//+// detail/timer_queue.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TIMER_QUEUE_HPP+#define ASIO_DETAIL_TIMER_QUEUE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include <vector>+#include "asio/detail/cstdint.hpp"+#include "asio/detail/date_time_fwd.hpp"+#include "asio/detail/limits.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/timer_queue_base.hpp"+#include "asio/detail/wait_op.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Time_Traits>+class timer_queue+ : public timer_queue_base+{+public:+ // The time type.+ typedef typename Time_Traits::time_type time_type;++ // The duration type.+ typedef typename Time_Traits::duration_type duration_type;++ // Per-timer data.+ class per_timer_data+ {+ public:+ per_timer_data() :+ heap_index_((std::numeric_limits<std::size_t>::max)()),+ next_(0), prev_(0)+ {+ }++ private:+ friend class timer_queue;++ // The operations waiting on the timer.+ op_queue<wait_op> op_queue_;++ // The index of the timer in the heap.+ std::size_t heap_index_;++ // Pointers to adjacent timers in a linked list.+ per_timer_data* next_;+ per_timer_data* prev_;+ };++ // Constructor.+ timer_queue()+ : timers_(),+ heap_()+ {+ }++ // Add a new timer to the queue. Returns true if this is the timer that is+ // earliest in the queue, in which case the reactor's event demultiplexing+ // function call may need to be interrupted and restarted.+ bool enqueue_timer(const time_type& time, per_timer_data& timer, wait_op* op)+ {+ // Enqueue the timer object.+ if (timer.prev_ == 0 && &timer != timers_)+ {+ if (this->is_positive_infinity(time))+ {+ // No heap entry is required for timers that never expire.+ timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();+ }+ else+ {+ // Put the new timer at the correct position in the heap. This is done+ // first since push_back() can throw due to allocation failure.+ timer.heap_index_ = heap_.size();+ heap_entry entry = { time, &timer };+ heap_.push_back(entry);+ up_heap(heap_.size() - 1);+ }++ // Insert the new timer into the linked list of active timers.+ timer.next_ = timers_;+ timer.prev_ = 0;+ if (timers_)+ timers_->prev_ = &timer;+ timers_ = &timer;+ }++ // Enqueue the individual timer operation.+ timer.op_queue_.push(op);++ // Interrupt reactor only if newly added timer is first to expire.+ return timer.heap_index_ == 0 && timer.op_queue_.front() == op;+ }++ // Whether there are no timers in the queue.+ virtual bool empty() const+ {+ return timers_ == 0;+ }++ // Get the time for the timer that is earliest in the queue.+ virtual long wait_duration_msec(long max_duration) const+ {+ if (heap_.empty())+ return max_duration;++ return this->to_msec(+ Time_Traits::to_posix_duration(+ Time_Traits::subtract(heap_[0].time_, Time_Traits::now())),+ max_duration);+ }++ // Get the time for the timer that is earliest in the queue.+ virtual long wait_duration_usec(long max_duration) const+ {+ if (heap_.empty())+ return max_duration;++ return this->to_usec(+ Time_Traits::to_posix_duration(+ Time_Traits::subtract(heap_[0].time_, Time_Traits::now())),+ max_duration);+ }++ // Dequeue all timers not later than the current time.+ virtual void get_ready_timers(op_queue<operation>& ops)+ {+ if (!heap_.empty())+ {+ const time_type now = Time_Traits::now();+ while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_))+ {+ per_timer_data* timer = heap_[0].timer_;+ ops.push(timer->op_queue_);+ remove_timer(*timer);+ }+ }+ }++ // Dequeue all timers.+ virtual void get_all_timers(op_queue<operation>& ops)+ {+ while (timers_)+ {+ per_timer_data* timer = timers_;+ timers_ = timers_->next_;+ ops.push(timer->op_queue_);+ timer->next_ = 0;+ timer->prev_ = 0;+ }++ heap_.clear();+ }++ // Cancel and dequeue operations for the given timer.+ std::size_t cancel_timer(per_timer_data& timer, op_queue<operation>& ops,+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)())+ {+ std::size_t num_cancelled = 0;+ if (timer.prev_ != 0 || &timer == timers_)+ {+ while (wait_op* op = (num_cancelled != max_cancelled)+ ? timer.op_queue_.front() : 0)+ {+ op->ec_ = asio::error::operation_aborted;+ timer.op_queue_.pop();+ ops.push(op);+ ++num_cancelled;+ }+ if (timer.op_queue_.empty())+ remove_timer(timer);+ }+ return num_cancelled;+ }++ // Move operations from one timer to another, empty timer.+ void move_timer(per_timer_data& target, per_timer_data& source)+ {+ target.op_queue_.push(source.op_queue_);++ target.heap_index_ = source.heap_index_;+ source.heap_index_ = (std::numeric_limits<std::size_t>::max)();++ if (target.heap_index_ < heap_.size())+ heap_[target.heap_index_].timer_ = ⌖++ if (timers_ == &source)+ timers_ = ⌖+ if (source.prev_)+ source.prev_->next_ = ⌖+ if (source.next_)+ source.next_->prev_= ⌖+ target.next_ = source.next_;+ target.prev_ = source.prev_;+ source.next_ = 0;+ source.prev_ = 0;+ }++private:+ // Move the item at the given index up the heap to its correct position.+ void up_heap(std::size_t index)+ {+ while (index > 0)+ {+ std::size_t parent = (index - 1) / 2;+ if (!Time_Traits::less_than(heap_[index].time_, heap_[parent].time_))+ break;+ swap_heap(index, parent);+ index = parent;+ }+ }++ // Move the item at the given index down the heap to its correct position.+ void down_heap(std::size_t index)+ {+ std::size_t child = index * 2 + 1;+ while (child < heap_.size())+ {+ std::size_t min_child = (child + 1 == heap_.size()+ || Time_Traits::less_than(+ heap_[child].time_, heap_[child + 1].time_))+ ? child : child + 1;+ if (Time_Traits::less_than(heap_[index].time_, heap_[min_child].time_))+ break;+ swap_heap(index, min_child);+ index = min_child;+ child = index * 2 + 1;+ }+ }++ // Swap two entries in the heap.+ void swap_heap(std::size_t index1, std::size_t index2)+ {+ heap_entry tmp = heap_[index1];+ heap_[index1] = heap_[index2];+ heap_[index2] = tmp;+ heap_[index1].timer_->heap_index_ = index1;+ heap_[index2].timer_->heap_index_ = index2;+ }++ // Remove a timer from the heap and list of timers.+ void remove_timer(per_timer_data& timer)+ {+ // Remove the timer from the heap.+ std::size_t index = timer.heap_index_;+ if (!heap_.empty() && index < heap_.size())+ {+ if (index == heap_.size() - 1)+ {+ timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();+ heap_.pop_back();+ }+ else+ {+ swap_heap(index, heap_.size() - 1);+ timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();+ heap_.pop_back();+ if (index > 0 && Time_Traits::less_than(+ heap_[index].time_, heap_[(index - 1) / 2].time_))+ up_heap(index);+ else+ down_heap(index);+ }+ }++ // Remove the timer from the linked list of active timers.+ if (timers_ == &timer)+ timers_ = timer.next_;+ if (timer.prev_)+ timer.prev_->next_ = timer.next_;+ if (timer.next_)+ timer.next_->prev_= timer.prev_;+ timer.next_ = 0;+ timer.prev_ = 0;+ }++ // Determine if the specified absolute time is positive infinity.+ template <typename Time_Type>+ static bool is_positive_infinity(const Time_Type&)+ {+ return false;+ }++ // Determine if the specified absolute time is positive infinity.+ template <typename T, typename TimeSystem>+ static bool is_positive_infinity(+ const boost::date_time::base_time<T, TimeSystem>& time)+ {+ return time.is_pos_infinity();+ }++ // Helper function to convert a duration into milliseconds.+ template <typename Duration>+ long to_msec(const Duration& d, long max_duration) const+ {+ if (d.ticks() <= 0)+ return 0;+ int64_t msec = d.total_milliseconds();+ if (msec == 0)+ return 1;+ if (msec > max_duration)+ return max_duration;+ return static_cast<long>(msec);+ }++ // Helper function to convert a duration into microseconds.+ template <typename Duration>+ long to_usec(const Duration& d, long max_duration) const+ {+ if (d.ticks() <= 0)+ return 0;+ int64_t usec = d.total_microseconds();+ if (usec == 0)+ return 1;+ if (usec > max_duration)+ return max_duration;+ return static_cast<long>(usec);+ }++ // The head of a linked list of all active timers.+ per_timer_data* timers_;++ struct heap_entry+ {+ // The time when the timer should fire.+ time_type time_;++ // The associated timer with enqueued operations.+ per_timer_data* timer_;+ };++ // The heap of timers, with the earliest timer at the front.+ std::vector<heap_entry> heap_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_TIMER_QUEUE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/timer_queue_base.hpp view
@@ -0,0 +1,68 @@+//+// detail/timer_queue_base.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TIMER_QUEUE_BASE_HPP+#define ASIO_DETAIL_TIMER_QUEUE_BASE_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/noncopyable.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/operation.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class timer_queue_base+ : private noncopyable+{+public:+ // Constructor.+ timer_queue_base() : next_(0) {}++ // Destructor.+ virtual ~timer_queue_base() {}++ // Whether there are no timers in the queue.+ virtual bool empty() const = 0;++ // Get the time to wait until the next timer.+ virtual long wait_duration_msec(long max_duration) const = 0;++ // Get the time to wait until the next timer.+ virtual long wait_duration_usec(long max_duration) const = 0;++ // Dequeue all ready timers.+ virtual void get_ready_timers(op_queue<operation>& ops) = 0;++ // Dequeue all timers.+ virtual void get_all_timers(op_queue<operation>& ops) = 0;++private:+ friend class timer_queue_set;++ // Next timer queue in the set.+ timer_queue_base* next_;+};++template <typename Time_Traits>+class timer_queue;++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/timer_queue_ptime.hpp view
@@ -0,0 +1,99 @@+//+// detail/timer_queue_ptime.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TIMER_QUEUE_PTIME_HPP+#define ASIO_DETAIL_TIMER_QUEUE_PTIME_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_BOOST_DATE_TIME)++#include "asio/time_traits.hpp"+#include "asio/detail/timer_queue.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++struct forwarding_posix_time_traits : time_traits<boost::posix_time::ptime> {};++// Template specialisation for the commonly used instantation.+template <>+class timer_queue<time_traits<boost::posix_time::ptime> >+ : public timer_queue_base+{+public:+ // The time type.+ typedef boost::posix_time::ptime time_type;++ // The duration type.+ typedef boost::posix_time::time_duration duration_type;++ // Per-timer data.+ typedef timer_queue<forwarding_posix_time_traits>::per_timer_data+ per_timer_data;++ // Constructor.+ ASIO_DECL timer_queue();++ // Destructor.+ ASIO_DECL virtual ~timer_queue();++ // Add a new timer to the queue. Returns true if this is the timer that is+ // earliest in the queue, in which case the reactor's event demultiplexing+ // function call may need to be interrupted and restarted.+ ASIO_DECL bool enqueue_timer(const time_type& time,+ per_timer_data& timer, wait_op* op);++ // Whether there are no timers in the queue.+ ASIO_DECL virtual bool empty() const;++ // Get the time for the timer that is earliest in the queue.+ ASIO_DECL virtual long wait_duration_msec(long max_duration) const;++ // Get the time for the timer that is earliest in the queue.+ ASIO_DECL virtual long wait_duration_usec(long max_duration) const;++ // Dequeue all timers not later than the current time.+ ASIO_DECL virtual void get_ready_timers(op_queue<operation>& ops);++ // Dequeue all timers.+ ASIO_DECL virtual void get_all_timers(op_queue<operation>& ops);++ // Cancel and dequeue operations for the given timer.+ ASIO_DECL std::size_t cancel_timer(+ per_timer_data& timer, op_queue<operation>& ops,+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());++ // Move operations from one timer to another, empty timer.+ ASIO_DECL void move_timer(per_timer_data& target,+ per_timer_data& source);++private:+ timer_queue<forwarding_posix_time_traits> impl_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/timer_queue_ptime.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_BOOST_DATE_TIME)++#endif // ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/timer_queue_set.hpp view
@@ -0,0 +1,66 @@+//+// detail/timer_queue_set.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TIMER_QUEUE_SET_HPP+#define ASIO_DETAIL_TIMER_QUEUE_SET_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/timer_queue_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class timer_queue_set+{+public:+ // Constructor.+ ASIO_DECL timer_queue_set();++ // Add a timer queue to the set.+ ASIO_DECL void insert(timer_queue_base* q);++ // Remove a timer queue from the set.+ ASIO_DECL void erase(timer_queue_base* q);++ // Determine whether all queues are empty.+ ASIO_DECL bool all_empty() const;++ // Get the wait duration in milliseconds.+ ASIO_DECL long wait_duration_msec(long max_duration) const;++ // Get the wait duration in microseconds.+ ASIO_DECL long wait_duration_usec(long max_duration) const;++ // Dequeue all ready timers.+ ASIO_DECL void get_ready_timers(op_queue<operation>& ops);++ // Dequeue all timers.+ ASIO_DECL void get_all_timers(op_queue<operation>& ops);++private:+ timer_queue_base* first_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/timer_queue_set.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_DETAIL_TIMER_QUEUE_SET_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/timer_scheduler.hpp view
@@ -0,0 +1,35 @@+//+// detail/timer_scheduler.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TIMER_SCHEDULER_HPP+#define ASIO_DETAIL_TIMER_SCHEDULER_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/timer_scheduler_fwd.hpp"++#if defined(ASIO_WINDOWS_RUNTIME)+# include "asio/detail/winrt_timer_scheduler.hpp"+#elif defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#elif defined(ASIO_HAS_EPOLL)+# include "asio/detail/epoll_reactor.hpp"+#elif defined(ASIO_HAS_KQUEUE)+# include "asio/detail/kqueue_reactor.hpp"+#elif defined(ASIO_HAS_DEV_POLL)+# include "asio/detail/dev_poll_reactor.hpp"+#else+# include "asio/detail/select_reactor.hpp"+#endif++#endif // ASIO_DETAIL_TIMER_SCHEDULER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/timer_scheduler_fwd.hpp view
@@ -0,0 +1,40 @@+//+// detail/timer_scheduler_fwd.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TIMER_SCHEDULER_FWD_HPP+#define ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++namespace asio {+namespace detail {++#if defined(ASIO_WINDOWS_RUNTIME)+typedef class winrt_timer_scheduler timer_scheduler;+#elif defined(ASIO_HAS_IOCP)+typedef class win_iocp_io_context timer_scheduler;+#elif defined(ASIO_HAS_EPOLL)+typedef class epoll_reactor timer_scheduler;+#elif defined(ASIO_HAS_KQUEUE)+typedef class kqueue_reactor timer_scheduler;+#elif defined(ASIO_HAS_DEV_POLL)+typedef class dev_poll_reactor timer_scheduler;+#else+typedef class select_reactor timer_scheduler;+#endif++} // namespace detail+} // namespace asio++#endif // ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/tss_ptr.hpp view
@@ -0,0 +1,69 @@+//+// detail/tss_ptr.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TSS_PTR_HPP+#define ASIO_DETAIL_TSS_PTR_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_THREADS)+# include "asio/detail/null_tss_ptr.hpp"+#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)+# include "asio/detail/keyword_tss_ptr.hpp"+#elif defined(ASIO_WINDOWS)+# include "asio/detail/win_tss_ptr.hpp"+#elif defined(ASIO_HAS_PTHREADS)+# include "asio/detail/posix_tss_ptr.hpp"+#else+# error Only Windows and POSIX are supported!+#endif++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename T>+class tss_ptr+#if !defined(ASIO_HAS_THREADS)+ : public null_tss_ptr<T>+#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)+ : public keyword_tss_ptr<T>+#elif defined(ASIO_WINDOWS)+ : public win_tss_ptr<T>+#elif defined(ASIO_HAS_PTHREADS)+ : public posix_tss_ptr<T>+#endif+{+public:+ void operator=(T* value)+ {+#if !defined(ASIO_HAS_THREADS)+ null_tss_ptr<T>::operator=(value);+#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)+ keyword_tss_ptr<T>::operator=(value);+#elif defined(ASIO_WINDOWS)+ win_tss_ptr<T>::operator=(value);+#elif defined(ASIO_HAS_PTHREADS)+ posix_tss_ptr<T>::operator=(value);+#endif+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_TSS_PTR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/type_traits.hpp view
@@ -0,0 +1,148 @@+//+// detail/type_traits.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TYPE_TRAITS_HPP+#define ASIO_DETAIL_TYPE_TRAITS_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_STD_TYPE_TRAITS)+# include <type_traits>+#else // defined(ASIO_HAS_STD_TYPE_TRAITS)+# include <boost/type_traits/add_const.hpp>+# include <boost/type_traits/add_lvalue_reference.hpp>+# include <boost/type_traits/aligned_storage.hpp>+# include <boost/type_traits/alignment_of.hpp>+# include <boost/type_traits/conditional.hpp>+# include <boost/type_traits/decay.hpp>+# include <boost/type_traits/has_nothrow_copy.hpp>+# include <boost/type_traits/has_nothrow_destructor.hpp>+# include <boost/type_traits/integral_constant.hpp>+# include <boost/type_traits/is_base_of.hpp>+# include <boost/type_traits/is_class.hpp>+# include <boost/type_traits/is_const.hpp>+# include <boost/type_traits/is_convertible.hpp>+# include <boost/type_traits/is_constructible.hpp>+# include <boost/type_traits/is_copy_constructible.hpp>+# include <boost/type_traits/is_destructible.hpp>+# include <boost/type_traits/is_function.hpp>+# include <boost/type_traits/is_object.hpp>+# include <boost/type_traits/is_same.hpp>+# include <boost/type_traits/remove_cv.hpp>+# include <boost/type_traits/remove_pointer.hpp>+# include <boost/type_traits/remove_reference.hpp>+# include <boost/utility/declval.hpp>+# include <boost/utility/enable_if.hpp>+# include <boost/utility/result_of.hpp>+#endif // defined(ASIO_HAS_STD_TYPE_TRAITS)++namespace asio {++#if defined(ASIO_HAS_STD_TYPE_TRAITS)+using std::add_const;+using std::add_lvalue_reference;+using std::aligned_storage;+using std::alignment_of;+using std::conditional;+using std::decay;+using std::declval;+using std::enable_if;+using std::false_type;+using std::integral_constant;+using std::is_base_of;+using std::is_class;+using std::is_const;+using std::is_constructible;+using std::is_convertible;+using std::is_copy_constructible;+using std::is_destructible;+using std::is_function;+using std::is_move_constructible;+using std::is_nothrow_copy_constructible;+using std::is_nothrow_destructible;+using std::is_object;+using std::is_reference;+using std::is_same;+using std::is_scalar;+using std::remove_cv;+template <typename T>+struct remove_cvref : remove_cv<typename std::remove_reference<T>::type> {};+using std::remove_pointer;+using std::remove_reference;+#if defined(ASIO_HAS_STD_INVOKE_RESULT)+template <typename> struct result_of;+template <typename F, typename... Args>+struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};+#else // defined(ASIO_HAS_STD_INVOKE_RESULT)+using std::result_of;+#endif // defined(ASIO_HAS_STD_INVOKE_RESULT)+using std::true_type;+#else // defined(ASIO_HAS_STD_TYPE_TRAITS)+using boost::add_const;+using boost::add_lvalue_reference;+using boost::aligned_storage;+using boost::alignment_of;+template <bool Condition, typename Type = void>+struct enable_if : boost::enable_if_c<Condition, Type> {};+using boost::conditional;+using boost::decay;+using boost::declval;+using boost::false_type;+using boost::integral_constant;+using boost::is_base_of;+using boost::is_class;+using boost::is_const;+using boost::is_constructible;+using boost::is_convertible;+using boost::is_copy_constructible;+using boost::is_destructible;+using boost::is_function;+#if defined(ASIO_HAS_MOVE)+template <typename T>+struct is_move_constructible : false_type {};+#else // defined(ASIO_HAS_MOVE)+template <typename T>+struct is_move_constructible : is_copy_constructible<T> {};+#endif // defined(ASIO_HAS_MOVE)+template <typename T>+struct is_nothrow_copy_constructible : boost::has_nothrow_copy<T> {};+template <typename T>+struct is_nothrow_destructible : boost::has_nothrow_destructor<T> {};+using boost::is_object;+using boost::is_reference;+using boost::is_same;+using boost::is_scalar;+using boost::remove_cv;+template <typename T>+struct remove_cvref : remove_cv<typename boost::remove_reference<T>::type> {};+using boost::remove_pointer;+using boost::remove_reference;+using boost::result_of;+using boost::true_type;+#endif // defined(ASIO_HAS_STD_TYPE_TRAITS)++template <typename> struct void_type { typedef void type; };++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename...> struct conjunction : true_type {};+template <typename T> struct conjunction<T> : T {};+template <typename Head, typename... Tail> struct conjunction<Head, Tail...> :+ conditional<Head::value, conjunction<Tail...>, Head>::type {};++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++} // namespace asio++#endif // ASIO_DETAIL_TYPE_TRAITS_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/variadic_templates.hpp view
@@ -0,0 +1,294 @@+//+// detail/variadic_templates.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_VARIADIC_TEMPLATES_HPP+#define ASIO_DETAIL_VARIADIC_TEMPLATES_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_VARIADIC_TEMPLATES)++# define ASIO_VARIADIC_TPARAMS(n) ASIO_VARIADIC_TPARAMS_##n++# define ASIO_VARIADIC_TPARAMS_1 \+ typename T1+# define ASIO_VARIADIC_TPARAMS_2 \+ typename T1, typename T2+# define ASIO_VARIADIC_TPARAMS_3 \+ typename T1, typename T2, typename T3+# define ASIO_VARIADIC_TPARAMS_4 \+ typename T1, typename T2, typename T3, typename T4+# define ASIO_VARIADIC_TPARAMS_5 \+ typename T1, typename T2, typename T3, typename T4, typename T5+# define ASIO_VARIADIC_TPARAMS_6 \+ typename T1, typename T2, typename T3, typename T4, typename T5, \+ typename T6+# define ASIO_VARIADIC_TPARAMS_7 \+ typename T1, typename T2, typename T3, typename T4, typename T5, \+ typename T6, typename T7+# define ASIO_VARIADIC_TPARAMS_8 \+ typename T1, typename T2, typename T3, typename T4, typename T5, \+ typename T6, typename T7, typename T8++# define ASIO_VARIADIC_TARGS(n) ASIO_VARIADIC_TARGS_##n++# define ASIO_VARIADIC_TARGS_1 T1+# define ASIO_VARIADIC_TARGS_2 T1, T2+# define ASIO_VARIADIC_TARGS_3 T1, T2, T3+# define ASIO_VARIADIC_TARGS_4 T1, T2, T3, T4+# define ASIO_VARIADIC_TARGS_5 T1, T2, T3, T4, T5+# define ASIO_VARIADIC_TARGS_6 T1, T2, T3, T4, T5, T6+# define ASIO_VARIADIC_TARGS_7 T1, T2, T3, T4, T5, T6, T7+# define ASIO_VARIADIC_TARGS_8 T1, T2, T3, T4, T5, T6, T7, T8++# define ASIO_VARIADIC_BYVAL_PARAMS(n) \+ ASIO_VARIADIC_BYVAL_PARAMS_##n++# define ASIO_VARIADIC_BYVAL_PARAMS_1 T1 x1+# define ASIO_VARIADIC_BYVAL_PARAMS_2 T1 x1, T2 x2+# define ASIO_VARIADIC_BYVAL_PARAMS_3 T1 x1, T2 x2, T3 x3+# define ASIO_VARIADIC_BYVAL_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4+# define ASIO_VARIADIC_BYVAL_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5+# define ASIO_VARIADIC_BYVAL_PARAMS_6 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \+ T6 x6+# define ASIO_VARIADIC_BYVAL_PARAMS_7 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \+ T6 x6, T7 x7+# define ASIO_VARIADIC_BYVAL_PARAMS_8 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \+ T6 x6, T7 x7, T8 x8++# define ASIO_VARIADIC_BYVAL_ARGS(n) \+ ASIO_VARIADIC_BYVAL_ARGS_##n++# define ASIO_VARIADIC_BYVAL_ARGS_1 x1+# define ASIO_VARIADIC_BYVAL_ARGS_2 x1, x2+# define ASIO_VARIADIC_BYVAL_ARGS_3 x1, x2, x3+# define ASIO_VARIADIC_BYVAL_ARGS_4 x1, x2, x3, x4+# define ASIO_VARIADIC_BYVAL_ARGS_5 x1, x2, x3, x4, x5+# define ASIO_VARIADIC_BYVAL_ARGS_6 x1, x2, x3, x4, x5, x6+# define ASIO_VARIADIC_BYVAL_ARGS_7 x1, x2, x3, x4, x5, x6, x7+# define ASIO_VARIADIC_BYVAL_ARGS_8 x1, x2, x3, x4, x5, x6, x7, x8++# define ASIO_VARIADIC_CONSTREF_PARAMS(n) \+ ASIO_VARIADIC_CONSTREF_PARAMS_##n++# define ASIO_VARIADIC_CONSTREF_PARAMS_1 \+ const T1& x1+# define ASIO_VARIADIC_CONSTREF_PARAMS_2 \+ const T1& x1, const T2& x2+# define ASIO_VARIADIC_CONSTREF_PARAMS_3 \+ const T1& x1, const T2& x2, const T3& x3+# define ASIO_VARIADIC_CONSTREF_PARAMS_4 \+ const T1& x1, const T2& x2, const T3& x3, const T4& x4+# define ASIO_VARIADIC_CONSTREF_PARAMS_5 \+ const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5+# define ASIO_VARIADIC_CONSTREF_PARAMS_6 \+ const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \+ const T6& x6+# define ASIO_VARIADIC_CONSTREF_PARAMS_7 \+ const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \+ const T6& x6, const T7& x7+# define ASIO_VARIADIC_CONSTREF_PARAMS_8 \+ const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \+ const T6& x6, const T7& x7, const T8& x8++# define ASIO_VARIADIC_MOVE_PARAMS(n) \+ ASIO_VARIADIC_MOVE_PARAMS_##n++# define ASIO_VARIADIC_MOVE_PARAMS_1 \+ ASIO_MOVE_ARG(T1) x1+# define ASIO_VARIADIC_MOVE_PARAMS_2 \+ ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2+# define ASIO_VARIADIC_MOVE_PARAMS_3 \+ ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \+ ASIO_MOVE_ARG(T3) x3+# define ASIO_VARIADIC_MOVE_PARAMS_4 \+ ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \+ ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4+# define ASIO_VARIADIC_MOVE_PARAMS_5 \+ ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \+ ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \+ ASIO_MOVE_ARG(T5) x5+# define ASIO_VARIADIC_MOVE_PARAMS_6 \+ ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \+ ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \+ ASIO_MOVE_ARG(T5) x5, ASIO_MOVE_ARG(T6) x6+# define ASIO_VARIADIC_MOVE_PARAMS_7 \+ ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \+ ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \+ ASIO_MOVE_ARG(T5) x5, ASIO_MOVE_ARG(T6) x6, \+ ASIO_MOVE_ARG(T7) x7+# define ASIO_VARIADIC_MOVE_PARAMS_8 \+ ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \+ ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \+ ASIO_MOVE_ARG(T5) x5, ASIO_MOVE_ARG(T6) x6, \+ ASIO_MOVE_ARG(T7) x7, ASIO_MOVE_ARG(T8) x8++# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS(n) \+ ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_##n++# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_1 \+ ASIO_MOVE_ARG(T1)+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_2 \+ ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2)+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_3 \+ ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \+ ASIO_MOVE_ARG(T3)+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_4 \+ ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \+ ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4)+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_5 \+ ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \+ ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \+ ASIO_MOVE_ARG(T5)+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_6 \+ ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \+ ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \+ ASIO_MOVE_ARG(T5), ASIO_MOVE_ARG(T6)+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_7 \+ ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \+ ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \+ ASIO_MOVE_ARG(T5), ASIO_MOVE_ARG(T6), \+ ASIO_MOVE_ARG(T7)+# define ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_8 \+ ASIO_MOVE_ARG(T1), ASIO_MOVE_ARG(T2), \+ ASIO_MOVE_ARG(T3), ASIO_MOVE_ARG(T4), \+ ASIO_MOVE_ARG(T5), ASIO_MOVE_ARG(T6), \+ ASIO_MOVE_ARG(T7), ASIO_MOVE_ARG(T8)++# define ASIO_VARIADIC_MOVE_ARGS(n) \+ ASIO_VARIADIC_MOVE_ARGS_##n++# define ASIO_VARIADIC_MOVE_ARGS_1 \+ ASIO_MOVE_CAST(T1)(x1)+# define ASIO_VARIADIC_MOVE_ARGS_2 \+ ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2)+# define ASIO_VARIADIC_MOVE_ARGS_3 \+ ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \+ ASIO_MOVE_CAST(T3)(x3)+# define ASIO_VARIADIC_MOVE_ARGS_4 \+ ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \+ ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4)+# define ASIO_VARIADIC_MOVE_ARGS_5 \+ ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \+ ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \+ ASIO_MOVE_CAST(T5)(x5)+# define ASIO_VARIADIC_MOVE_ARGS_6 \+ ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \+ ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \+ ASIO_MOVE_CAST(T5)(x5), ASIO_MOVE_CAST(T6)(x6)+# define ASIO_VARIADIC_MOVE_ARGS_7 \+ ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \+ ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \+ ASIO_MOVE_CAST(T5)(x5), ASIO_MOVE_CAST(T6)(x6), \+ ASIO_MOVE_CAST(T7)(x7)+# define ASIO_VARIADIC_MOVE_ARGS_8 \+ ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \+ ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \+ ASIO_MOVE_CAST(T5)(x5), ASIO_MOVE_CAST(T6)(x6), \+ ASIO_MOVE_CAST(T7)(x7), ASIO_MOVE_CAST(T8)(x8)++# define ASIO_VARIADIC_DECLVAL(n) \+ ASIO_VARIADIC_DECLVAL_##n++# define ASIO_VARIADIC_DECLVAL_1 \+ declval<T1>()+# define ASIO_VARIADIC_DECLVAL_2 \+ declval<T1>(), declval<T2>()+# define ASIO_VARIADIC_DECLVAL_3 \+ declval<T1>(), declval<T2>(), declval<T3>()+# define ASIO_VARIADIC_DECLVAL_4 \+ declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>()+# define ASIO_VARIADIC_DECLVAL_5 \+ declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \+ declval<T5>()+# define ASIO_VARIADIC_DECLVAL_6 \+ declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \+ declval<T5>(), declval<T6>()+# define ASIO_VARIADIC_DECLVAL_7 \+ declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \+ declval<T5>(), declval<T6>(), declval<T7>()+# define ASIO_VARIADIC_DECLVAL_8 \+ declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \+ declval<T5>(), declval<T6>(), declval<T7>(), declval<T8>()++# define ASIO_VARIADIC_MOVE_DECLVAL(n) \+ ASIO_VARIADIC_MOVE_DECLVAL_##n++# define ASIO_VARIADIC_MOVE_DECLVAL_1 \+ declval<ASIO_MOVE_ARG(T1)>()+# define ASIO_VARIADIC_MOVE_DECLVAL_2 \+ declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>()+# define ASIO_VARIADIC_MOVE_DECLVAL_3 \+ declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \+ declval<ASIO_MOVE_ARG(T3)>()+# define ASIO_VARIADIC_MOVE_DECLVAL_4 \+ declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \+ declval<ASIO_MOVE_ARG(T3)>(), declval<ASIO_MOVE_ARG(T4)>()+# define ASIO_VARIADIC_MOVE_DECLVAL_5 \+ declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \+ declval<ASIO_MOVE_ARG(T3)>(), declval<ASIO_MOVE_ARG(T4)>(), \+ declval<ASIO_MOVE_ARG(T5)>()+# define ASIO_VARIADIC_MOVE_DECLVAL_6 \+ declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \+ declval<ASIO_MOVE_ARG(T3)>(), declval<ASIO_MOVE_ARG(T4)>(), \+ declval<ASIO_MOVE_ARG(T5)>(), declval<ASIO_MOVE_ARG(T6)>()+# define ASIO_VARIADIC_MOVE_DECLVAL_7 \+ declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \+ declval<ASIO_MOVE_ARG(T3)>(), declval<ASIO_MOVE_ARG(T4)>(), \+ declval<ASIO_MOVE_ARG(T5)>(), declval<ASIO_MOVE_ARG(T6)>(), \+ declval<ASIO_MOVE_ARG(T7)>()+# define ASIO_VARIADIC_MOVE_DECLVAL_8 \+ declval<ASIO_MOVE_ARG(T1)>(), declval<ASIO_MOVE_ARG(T2)>(), \+ declval<ASIO_MOVE_ARG(T3)>(), declval<ASIO_MOVE_ARG(T4)>(), \+ declval<ASIO_MOVE_ARG(T5)>(), declval<ASIO_MOVE_ARG(T6)>(), \+ declval<ASIO_MOVE_ARG(T7)>(), declval<ASIO_MOVE_ARG(T8)>()++# define ASIO_VARIADIC_DECAY(n) \+ ASIO_VARIADIC_DECAY_##n++# define ASIO_VARIADIC_DECAY_1 \+ typename decay<T1>::type+# define ASIO_VARIADIC_DECAY_2 \+ typename decay<T1>::type, typename decay<T2>::type+# define ASIO_VARIADIC_DECAY_3 \+ typename decay<T1>::type, typename decay<T2>::type, \+ typename decay<T3>::type+# define ASIO_VARIADIC_DECAY_4 \+ typename decay<T1>::type, typename decay<T2>::type, \+ typename decay<T3>::type, typename decay<T4>::type+# define ASIO_VARIADIC_DECAY_5 \+ typename decay<T1>::type, typename decay<T2>::type, \+ typename decay<T3>::type, typename decay<T4>::type, \+ typename decay<T5>::type+# define ASIO_VARIADIC_DECAY_6 \+ typename decay<T1>::type, typename decay<T2>::type, \+ typename decay<T3>::type, typename decay<T4>::type, \+ typename decay<T5>::type, typename decay<T6>::type+# define ASIO_VARIADIC_DECAY_7 \+ typename decay<T1>::type, typename decay<T2>::type, \+ typename decay<T3>::type, typename decay<T4>::type, \+ typename decay<T5>::type, typename decay<T6>::type, \+ typename decay<T7>::type+# define ASIO_VARIADIC_DECAY_8 \+ typename decay<T1>::type, typename decay<T2>::type, \+ typename decay<T3>::type, typename decay<T4>::type, \+ typename decay<T5>::type, typename decay<T6>::type, \+ typename decay<T7>::type, typename decay<T8>::type++# define ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8)+# define ASIO_VARIADIC_GENERATE_5(m) m(1) m(2) m(3) m(4) m(5)++#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)++#endif // ASIO_DETAIL_VARIADIC_TEMPLATES_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/wait_handler.hpp view
@@ -0,0 +1,90 @@+//+// detail/wait_handler.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WAIT_HANDLER_HPP+#define ASIO_DETAIL_WAIT_HANDLER_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/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/wait_op.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename IoExecutor>+class wait_handler : public wait_op+{+public:+ ASIO_DEFINE_HANDLER_PTR(wait_handler);++ wait_handler(Handler& h, const IoExecutor& io_ex)+ : wait_op(&wait_handler::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(h)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& /*ec*/,+ std::size_t /*bytes_transferred*/)+ {+ // Take ownership of the handler object.+ wait_handler* h(static_cast<wait_handler*>(base));+ ptr p = { asio::detail::addressof(h->handler_), h, h };++ ASIO_HANDLER_COMPLETION((*h));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ h->work_));++ // 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::binder1<Handler, asio::error_code>+ handler(h->handler_, h->ec_);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_WAIT_HANDLER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/wait_op.hpp view
@@ -0,0 +1,45 @@+//+// detail/wait_op.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WAIT_OP_HPP+#define ASIO_DETAIL_WAIT_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/operation.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class wait_op+ : public operation+{+public:+ // The error code to be passed to the completion handler.+ asio::error_code ec_;++protected:+ wait_op(func_type func)+ : operation(func)+ {+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_WAIT_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_event.hpp view
@@ -0,0 +1,164 @@+//+// detail/win_event.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_EVENT_HPP+#define ASIO_DETAIL_WIN_EVENT_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_WINDOWS)++#include <cstddef>+#include "asio/detail/assert.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class win_event+ : private noncopyable+{+public:+ // Constructor.+ ASIO_DECL win_event();++ // Destructor.+ ASIO_DECL ~win_event();++ // Signal the event. (Retained for backward compatibility.)+ template <typename Lock>+ void signal(Lock& lock)+ {+ this->signal_all(lock);+ }++ // Signal all waiters.+ template <typename Lock>+ void signal_all(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ (void)lock;+ state_ |= 1;+ ::SetEvent(events_[0]);+ }++ // Unlock the mutex and signal one waiter.+ template <typename Lock>+ void unlock_and_signal_one(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ state_ |= 1;+ bool have_waiters = (state_ > 1);+ lock.unlock();+ if (have_waiters)+ ::SetEvent(events_[1]);+ }++ // Unlock the mutex and signal one waiter who may destroy us.+ template <typename Lock>+ void unlock_and_signal_one_for_destruction(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ state_ |= 1;+ bool have_waiters = (state_ > 1);+ if (have_waiters)+ ::SetEvent(events_[1]);+ lock.unlock();+ }++ // If there's a waiter, unlock the mutex and signal it.+ template <typename Lock>+ bool maybe_unlock_and_signal_one(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ state_ |= 1;+ if (state_ > 1)+ {+ lock.unlock();+ ::SetEvent(events_[1]);+ return true;+ }+ return false;+ }++ // Reset the event.+ template <typename Lock>+ void clear(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ (void)lock;+ ::ResetEvent(events_[0]);+ state_ &= ~std::size_t(1);+ }++ // Wait for the event to become signalled.+ template <typename Lock>+ void wait(Lock& lock)+ {+ ASIO_ASSERT(lock.locked());+ while ((state_ & 1) == 0)+ {+ state_ += 2;+ lock.unlock();+#if defined(ASIO_WINDOWS_APP)+ ::WaitForMultipleObjectsEx(2, events_, false, INFINITE, false);+#else // defined(ASIO_WINDOWS_APP)+ ::WaitForMultipleObjects(2, events_, false, INFINITE);+#endif // defined(ASIO_WINDOWS_APP)+ lock.lock();+ state_ -= 2;+ }+ }++ // Timed wait for the event to become signalled.+ template <typename Lock>+ bool wait_for_usec(Lock& lock, long usec)+ {+ ASIO_ASSERT(lock.locked());+ if ((state_ & 1) == 0)+ {+ state_ += 2;+ lock.unlock();+ DWORD msec = usec > 0 ? (usec < 1000 ? 1 : usec / 1000) : 0;+#if defined(ASIO_WINDOWS_APP)+ ::WaitForMultipleObjectsEx(2, events_, false, msec, false);+#else // defined(ASIO_WINDOWS_APP)+ ::WaitForMultipleObjects(2, events_, false, msec);+#endif // defined(ASIO_WINDOWS_APP)+ lock.lock();+ state_ -= 2;+ }+ return (state_ & 1) != 0;+ }++private:+ HANDLE events_[2];+ std::size_t state_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/win_event.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_WINDOWS)++#endif // ASIO_DETAIL_WIN_EVENT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_fd_set_adapter.hpp view
@@ -0,0 +1,149 @@+//+// detail/win_fd_set_adapter.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_FD_SET_ADAPTER_HPP+#define ASIO_DETAIL_WIN_FD_SET_ADAPTER_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_WINDOWS) || defined(__CYGWIN__)++#include "asio/detail/noncopyable.hpp"+#include "asio/detail/reactor_op_queue.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.+class win_fd_set_adapter : noncopyable+{+public:+ enum { default_fd_set_size = 1024 };++ win_fd_set_adapter()+ : capacity_(default_fd_set_size),+ max_descriptor_(invalid_socket)+ {+ fd_set_ = static_cast<win_fd_set*>(::operator new(+ sizeof(win_fd_set) - sizeof(SOCKET)+ + sizeof(SOCKET) * (capacity_)));+ fd_set_->fd_count = 0;+ }++ ~win_fd_set_adapter()+ {+ ::operator delete(fd_set_);+ }++ void reset()+ {+ fd_set_->fd_count = 0;+ max_descriptor_ = invalid_socket;+ }++ bool set(socket_type descriptor)+ {+ for (u_int i = 0; i < fd_set_->fd_count; ++i)+ if (fd_set_->fd_array[i] == descriptor)+ return true;++ reserve(fd_set_->fd_count + 1);+ fd_set_->fd_array[fd_set_->fd_count++] = descriptor;+ return true;+ }++ void set(reactor_op_queue<socket_type>& operations, op_queue<operation>&)+ {+ reactor_op_queue<socket_type>::iterator i = operations.begin();+ while (i != operations.end())+ {+ reactor_op_queue<socket_type>::iterator op_iter = i++;+ reserve(fd_set_->fd_count + 1);+ fd_set_->fd_array[fd_set_->fd_count++] = op_iter->first;+ }+ }++ bool is_set(socket_type descriptor) const+ {+ return !!__WSAFDIsSet(descriptor,+ const_cast<fd_set*>(reinterpret_cast<const fd_set*>(fd_set_)));+ }++ operator fd_set*()+ {+ return reinterpret_cast<fd_set*>(fd_set_);+ }++ socket_type max_descriptor() const+ {+ return max_descriptor_;+ }++ void perform(reactor_op_queue<socket_type>& operations,+ op_queue<operation>& ops) const+ {+ for (u_int i = 0; i < fd_set_->fd_count; ++i)+ operations.perform_operations(fd_set_->fd_array[i], ops);+ }++private:+ // This structure is defined to be compatible with the Windows API fd_set+ // structure, but without being dependent on the value of FD_SETSIZE. We use+ // the "struct hack" to allow the number of descriptors to be varied at+ // runtime.+ struct win_fd_set+ {+ u_int fd_count;+ SOCKET fd_array[1];+ };++ // Increase the fd_set_ capacity to at least the specified number of elements.+ void reserve(u_int n)+ {+ if (n <= capacity_)+ return;++ u_int new_capacity = capacity_ + capacity_ / 2;+ if (new_capacity < n)+ new_capacity = n;++ win_fd_set* new_fd_set = static_cast<win_fd_set*>(::operator new(+ sizeof(win_fd_set) - sizeof(SOCKET)+ + sizeof(SOCKET) * (new_capacity)));++ new_fd_set->fd_count = fd_set_->fd_count;+ for (u_int i = 0; i < fd_set_->fd_count; ++i)+ new_fd_set->fd_array[i] = fd_set_->fd_array[i];++ ::operator delete(fd_set_);+ fd_set_ = new_fd_set;+ capacity_ = new_capacity;+ }++ win_fd_set* fd_set_;+ u_int capacity_;+ socket_type max_descriptor_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++#endif // ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_fenced_block.hpp view
@@ -0,0 +1,90 @@+//+// detail/win_fenced_block.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_FENCED_BLOCK_HPP+#define ASIO_DETAIL_WIN_FENCED_BLOCK_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_WINDOWS) && !defined(UNDER_CE)++#include "asio/detail/socket_types.hpp"+#include "asio/detail/noncopyable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class win_fenced_block+ : private noncopyable+{+public:+ enum half_t { half };+ enum full_t { full };++ // Constructor for a half fenced block.+ explicit win_fenced_block(half_t)+ {+ }++ // Constructor for a full fenced block.+ explicit win_fenced_block(full_t)+ {+#if defined(__BORLANDC__)+ LONG barrier = 0;+ ::InterlockedExchange(&barrier, 1);+#elif defined(ASIO_MSVC) \+ && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier))+# if defined(_M_IX86)+# pragma warning(push)+# pragma warning(disable:4793)+ LONG barrier;+ __asm { xchg barrier, eax }+# pragma warning(pop)+# endif // defined(_M_IX86)+#else+ MemoryBarrier();+#endif+ }++ // Destructor.+ ~win_fenced_block()+ {+#if defined(__BORLANDC__)+ LONG barrier = 0;+ ::InterlockedExchange(&barrier, 1);+#elif defined(ASIO_MSVC) \+ && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier))+# if defined(_M_IX86)+# pragma warning(push)+# pragma warning(disable:4793)+ LONG barrier;+ __asm { xchg barrier, eax }+# pragma warning(pop)+# endif // defined(_M_IX86)+#else+ MemoryBarrier();+#endif+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS) && !defined(UNDER_CE)++#endif // ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_global.hpp view
@@ -0,0 +1,71 @@+//+// detail/win_global.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_GLOBAL_HPP+#define ASIO_DETAIL_WIN_GLOBAL_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/static_mutex.hpp"+#include "asio/detail/tss_ptr.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename T>+struct win_global_impl+{+ // Destructor automatically cleans up the global.+ ~win_global_impl()+ {+ delete ptr_;+ }++ static win_global_impl instance_;+ static static_mutex mutex_;+ T* ptr_;+ static tss_ptr<T> tss_ptr_;+};++template <typename T>+win_global_impl<T> win_global_impl<T>::instance_ = { 0 };++template <typename T>+static_mutex win_global_impl<T>::mutex_ = ASIO_STATIC_MUTEX_INIT;++template <typename T>+tss_ptr<T> win_global_impl<T>::tss_ptr_;++template <typename T>+T& win_global()+{+ if (static_cast<T*>(win_global_impl<T>::tss_ptr_) == 0)+ {+ win_global_impl<T>::mutex_.init();+ static_mutex::scoped_lock lock(win_global_impl<T>::mutex_);+ if (win_global_impl<T>::instance_.ptr_ == 0)+ win_global_impl<T>::instance_.ptr_ = new T;+ win_global_impl<T>::tss_ptr_ = win_global_impl<T>::instance_.ptr_;+ }++ return *win_global_impl<T>::tss_ptr_;+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_WIN_GLOBAL_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_read_op.hpp view
@@ -0,0 +1,117 @@+//+// detail/win_iocp_handle_read_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_WIN_IOCP_HANDLE_READ_OP_HPP+#define ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_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_IOCP)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/operation.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename MutableBufferSequence, typename Handler, typename IoExecutor>+class win_iocp_handle_read_op : public operation+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op);++ win_iocp_handle_read_op(const MutableBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ : operation(&win_iocp_handle_read_op::do_complete),+ buffers_(buffers),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& result_ec,+ std::size_t bytes_transferred)+ {+ asio::error_code ec(result_ec);++ // Take ownership of the operation object.+ win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ if (owner)+ {+ // Check whether buffers are still valid.+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::validate(o->buffers_);+ }+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)++ // Map non-portable errors to their portable counterparts.+ if (ec.value() == ERROR_HANDLE_EOF)+ ec = asio::error::eof;++ // 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_, ec, bytes_transferred);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ MutableBufferSequence buffers_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_service.hpp view
@@ -0,0 +1,335 @@+//+// detail/win_iocp_handle_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_WIN_IOCP_HANDLE_SERVICE_HPP+#define ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_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_IOCP)++#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/cstdint.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/operation.hpp"+#include "asio/detail/win_iocp_handle_read_op.hpp"+#include "asio/detail/win_iocp_handle_write_op.hpp"+#include "asio/detail/win_iocp_io_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class win_iocp_handle_service :+ public execution_context_service_base<win_iocp_handle_service>+{+public:+ // The native type of a stream handle.+ typedef HANDLE native_handle_type;++ // The implementation type of the stream handle.+ class implementation_type+ {+ public:+ // Default constructor.+ implementation_type()+ : handle_(INVALID_HANDLE_VALUE),+ safe_cancellation_thread_id_(0),+ next_(0),+ prev_(0)+ {+ }++ private:+ // Only this service will have access to the internal values.+ friend class win_iocp_handle_service;++ // The native stream handle representation.+ native_handle_type handle_;++ // The ID of the thread from which it is safe to cancel asynchronous+ // operations. 0 means no asynchronous operations have been started yet.+ // ~0 means asynchronous operations have been started from more than one+ // thread, and cancellation is not supported for the handle.+ DWORD safe_cancellation_thread_id_;++ // Pointers to adjacent handle implementations in linked list.+ implementation_type* next_;+ implementation_type* prev_;+ };++ ASIO_DECL win_iocp_handle_service(execution_context& context);++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Construct a new handle implementation.+ ASIO_DECL void construct(implementation_type& impl);++ // Move-construct a new handle implementation.+ ASIO_DECL void move_construct(implementation_type& impl,+ implementation_type& other_impl);++ // Move-assign from another handle implementation.+ ASIO_DECL void move_assign(implementation_type& impl,+ win_iocp_handle_service& other_service,+ implementation_type& other_impl);++ // Destroy a handle implementation.+ ASIO_DECL void destroy(implementation_type& impl);++ // Assign a native handle to a handle implementation.+ ASIO_DECL asio::error_code assign(implementation_type& impl,+ const native_handle_type& handle, asio::error_code& ec);++ // Determine whether the handle is open.+ bool is_open(const implementation_type& impl) const+ {+ return impl.handle_ != INVALID_HANDLE_VALUE;+ }++ // Destroy a handle implementation.+ ASIO_DECL asio::error_code close(implementation_type& impl,+ asio::error_code& ec);++ // Get the native handle representation.+ native_handle_type native_handle(const implementation_type& impl) const+ {+ return impl.handle_;+ }++ // Cancel all operations associated with the handle.+ ASIO_DECL asio::error_code cancel(implementation_type& impl,+ asio::error_code& ec);++ // Write the given data. Returns the number of bytes written.+ template <typename ConstBufferSequence>+ size_t write_some(implementation_type& impl,+ const ConstBufferSequence& buffers, asio::error_code& ec)+ {+ return write_some_at(impl, 0, buffers, ec);+ }++ // Write the given data at the specified offset. Returns the number of bytes+ // written.+ template <typename ConstBufferSequence>+ size_t write_some_at(implementation_type& impl, uint64_t offset,+ const ConstBufferSequence& buffers, asio::error_code& ec)+ {+ asio::const_buffer buffer =+ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::first(buffers);++ return do_write(impl, offset, buffer, ec);+ }++ // Start an asynchronous write. The data being written must be valid for the+ // lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_write_some(implementation_type& impl,+ const ConstBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_handle_write_op<+ ConstBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,+ reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some"));++ start_write_op(impl, 0,+ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::first(buffers), p.p);+ p.v = p.p = 0;+ }++ // Start an asynchronous write at a specified offset. The data being written+ // must be valid for the lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_write_some_at(implementation_type& impl,+ uint64_t offset, const ConstBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_handle_write_op<+ ConstBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,+ reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some_at"));++ start_write_op(impl, offset,+ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::first(buffers), p.p);+ p.v = p.p = 0;+ }++ // Read some data. Returns the number of bytes received.+ template <typename MutableBufferSequence>+ size_t read_some(implementation_type& impl,+ const MutableBufferSequence& buffers, asio::error_code& ec)+ {+ return read_some_at(impl, 0, buffers, ec);+ }++ // Read some data at a specified offset. Returns the number of bytes received.+ template <typename MutableBufferSequence>+ size_t read_some_at(implementation_type& impl, uint64_t offset,+ const MutableBufferSequence& buffers, asio::error_code& ec)+ {+ asio::mutable_buffer buffer =+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::first(buffers);++ return do_read(impl, offset, buffer, ec);+ }++ // Start an asynchronous read. The buffer for the data being received must be+ // valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_read_some(implementation_type& impl,+ const MutableBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_handle_read_op<+ MutableBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,+ reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some"));++ start_read_op(impl, 0,+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::first(buffers), p.p);+ p.v = p.p = 0;+ }++ // Start an asynchronous read at a specified offset. The buffer for the data+ // being received must be valid for the lifetime of the asynchronous+ // operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_read_some_at(implementation_type& impl,+ uint64_t offset, const MutableBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_handle_read_op<+ MutableBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,+ reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some_at"));++ start_read_op(impl, offset,+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::first(buffers), p.p);+ p.v = p.p = 0;+ }++private:+ // Prevent the use of the null_buffers type with this service.+ size_t write_some(implementation_type& impl,+ const null_buffers& buffers, asio::error_code& ec);+ size_t write_some_at(implementation_type& impl, uint64_t offset,+ const null_buffers& buffers, asio::error_code& ec);+ template <typename Handler, typename IoExecutor>+ void async_write_some(implementation_type& impl,+ const null_buffers& buffers, Handler& handler,+ const IoExecutor& io_ex);+ template <typename Handler, typename IoExecutor>+ void async_write_some_at(implementation_type& impl, uint64_t offset,+ const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex);+ size_t read_some(implementation_type& impl,+ const null_buffers& buffers, asio::error_code& ec);+ size_t read_some_at(implementation_type& impl, uint64_t offset,+ const null_buffers& buffers, asio::error_code& ec);+ template <typename Handler, typename IoExecutor>+ void async_read_some(implementation_type& impl,+ const null_buffers& buffers, Handler& handler,+ const IoExecutor& io_ex);+ template <typename Handler, typename IoExecutor>+ void async_read_some_at(implementation_type& impl, uint64_t offset,+ const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex);++ // Helper class for waiting for synchronous operations to complete.+ class overlapped_wrapper;++ // Helper function to perform a synchronous write operation.+ ASIO_DECL size_t do_write(implementation_type& impl,+ uint64_t offset, const asio::const_buffer& buffer,+ asio::error_code& ec);++ // Helper function to start a write operation.+ ASIO_DECL void start_write_op(implementation_type& impl,+ uint64_t offset, const asio::const_buffer& buffer,+ operation* op);++ // Helper function to perform a synchronous write operation.+ ASIO_DECL size_t do_read(implementation_type& impl,+ uint64_t offset, const asio::mutable_buffer& buffer,+ asio::error_code& ec);++ // Helper function to start a read operation.+ ASIO_DECL void start_read_op(implementation_type& impl,+ uint64_t offset, const asio::mutable_buffer& buffer,+ operation* op);++ // Update the ID of the thread from which cancellation is safe.+ ASIO_DECL void update_cancellation_thread_id(implementation_type& impl);++ // Helper function to close a handle when the associated object is being+ // destroyed.+ ASIO_DECL void close_for_destruction(implementation_type& impl);++ // The IOCP service used for running asynchronous operations and dispatching+ // handlers.+ win_iocp_io_context& iocp_service_;++ // Mutex to protect access to the linked list of implementations.+ mutex mutex_;++ // The head of a linked list of all implementations.+ implementation_type* impl_list_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/win_iocp_handle_service.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_handle_write_op.hpp view
@@ -0,0 +1,110 @@+//+// detail/win_iocp_handle_write_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_WIN_IOCP_HANDLE_WRITE_OP_HPP+#define ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_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_IOCP)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/operation.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+class win_iocp_handle_write_op : public operation+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op);++ win_iocp_handle_write_op(const ConstBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ : operation(&win_iocp_handle_write_op::do_complete),+ buffers_(buffers),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& ec, std::size_t bytes_transferred)+ {+ // Take ownership of the operation object.+ win_iocp_handle_write_op* o(static_cast<win_iocp_handle_write_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ if (owner)+ {+ // Check whether buffers are still valid.+ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::validate(o->buffers_);+ }+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)++ // 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_, ec, bytes_transferred);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ ConstBufferSequence buffers_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_io_context.hpp view
@@ -0,0 +1,342 @@+//+// detail/win_iocp_io_context.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_IO_CONTEXT_HPP+#define ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_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_IOCP)++#include "asio/detail/limits.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/scoped_ptr.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/thread.hpp"+#include "asio/detail/thread_context.hpp"+#include "asio/detail/timer_queue_base.hpp"+#include "asio/detail/timer_queue_set.hpp"+#include "asio/detail/wait_op.hpp"+#include "asio/detail/win_iocp_operation.hpp"+#include "asio/detail/win_iocp_thread_info.hpp"+#include "asio/execution_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class wait_op;++class win_iocp_io_context+ : public execution_context_service_base<win_iocp_io_context>,+ public thread_context+{+public:+ // Constructor. Specifies a concurrency hint that is passed through to the+ // underlying I/O completion port.+ ASIO_DECL win_iocp_io_context(asio::execution_context& ctx,+ int concurrency_hint = -1, bool own_thread = true);++ // Destructor.+ ASIO_DECL ~win_iocp_io_context();++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Initialise the task. Nothing to do here.+ void init_task()+ {+ }++ // Register a handle with the IO completion port.+ ASIO_DECL asio::error_code register_handle(+ HANDLE handle, asio::error_code& ec);++ // Run the event loop until stopped or no more work.+ ASIO_DECL size_t run(asio::error_code& ec);++ // Run until stopped or one operation is performed.+ ASIO_DECL size_t run_one(asio::error_code& ec);++ // Run until timeout, interrupted, or one operation is performed.+ ASIO_DECL size_t wait_one(long usec, asio::error_code& ec);++ // Poll for operations without blocking.+ ASIO_DECL size_t poll(asio::error_code& ec);++ // Poll for one operation without blocking.+ ASIO_DECL size_t poll_one(asio::error_code& ec);++ // Stop the event processing loop.+ ASIO_DECL void stop();++ // Determine whether the io_context is stopped.+ bool stopped() const+ {+ return ::InterlockedExchangeAdd(&stopped_, 0) != 0;+ }++ // Restart in preparation for a subsequent run invocation.+ void restart()+ {+ ::InterlockedExchange(&stopped_, 0);+ }++ // Notify that some work has started.+ void work_started()+ {+ ::InterlockedIncrement(&outstanding_work_);+ }++ // Notify that some work has finished.+ void work_finished()+ {+ if (::InterlockedDecrement(&outstanding_work_) == 0)+ stop();+ }++ // Return whether a handler can be dispatched immediately.+ bool can_dispatch()+ {+ return thread_call_stack::contains(this) != 0;+ }++ /// Capture the current exception so it can be rethrown from a run function.+ ASIO_DECL void capture_current_exception();++ // Request invocation of the given operation and return immediately. Assumes+ // that work_started() has not yet been called for the operation.+ void post_immediate_completion(win_iocp_operation* op, bool)+ {+ work_started();+ post_deferred_completion(op);+ }++ // Request invocation of the given operation and return immediately. Assumes+ // that work_started() was previously called for the operation.+ ASIO_DECL void post_deferred_completion(win_iocp_operation* op);++ // Request invocation of the given operation and return immediately. Assumes+ // that work_started() was previously called for the operations.+ ASIO_DECL void post_deferred_completions(+ op_queue<win_iocp_operation>& ops);++ // Request invocation of the given operation using the thread-private queue+ // and return immediately. Assumes that work_started() has not yet been+ // called for the operation.+ void post_private_immediate_completion(win_iocp_operation* op)+ {+ post_immediate_completion(op, false);+ }++ // Request invocation of the given operation using the thread-private queue+ // and return immediately. Assumes that work_started() was previously called+ // for the operation.+ void post_private_deferred_completion(win_iocp_operation* op)+ {+ post_deferred_completion(op);+ }++ // Enqueue the given operation following a failed attempt to dispatch the+ // operation for immediate invocation.+ void do_dispatch(operation* op)+ {+ post_immediate_completion(op, false);+ }++ // Process unfinished operations as part of a shutdown operation. Assumes+ // that work_started() was previously called for the operations.+ ASIO_DECL void abandon_operations(op_queue<operation>& ops);++ // Called after starting an overlapped I/O operation that did not complete+ // immediately. The caller must have already called work_started() prior to+ // starting the operation.+ ASIO_DECL void on_pending(win_iocp_operation* op);++ // Called after starting an overlapped I/O operation that completed+ // immediately. The caller must have already called work_started() prior to+ // starting the operation.+ ASIO_DECL void on_completion(win_iocp_operation* op,+ DWORD last_error = 0, DWORD bytes_transferred = 0);++ // Called after starting an overlapped I/O operation that completed+ // immediately. The caller must have already called work_started() prior to+ // starting the operation.+ ASIO_DECL void on_completion(win_iocp_operation* op,+ const asio::error_code& ec, DWORD bytes_transferred = 0);++ // Add a new timer queue to the service.+ template <typename Time_Traits>+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue);++ // Remove a timer queue from the service.+ template <typename Time_Traits>+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);++ // Schedule a new operation in the given timer queue to expire at the+ // specified absolute time.+ template <typename Time_Traits>+ void schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);++ // Cancel the timer associated with the given token. Returns the number of+ // handlers that have been posted or dispatched.+ template <typename Time_Traits>+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());++ // Move the timer operations associated with the given timer.+ template <typename Time_Traits>+ void move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& to,+ typename timer_queue<Time_Traits>::per_timer_data& from);++ // Get the concurrency hint that was used to initialise the io_context.+ int concurrency_hint() const+ {+ return concurrency_hint_;+ }++private:+#if defined(WINVER) && (WINVER < 0x0500)+ typedef DWORD dword_ptr_t;+ typedef ULONG ulong_ptr_t;+#else // defined(WINVER) && (WINVER < 0x0500)+ typedef DWORD_PTR dword_ptr_t;+ typedef ULONG_PTR ulong_ptr_t;+#endif // defined(WINVER) && (WINVER < 0x0500)++ // Dequeues at most one operation from the I/O completion port, and then+ // executes it. Returns the number of operations that were dequeued (i.e.+ // either 0 or 1).+ ASIO_DECL size_t do_one(DWORD msec,+ win_iocp_thread_info& this_thread, asio::error_code& ec);++ // Helper to calculate the GetQueuedCompletionStatus timeout.+ ASIO_DECL static DWORD get_gqcs_timeout();++ // Helper function to add a new timer queue.+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);++ // Helper function to remove a timer queue.+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);++ // Called to recalculate and update the timeout.+ ASIO_DECL void update_timeout();++ // Helper class to call work_finished() on block exit.+ struct work_finished_on_block_exit;++ // Helper class for managing a HANDLE.+ struct auto_handle+ {+ HANDLE handle;+ auto_handle() : handle(0) {}+ ~auto_handle() { if (handle) ::CloseHandle(handle); }+ };++ // The IO completion port used for queueing operations.+ auto_handle iocp_;++ // The count of unfinished work.+ long outstanding_work_;++ // Flag to indicate whether the event loop has been stopped.+ mutable long stopped_;++ // Flag to indicate whether there is an in-flight stop event. Every event+ // posted using PostQueuedCompletionStatus consumes non-paged pool, so to+ // avoid exhausting this resouce we limit the number of outstanding events.+ long stop_event_posted_;++ // Flag to indicate whether the service has been shut down.+ long shutdown_;++ enum+ {+ // Timeout to use with GetQueuedCompletionStatus on older versions of+ // Windows. Some versions of windows have a "bug" where a call to+ // GetQueuedCompletionStatus can appear stuck even though there are events+ // waiting on the queue. Using a timeout helps to work around the issue.+ default_gqcs_timeout = 500,++ // Maximum waitable timer timeout, in milliseconds.+ max_timeout_msec = 5 * 60 * 1000,++ // Maximum waitable timer timeout, in microseconds.+ max_timeout_usec = max_timeout_msec * 1000,++ // Completion key value used to wake up a thread to dispatch timers or+ // completed operations.+ wake_for_dispatch = 1,++ // Completion key value to indicate that an operation has posted with the+ // original last_error and bytes_transferred values stored in the fields of+ // the OVERLAPPED structure.+ overlapped_contains_result = 2+ };++ // Timeout to use with GetQueuedCompletionStatus.+ const DWORD gqcs_timeout_;++ // Helper class to run the scheduler in its own thread.+ struct thread_function;+ friend struct thread_function;++ // Function object for processing timeouts in a background thread.+ struct timer_thread_function;+ friend struct timer_thread_function;++ // Background thread used for processing timeouts.+ scoped_ptr<thread> timer_thread_;++ // A waitable timer object used for waiting for timeouts.+ auto_handle waitable_timer_;++ // Non-zero if timers or completed operations need to be dispatched.+ long dispatch_required_;++ // Mutex for protecting access to the timer queues and completed operations.+ mutex dispatch_mutex_;++ // The timer queues.+ timer_queue_set timer_queues_;++ // The operations that are ready to dispatch.+ op_queue<win_iocp_operation> completed_ops_;++ // The concurrency hint used to initialise the io_context.+ const int concurrency_hint_;++ // The thread that is running the io_context.+ scoped_ptr<thread> thread_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/detail/impl/win_iocp_io_context.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/win_iocp_io_context.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_null_buffers_op.hpp view
@@ -0,0 +1,127 @@+//+// detail/win_iocp_null_buffers_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_NULL_BUFFERS_OP_HPP+#define ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_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_IOCP)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename IoExecutor>+class win_iocp_null_buffers_op : public reactor_op+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op);++ win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token,+ Handler& handler, const IoExecutor& io_ex)+ : reactor_op(asio::error_code(),+ &win_iocp_null_buffers_op::do_perform,+ &win_iocp_null_buffers_op::do_complete),+ cancel_token_(cancel_token),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static status do_perform(reactor_op*)+ {+ return done;+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& result_ec,+ std::size_t bytes_transferred)+ {+ asio::error_code ec(result_ec);++ // Take ownership of the operation object.+ win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // The reactor may have stored a result in the operation object.+ if (o->ec_)+ ec = o->ec_;++ // Map non-portable errors to their portable counterparts.+ if (ec.value() == ERROR_NETNAME_DELETED)+ {+ if (o->cancel_token_.expired())+ ec = asio::error::operation_aborted;+ else+ ec = asio::error::connection_reset;+ }+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ {+ ec = asio::error::connection_refused;+ }++ // 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_, ec, bytes_transferred);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ socket_ops::weak_cancel_token_type cancel_token_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_operation.hpp view
@@ -0,0 +1,96 @@+//+// detail/win_iocp_operation.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_OPERATION_HPP+#define ASIO_DETAIL_WIN_IOCP_OPERATION_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_IOCP)++#include "asio/detail/handler_tracking.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/error_code.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class win_iocp_io_context;++// Base class for all operations. A function pointer is used instead of virtual+// functions to avoid the associated overhead.+class win_iocp_operation+ : public OVERLAPPED+ ASIO_ALSO_INHERIT_TRACKED_HANDLER+{+public:+ typedef win_iocp_operation operation_type;++ void complete(void* owner, const asio::error_code& ec,+ std::size_t bytes_transferred)+ {+ func_(owner, this, ec, bytes_transferred);+ }++ void destroy()+ {+ func_(0, this, asio::error_code(), 0);+ }++protected:+ typedef void (*func_type)(+ void*, win_iocp_operation*,+ const asio::error_code&, std::size_t);++ win_iocp_operation(func_type func)+ : next_(0),+ func_(func)+ {+ reset();+ }++ // Prevents deletion through this type.+ ~win_iocp_operation()+ {+ }++ void reset()+ {+ Internal = 0;+ InternalHigh = 0;+ Offset = 0;+ OffsetHigh = 0;+ hEvent = 0;+ ready_ = 0;+ }++private:+ friend class op_queue_access;+ friend class win_iocp_io_context;+ win_iocp_operation* next_;+ func_type func_;+ long ready_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_overlapped_op.hpp view
@@ -0,0 +1,96 @@+//+// detail/win_iocp_overlapped_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_OVERLAPPED_OP_HPP+#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_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_IOCP)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/operation.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename IoExecutor>+class win_iocp_overlapped_op : public operation+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op);++ win_iocp_overlapped_op(Handler& handler, const IoExecutor& io_ex)+ : operation(&win_iocp_overlapped_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& ec, std::size_t bytes_transferred)+ {+ // Take ownership of the operation object.+ win_iocp_overlapped_op* o(static_cast<win_iocp_overlapped_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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_, ec, bytes_transferred);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_overlapped_ptr.hpp view
@@ -0,0 +1,171 @@+//+// detail/win_iocp_overlapped_ptr.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_OVERLAPPED_PTR_HPP+#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_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_IOCP)++#include "asio/io_context.hpp"+#include "asio/query.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/win_iocp_overlapped_op.hpp"+#include "asio/detail/win_iocp_io_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Wraps a handler to create an OVERLAPPED object for use with overlapped I/O.+class win_iocp_overlapped_ptr+ : private noncopyable+{+public:+ // Construct an empty win_iocp_overlapped_ptr.+ win_iocp_overlapped_ptr()+ : ptr_(0),+ iocp_service_(0)+ {+ }++ // Construct an win_iocp_overlapped_ptr to contain the specified handler.+ template <typename Executor, typename Handler>+ explicit win_iocp_overlapped_ptr(const Executor& ex,+ ASIO_MOVE_ARG(Handler) handler)+ : ptr_(0),+ iocp_service_(0)+ {+ this->reset(ex, ASIO_MOVE_CAST(Handler)(handler));+ }++ // Destructor automatically frees the OVERLAPPED object unless released.+ ~win_iocp_overlapped_ptr()+ {+ reset();+ }++ // Reset to empty.+ void reset()+ {+ if (ptr_)+ {+ ptr_->destroy();+ ptr_ = 0;+ iocp_service_->work_finished();+ iocp_service_ = 0;+ }+ }++ // Reset to contain the specified handler, freeing any current OVERLAPPED+ // object.+ template <typename Executor, typename Handler>+ void reset(const Executor& ex, Handler handler)+ {+ win_iocp_io_context* iocp_service = this->get_iocp_service(ex);++ typedef win_iocp_overlapped_op<Handler, Executor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(handler, ex);++ ASIO_HANDLER_CREATION((ex.context(), *p.p,+ "iocp_service", iocp_service, 0, "overlapped"));++ iocp_service->work_started();+ reset();+ ptr_ = p.p;+ p.v = p.p = 0;+ iocp_service_ = iocp_service;+ }++ // Get the contained OVERLAPPED object.+ OVERLAPPED* get()+ {+ return ptr_;+ }++ // Get the contained OVERLAPPED object.+ const OVERLAPPED* get() const+ {+ return ptr_;+ }++ // Release ownership of the OVERLAPPED object.+ OVERLAPPED* release()+ {+ if (ptr_)+ iocp_service_->on_pending(ptr_);++ OVERLAPPED* tmp = ptr_;+ ptr_ = 0;+ iocp_service_ = 0;+ return tmp;+ }++ // Post completion notification for overlapped operation. Releases ownership.+ void complete(const asio::error_code& ec,+ std::size_t bytes_transferred)+ {+ if (ptr_)+ {+ iocp_service_->on_completion(ptr_, ec,+ static_cast<DWORD>(bytes_transferred));+ ptr_ = 0;+ iocp_service_ = 0;+ }+ }++private:+ template <typename Executor>+ static win_iocp_io_context* get_iocp_service(const Executor& ex,+ typename enable_if<+ can_query<const Executor&, execution::context_t>::value+ >::type* = 0)+ {+ return &use_service<win_iocp_io_context>(+ asio::query(ex, execution::context));+ }++ template <typename Executor>+ static win_iocp_io_context* get_iocp_service(const Executor& ex,+ typename enable_if<+ !can_query<const Executor&, execution::context_t>::value+ >::type* = 0)+ {+ return &use_service<win_iocp_io_context>(ex.context());+ }++ static win_iocp_io_context* get_iocp_service(+ const io_context::executor_type& ex)+ {+ return &asio::query(ex, execution::context).impl_;+ }++ win_iocp_operation* ptr_;+ win_iocp_io_context* iocp_service_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_serial_port_service.hpp view
@@ -0,0 +1,232 @@+//+// detail/win_iocp_serial_port_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_WIN_IOCP_SERIAL_PORT_SERVICE_HPP+#define ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_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_IOCP) && defined(ASIO_HAS_SERIAL_PORT)++#include <string>+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/detail/win_iocp_handle_service.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Extend win_iocp_handle_service to provide serial port support.+class win_iocp_serial_port_service :+ public execution_context_service_base<win_iocp_serial_port_service>+{+public:+ // The native type of a serial port.+ typedef win_iocp_handle_service::native_handle_type native_handle_type;++ // The implementation type of the serial port.+ typedef win_iocp_handle_service::implementation_type implementation_type;++ // Constructor.+ ASIO_DECL win_iocp_serial_port_service(execution_context& context);++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Construct a new serial port implementation.+ void construct(implementation_type& impl)+ {+ handle_service_.construct(impl);+ }++ // Move-construct a new serial port implementation.+ void move_construct(implementation_type& impl,+ implementation_type& other_impl)+ {+ handle_service_.move_construct(impl, other_impl);+ }++ // Move-assign from another serial port implementation.+ void move_assign(implementation_type& impl,+ win_iocp_serial_port_service& other_service,+ implementation_type& other_impl)+ {+ handle_service_.move_assign(impl,+ other_service.handle_service_, other_impl);+ }++ // Destroy a serial port implementation.+ void destroy(implementation_type& impl)+ {+ handle_service_.destroy(impl);+ }++ // Open the serial port using the specified device name.+ ASIO_DECL asio::error_code open(implementation_type& impl,+ const std::string& device, asio::error_code& ec);++ // Assign a native handle to a serial port implementation.+ asio::error_code assign(implementation_type& impl,+ const native_handle_type& handle, asio::error_code& ec)+ {+ return handle_service_.assign(impl, handle, ec);+ }++ // Determine whether the serial port is open.+ bool is_open(const implementation_type& impl) const+ {+ return handle_service_.is_open(impl);+ }++ // Destroy a serial port implementation.+ asio::error_code close(implementation_type& impl,+ asio::error_code& ec)+ {+ return handle_service_.close(impl, ec);+ }++ // Get the native serial port representation.+ native_handle_type native_handle(implementation_type& impl)+ {+ return handle_service_.native_handle(impl);+ }++ // Cancel all operations associated with the handle.+ asio::error_code cancel(implementation_type& impl,+ asio::error_code& ec)+ {+ return handle_service_.cancel(impl, ec);+ }++ // Set an option on the serial port.+ template <typename SettableSerialPortOption>+ asio::error_code set_option(implementation_type& impl,+ const SettableSerialPortOption& option, asio::error_code& ec)+ {+ return do_set_option(impl,+ &win_iocp_serial_port_service::store_option<SettableSerialPortOption>,+ &option, ec);+ }++ // Get an option from the serial port.+ template <typename GettableSerialPortOption>+ asio::error_code get_option(const implementation_type& impl,+ GettableSerialPortOption& option, asio::error_code& ec) const+ {+ return do_get_option(impl,+ &win_iocp_serial_port_service::load_option<GettableSerialPortOption>,+ &option, ec);+ }++ // Send a break sequence to the serial port.+ asio::error_code send_break(implementation_type&,+ asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Write the given data. Returns the number of bytes sent.+ template <typename ConstBufferSequence>+ size_t write_some(implementation_type& impl,+ const ConstBufferSequence& buffers, asio::error_code& ec)+ {+ return handle_service_.write_some(impl, buffers, ec);+ }++ // Start an asynchronous write. The data being written must be valid for the+ // lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_write_some(implementation_type& impl,+ const ConstBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ {+ handle_service_.async_write_some(impl, buffers, handler, io_ex);+ }++ // Read some data. Returns the number of bytes received.+ template <typename MutableBufferSequence>+ size_t read_some(implementation_type& impl,+ const MutableBufferSequence& buffers, asio::error_code& ec)+ {+ return handle_service_.read_some(impl, buffers, ec);+ }++ // Start an asynchronous read. The buffer for the data being received must be+ // valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_read_some(implementation_type& impl,+ const MutableBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ {+ handle_service_.async_read_some(impl, buffers, handler, io_ex);+ }++private:+ // Function pointer type for storing a serial port option.+ typedef asio::error_code (*store_function_type)(+ const void*, ::DCB&, asio::error_code&);++ // Helper function template to store a serial port option.+ template <typename SettableSerialPortOption>+ static asio::error_code store_option(const void* option,+ ::DCB& storage, asio::error_code& ec)+ {+ static_cast<const SettableSerialPortOption*>(option)->store(storage, ec);+ return ec;+ }++ // Helper function to set a serial port option.+ ASIO_DECL asio::error_code do_set_option(+ implementation_type& impl, store_function_type store,+ const void* option, asio::error_code& ec);++ // Function pointer type for loading a serial port option.+ typedef asio::error_code (*load_function_type)(+ void*, const ::DCB&, asio::error_code&);++ // Helper function template to load a serial port option.+ template <typename GettableSerialPortOption>+ static asio::error_code load_option(void* option,+ const ::DCB& storage, asio::error_code& ec)+ {+ static_cast<GettableSerialPortOption*>(option)->load(storage, ec);+ return ec;+ }++ // Helper function to get a serial port option.+ ASIO_DECL asio::error_code do_get_option(+ const implementation_type& impl, load_function_type load,+ void* option, asio::error_code& ec) const;++ // The implementation used for initiating asynchronous operations.+ win_iocp_handle_service handle_service_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/win_iocp_serial_port_service.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)++#endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_accept_op.hpp view
@@ -0,0 +1,312 @@+//+// detail/win_iocp_socket_accept_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_SOCKET_ACCEPT_OP_HPP+#define ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_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_IOCP)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/operation.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/win_iocp_socket_service_base.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Socket, typename Protocol,+ typename Handler, typename IoExecutor>+class win_iocp_socket_accept_op : public operation+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op);++ win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service,+ socket_type socket, Socket& peer, const Protocol& protocol,+ typename Protocol::endpoint* peer_endpoint,+ bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex)+ : operation(&win_iocp_socket_accept_op::do_complete),+ socket_service_(socket_service),+ socket_(socket),+ peer_(peer),+ protocol_(protocol),+ peer_endpoint_(peer_endpoint),+ enable_connection_aborted_(enable_connection_aborted),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ socket_holder& new_socket()+ {+ return new_socket_;+ }++ void* output_buffer()+ {+ return output_buffer_;+ }++ DWORD address_length()+ {+ return sizeof(sockaddr_storage_type) + 16;+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& result_ec,+ std::size_t /*bytes_transferred*/)+ {+ asio::error_code ec(result_ec);++ // Take ownership of the operation object.+ win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ if (owner)+ {+ typename Protocol::endpoint peer_endpoint;+ std::size_t addr_len = peer_endpoint.capacity();+ socket_ops::complete_iocp_accept(o->socket_,+ o->output_buffer(), o->address_length(),+ peer_endpoint.data(), &addr_len,+ o->new_socket_.get(), ec);++ // Restart the accept operation if we got the connection_aborted error+ // and the enable_connection_aborted socket option is not set.+ if (ec == asio::error::connection_aborted+ && !o->enable_connection_aborted_)+ {+ o->reset();+ o->socket_service_.restart_accept_op(o->socket_,+ o->new_socket_, o->protocol_.family(),+ o->protocol_.type(), o->protocol_.protocol(),+ o->output_buffer(), o->address_length(), o);+ p.v = p.p = 0;+ return;+ }++ // If the socket was successfully accepted, transfer ownership of the+ // socket to the peer object.+ if (!ec)+ {+ o->peer_.assign(o->protocol_,+ typename Socket::native_handle_type(+ o->new_socket_.get(), peer_endpoint), ec);+ if (!ec)+ o->new_socket_.release();+ }++ // Pass endpoint back to caller.+ if (o->peer_endpoint_)+ *o->peer_endpoint_ = peer_endpoint;+ }++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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::binder1<Handler, asio::error_code>+ handler(o->handler_, ec);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ win_iocp_socket_service_base& socket_service_;+ socket_type socket_;+ socket_holder new_socket_;+ Socket& peer_;+ Protocol protocol_;+ typename Protocol::endpoint* peer_endpoint_;+ unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];+ bool enable_connection_aborted_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++#if defined(ASIO_HAS_MOVE)++template <typename Protocol, typename PeerIoExecutor,+ typename Handler, typename IoExecutor>+class win_iocp_socket_move_accept_op : public operation+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_move_accept_op);++ win_iocp_socket_move_accept_op(+ win_iocp_socket_service_base& socket_service, socket_type socket,+ const Protocol& protocol, const PeerIoExecutor& peer_io_ex,+ typename Protocol::endpoint* peer_endpoint,+ bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex)+ : operation(&win_iocp_socket_move_accept_op::do_complete),+ socket_service_(socket_service),+ socket_(socket),+ peer_(peer_io_ex),+ protocol_(protocol),+ peer_endpoint_(peer_endpoint),+ enable_connection_aborted_(enable_connection_aborted),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ socket_holder& new_socket()+ {+ return new_socket_;+ }++ void* output_buffer()+ {+ return output_buffer_;+ }++ DWORD address_length()+ {+ return sizeof(sockaddr_storage_type) + 16;+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& result_ec,+ std::size_t /*bytes_transferred*/)+ {+ asio::error_code ec(result_ec);++ // Take ownership of the operation object.+ win_iocp_socket_move_accept_op* o(+ static_cast<win_iocp_socket_move_accept_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ if (owner)+ {+ typename Protocol::endpoint peer_endpoint;+ std::size_t addr_len = peer_endpoint.capacity();+ socket_ops::complete_iocp_accept(o->socket_,+ o->output_buffer(), o->address_length(),+ peer_endpoint.data(), &addr_len,+ o->new_socket_.get(), ec);++ // Restart the accept operation if we got the connection_aborted error+ // and the enable_connection_aborted socket option is not set.+ if (ec == asio::error::connection_aborted+ && !o->enable_connection_aborted_)+ {+ o->reset();+ o->socket_service_.restart_accept_op(o->socket_,+ o->new_socket_, o->protocol_.family(),+ o->protocol_.type(), o->protocol_.protocol(),+ o->output_buffer(), o->address_length(), o);+ p.v = p.p = 0;+ return;+ }++ // If the socket was successfully accepted, transfer ownership of the+ // socket to the peer object.+ if (!ec)+ {+ o->peer_.assign(o->protocol_,+ typename Protocol::socket::native_handle_type(+ o->new_socket_.get(), peer_endpoint), ec);+ if (!ec)+ o->new_socket_.release();+ }++ // Pass endpoint back to caller.+ if (o->peer_endpoint_)+ *o->peer_endpoint_ = peer_endpoint;+ }++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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::move_binder2<Handler,+ asio::error_code, peer_socket_type>+ handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), ec,+ ASIO_MOVE_CAST(peer_socket_type)(o->peer_));+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ typedef typename Protocol::socket::template+ rebind_executor<PeerIoExecutor>::other peer_socket_type;++ win_iocp_socket_service_base& socket_service_;+ socket_type socket_;+ socket_holder new_socket_;+ peer_socket_type peer_;+ Protocol protocol_;+ typename Protocol::endpoint* peer_endpoint_;+ unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];+ bool enable_connection_aborted_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++#endif // defined(ASIO_HAS_MOVE)++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_connect_op.hpp view
@@ -0,0 +1,135 @@+//+// detail/win_iocp_socket_connect_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_SOCKET_CONNECT_OP_HPP+#define ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_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_IOCP)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class win_iocp_socket_connect_op_base : public reactor_op+{+public:+ win_iocp_socket_connect_op_base(socket_type socket, func_type complete_func)+ : reactor_op(asio::error_code(),+ &win_iocp_socket_connect_op_base::do_perform, complete_func),+ socket_(socket),+ connect_ex_(false)+ {+ }++ static status do_perform(reactor_op* base)+ {+ win_iocp_socket_connect_op_base* o(+ static_cast<win_iocp_socket_connect_op_base*>(base));++ return socket_ops::non_blocking_connect(+ o->socket_, o->ec_) ? done : not_done;+ }++ socket_type socket_;+ bool connect_ex_;+};++template <typename Handler, typename IoExecutor>+class win_iocp_socket_connect_op : public win_iocp_socket_connect_op_base+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_connect_op);++ win_iocp_socket_connect_op(socket_type socket,+ Handler& handler, const IoExecutor& io_ex)+ : win_iocp_socket_connect_op_base(socket,+ &win_iocp_socket_connect_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& result_ec,+ std::size_t /*bytes_transferred*/)+ {+ asio::error_code ec(result_ec);++ // Take ownership of the operation object.+ win_iocp_socket_connect_op* o(+ static_cast<win_iocp_socket_connect_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ if (owner)+ {+ if (o->connect_ex_)+ socket_ops::complete_iocp_connect(o->socket_, ec);+ else+ ec = o->ec_;+ }++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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::binder1<Handler, asio::error_code>+ handler(o->handler_, ec);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recv_op.hpp view
@@ -0,0 +1,124 @@+//+// detail/win_iocp_socket_recv_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_SOCKET_RECV_OP_HPP+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_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_IOCP)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/operation.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename MutableBufferSequence, typename Handler, typename IoExecutor>+class win_iocp_socket_recv_op : public operation+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op);++ win_iocp_socket_recv_op(socket_ops::state_type state,+ socket_ops::weak_cancel_token_type cancel_token,+ const MutableBufferSequence& buffers, Handler& handler,+ const IoExecutor& io_ex)+ : operation(&win_iocp_socket_recv_op::do_complete),+ state_(state),+ cancel_token_(cancel_token),+ buffers_(buffers),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& result_ec,+ std::size_t bytes_transferred)+ {+ asio::error_code ec(result_ec);++ // Take ownership of the operation object.+ win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ // Check whether buffers are still valid.+ if (owner)+ {+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::validate(o->buffers_);+ }+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)++ socket_ops::complete_iocp_recv(o->state_, o->cancel_token_,+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::all_empty(o->buffers_),+ ec, bytes_transferred);++ // 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_, ec, bytes_transferred);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ socket_ops::state_type state_;+ socket_ops::weak_cancel_token_type cancel_token_;+ MutableBufferSequence buffers_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recvfrom_op.hpp view
@@ -0,0 +1,133 @@+//+// detail/win_iocp_socket_recvfrom_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_SOCKET_RECVFROM_OP_HPP+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_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_IOCP)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/operation.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename MutableBufferSequence, typename Endpoint,+ typename Handler, typename IoExecutor>+class win_iocp_socket_recvfrom_op : public operation+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op);++ win_iocp_socket_recvfrom_op(Endpoint& endpoint,+ socket_ops::weak_cancel_token_type cancel_token,+ const MutableBufferSequence& buffers, Handler& handler,+ const IoExecutor& io_ex)+ : operation(&win_iocp_socket_recvfrom_op::do_complete),+ endpoint_(endpoint),+ endpoint_size_(static_cast<int>(endpoint.capacity())),+ cancel_token_(cancel_token),+ buffers_(buffers),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ int& endpoint_size()+ {+ return endpoint_size_;+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& result_ec,+ std::size_t bytes_transferred)+ {+ asio::error_code ec(result_ec);++ // Take ownership of the operation object.+ win_iocp_socket_recvfrom_op* o(+ static_cast<win_iocp_socket_recvfrom_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ // Check whether buffers are still valid.+ if (owner)+ {+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::validate(o->buffers_);+ }+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)++ socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec);++ // Record the size of the endpoint returned by the operation.+ o->endpoint_.resize(o->endpoint_size_);++ // 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_, ec, bytes_transferred);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Endpoint& endpoint_;+ int endpoint_size_;+ socket_ops::weak_cancel_token_type cancel_token_;+ MutableBufferSequence buffers_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_recvmsg_op.hpp view
@@ -0,0 +1,125 @@+//+// detail/win_iocp_socket_recvmsg_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_SOCKET_RECVMSG_OP_HPP+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_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_IOCP)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/operation.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/error.hpp"+#include "asio/socket_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename MutableBufferSequence, typename Handler, typename IoExecutor>+class win_iocp_socket_recvmsg_op : public operation+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvmsg_op);++ win_iocp_socket_recvmsg_op(+ socket_ops::weak_cancel_token_type cancel_token,+ const MutableBufferSequence& buffers,+ socket_base::message_flags& out_flags,+ Handler& handler, const IoExecutor& io_ex)+ : operation(&win_iocp_socket_recvmsg_op::do_complete),+ cancel_token_(cancel_token),+ buffers_(buffers),+ out_flags_(out_flags),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& result_ec,+ std::size_t bytes_transferred)+ {+ asio::error_code ec(result_ec);++ // Take ownership of the operation object.+ win_iocp_socket_recvmsg_op* o(+ static_cast<win_iocp_socket_recvmsg_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ // Check whether buffers are still valid.+ if (owner)+ {+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::validate(o->buffers_);+ }+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)++ socket_ops::complete_iocp_recvmsg(o->cancel_token_, ec);+ o->out_flags_ = 0;++ // 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_, ec, bytes_transferred);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ socket_ops::weak_cancel_token_type cancel_token_;+ MutableBufferSequence buffers_;+ socket_base::message_flags& out_flags_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_send_op.hpp view
@@ -0,0 +1,118 @@+//+// detail/win_iocp_socket_send_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_SOCKET_SEND_OP_HPP+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_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_IOCP)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/operation.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+class win_iocp_socket_send_op : public operation+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op);++ win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token,+ const ConstBufferSequence& buffers, Handler& handler,+ const IoExecutor& io_ex)+ : operation(&win_iocp_socket_send_op::do_complete),+ cancel_token_(cancel_token),+ buffers_(buffers),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& result_ec,+ std::size_t bytes_transferred)+ {+ asio::error_code ec(result_ec);++ // Take ownership of the operation object.+ win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ // Check whether buffers are still valid.+ if (owner)+ {+ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::validate(o->buffers_);+ }+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)++ socket_ops::complete_iocp_send(o->cancel_token_, 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_, ec, bytes_transferred);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ socket_ops::weak_cancel_token_type cancel_token_;+ ConstBufferSequence buffers_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_service.hpp view
@@ -0,0 +1,581 @@+//+// detail/win_iocp_socket_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_SOCKET_SERVICE_HPP+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_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_IOCP)++#include <cstring>+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/socket_base.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/operation.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/select_reactor.hpp"+#include "asio/detail/socket_holder.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/win_iocp_io_context.hpp"+#include "asio/detail/win_iocp_null_buffers_op.hpp"+#include "asio/detail/win_iocp_socket_accept_op.hpp"+#include "asio/detail/win_iocp_socket_connect_op.hpp"+#include "asio/detail/win_iocp_socket_recvfrom_op.hpp"+#include "asio/detail/win_iocp_socket_send_op.hpp"+#include "asio/detail/win_iocp_socket_service_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Protocol>+class win_iocp_socket_service :+ public execution_context_service_base<win_iocp_socket_service<Protocol> >,+ public win_iocp_socket_service_base+{+public:+ // The protocol type.+ typedef Protocol protocol_type;++ // The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ // The native type of a socket.+ class native_handle_type+ {+ public:+ native_handle_type(socket_type s)+ : socket_(s),+ have_remote_endpoint_(false)+ {+ }++ native_handle_type(socket_type s, const endpoint_type& ep)+ : socket_(s),+ have_remote_endpoint_(true),+ remote_endpoint_(ep)+ {+ }++ void operator=(socket_type s)+ {+ socket_ = s;+ have_remote_endpoint_ = false;+ remote_endpoint_ = endpoint_type();+ }++ operator socket_type() const+ {+ return socket_;+ }++ bool have_remote_endpoint() const+ {+ return have_remote_endpoint_;+ }++ endpoint_type remote_endpoint() const+ {+ return remote_endpoint_;+ }++ private:+ socket_type socket_;+ bool have_remote_endpoint_;+ endpoint_type remote_endpoint_;+ };++ // The implementation type of the socket.+ struct implementation_type :+ win_iocp_socket_service_base::base_implementation_type+ {+ // Default constructor.+ implementation_type()+ : protocol_(endpoint_type().protocol()),+ have_remote_endpoint_(false),+ remote_endpoint_()+ {+ }++ // The protocol associated with the socket.+ protocol_type protocol_;++ // Whether we have a cached remote endpoint.+ bool have_remote_endpoint_;++ // A cached remote endpoint.+ endpoint_type remote_endpoint_;+ };++ // Constructor.+ win_iocp_socket_service(execution_context& context)+ : execution_context_service_base<+ win_iocp_socket_service<Protocol> >(context),+ win_iocp_socket_service_base(context)+ {+ }++ // Destroy all user-defined handler objects owned by the service.+ void shutdown()+ {+ this->base_shutdown();+ }++ // Move-construct a new socket implementation.+ void move_construct(implementation_type& impl,+ implementation_type& other_impl) ASIO_NOEXCEPT+ {+ this->base_move_construct(impl, other_impl);++ impl.protocol_ = other_impl.protocol_;+ other_impl.protocol_ = endpoint_type().protocol();++ impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_;+ other_impl.have_remote_endpoint_ = false;++ impl.remote_endpoint_ = other_impl.remote_endpoint_;+ other_impl.remote_endpoint_ = endpoint_type();+ }++ // Move-assign from another socket implementation.+ void move_assign(implementation_type& impl,+ win_iocp_socket_service_base& other_service,+ implementation_type& other_impl)+ {+ this->base_move_assign(impl, other_service, other_impl);++ impl.protocol_ = other_impl.protocol_;+ other_impl.protocol_ = endpoint_type().protocol();++ impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_;+ other_impl.have_remote_endpoint_ = false;++ impl.remote_endpoint_ = other_impl.remote_endpoint_;+ other_impl.remote_endpoint_ = endpoint_type();+ }++ // Move-construct a new socket implementation from another protocol type.+ template <typename Protocol1>+ void converting_move_construct(implementation_type& impl,+ win_iocp_socket_service<Protocol1>&,+ typename win_iocp_socket_service<+ Protocol1>::implementation_type& other_impl)+ {+ this->base_move_construct(impl, other_impl);++ impl.protocol_ = protocol_type(other_impl.protocol_);+ other_impl.protocol_ = typename Protocol1::endpoint().protocol();++ impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_;+ other_impl.have_remote_endpoint_ = false;++ impl.remote_endpoint_ = other_impl.remote_endpoint_;+ other_impl.remote_endpoint_ = typename Protocol1::endpoint();+ }++ // Open a new socket implementation.+ asio::error_code open(implementation_type& impl,+ const protocol_type& protocol, asio::error_code& ec)+ {+ if (!do_open(impl, protocol.family(),+ protocol.type(), protocol.protocol(), ec))+ {+ impl.protocol_ = protocol;+ impl.have_remote_endpoint_ = false;+ impl.remote_endpoint_ = endpoint_type();+ }+ return ec;+ }++ // Assign a native socket to a socket implementation.+ asio::error_code assign(implementation_type& impl,+ const protocol_type& protocol, const native_handle_type& native_socket,+ asio::error_code& ec)+ {+ if (!do_assign(impl, protocol.type(), native_socket, ec))+ {+ impl.protocol_ = protocol;+ impl.have_remote_endpoint_ = native_socket.have_remote_endpoint();+ impl.remote_endpoint_ = native_socket.remote_endpoint();+ }+ return ec;+ }++ // Get the native socket representation.+ native_handle_type native_handle(implementation_type& impl)+ {+ if (impl.have_remote_endpoint_)+ return native_handle_type(impl.socket_, impl.remote_endpoint_);+ return native_handle_type(impl.socket_);+ }++ // Bind the socket to the specified local endpoint.+ asio::error_code bind(implementation_type& impl,+ const endpoint_type& endpoint, asio::error_code& ec)+ {+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);+ return ec;+ }++ // Set a socket option.+ template <typename Option>+ asio::error_code set_option(implementation_type& impl,+ const Option& option, asio::error_code& ec)+ {+ socket_ops::setsockopt(impl.socket_, impl.state_,+ option.level(impl.protocol_), option.name(impl.protocol_),+ option.data(impl.protocol_), option.size(impl.protocol_), ec);+ return ec;+ }++ // Set a socket option.+ template <typename Option>+ asio::error_code get_option(const implementation_type& impl,+ Option& option, asio::error_code& ec) const+ {+ std::size_t size = option.size(impl.protocol_);+ socket_ops::getsockopt(impl.socket_, impl.state_,+ option.level(impl.protocol_), option.name(impl.protocol_),+ option.data(impl.protocol_), &size, ec);+ if (!ec)+ option.resize(impl.protocol_, size);+ return ec;+ }++ // Get the local endpoint.+ endpoint_type local_endpoint(const implementation_type& impl,+ asio::error_code& ec) const+ {+ endpoint_type endpoint;+ std::size_t addr_len = endpoint.capacity();+ if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))+ return endpoint_type();+ endpoint.resize(addr_len);+ return endpoint;+ }++ // Get the remote endpoint.+ endpoint_type remote_endpoint(const implementation_type& impl,+ asio::error_code& ec) const+ {+ endpoint_type endpoint = impl.remote_endpoint_;+ std::size_t addr_len = endpoint.capacity();+ if (socket_ops::getpeername(impl.socket_, endpoint.data(),+ &addr_len, impl.have_remote_endpoint_, ec))+ return endpoint_type();+ endpoint.resize(addr_len);+ return endpoint;+ }++ // Disable sends or receives on the socket.+ asio::error_code shutdown(base_implementation_type& impl,+ socket_base::shutdown_type what, asio::error_code& ec)+ {+ socket_ops::shutdown(impl.socket_, what, ec);+ return ec;+ }++ // Send a datagram to the specified endpoint. Returns the number of bytes+ // sent.+ template <typename ConstBufferSequence>+ size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,+ const endpoint_type& destination, socket_base::message_flags flags,+ asio::error_code& ec)+ {+ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence> bufs(buffers);++ return socket_ops::sync_sendto(impl.socket_, impl.state_,+ bufs.buffers(), bufs.count(), flags,+ destination.data(), destination.size(), ec);+ }++ // Wait until data can be sent without blocking.+ size_t send_to(implementation_type& impl, const null_buffers&,+ const endpoint_type&, socket_base::message_flags,+ asio::error_code& ec)+ {+ // Wait for socket to become ready.+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);++ return 0;+ }++ // Start an asynchronous send. The data being sent must be valid for the+ // lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_send_to(implementation_type& impl,+ const ConstBufferSequence& buffers, const endpoint_type& destination,+ socket_base::message_flags flags, Handler& handler,+ const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_socket_send_op<+ ConstBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl.cancel_token_, buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_send_to"));++ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence> bufs(buffers);++ start_send_to_op(impl, bufs.buffers(), bufs.count(),+ destination.data(), static_cast<int>(destination.size()),+ flags, p.p);+ p.v = p.p = 0;+ }++ // Start an asynchronous wait until data can be sent without blocking.+ template <typename Handler, typename IoExecutor>+ void async_send_to(implementation_type& impl, const null_buffers&,+ const endpoint_type&, socket_base::message_flags, Handler& handler,+ const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_send_to(null_buffers)"));++ start_reactor_op(impl, select_reactor::write_op, p.p);+ p.v = p.p = 0;+ }++ // Receive a datagram with the endpoint of the sender. Returns the number of+ // bytes received.+ template <typename MutableBufferSequence>+ size_t receive_from(implementation_type& impl,+ const MutableBufferSequence& buffers,+ endpoint_type& sender_endpoint, socket_base::message_flags flags,+ asio::error_code& ec)+ {+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs(buffers);++ std::size_t addr_len = sender_endpoint.capacity();+ std::size_t bytes_recvd = socket_ops::sync_recvfrom(+ impl.socket_, impl.state_, bufs.buffers(), bufs.count(),+ flags, sender_endpoint.data(), &addr_len, ec);++ if (!ec)+ sender_endpoint.resize(addr_len);++ return bytes_recvd;+ }++ // Wait until data can be received without blocking.+ size_t receive_from(implementation_type& impl,+ const null_buffers&, endpoint_type& sender_endpoint,+ socket_base::message_flags, asio::error_code& ec)+ {+ // Wait for socket to become ready.+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);++ // Reset endpoint since it can be given no sensible value at this time.+ sender_endpoint = endpoint_type();++ return 0;+ }++ // Start an asynchronous receive. The buffer for the data being received and+ // the sender_endpoint object must both be valid for the lifetime of the+ // asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_receive_from(implementation_type& impl,+ const MutableBufferSequence& buffers, endpoint_type& sender_endp,+ socket_base::message_flags flags, Handler& handler,+ const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_socket_recvfrom_op<MutableBufferSequence,+ endpoint_type, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(sender_endp, impl.cancel_token_,+ buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_receive_from"));++ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs(buffers);++ start_receive_from_op(impl, bufs.buffers(), bufs.count(),+ sender_endp.data(), flags, &p.p->endpoint_size(), p.p);+ p.v = p.p = 0;+ }++ // Wait until data can be received without blocking.+ template <typename Handler, typename IoExecutor>+ void async_receive_from(implementation_type& impl, const null_buffers&,+ endpoint_type& sender_endpoint, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_receive_from(null_buffers)"));++ // Reset endpoint since it can be given no sensible value at this time.+ sender_endpoint = endpoint_type();++ start_null_buffers_receive_op(impl, flags, p.p);+ p.v = p.p = 0;+ }++ // Accept a new connection.+ template <typename Socket>+ asio::error_code accept(implementation_type& impl, Socket& peer,+ endpoint_type* peer_endpoint, asio::error_code& ec)+ {+ // We cannot accept a socket that is already open.+ if (peer.is_open())+ {+ ec = asio::error::already_open;+ return ec;+ }++ std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;+ socket_holder new_socket(socket_ops::sync_accept(impl.socket_,+ impl.state_, peer_endpoint ? peer_endpoint->data() : 0,+ peer_endpoint ? &addr_len : 0, ec));++ // On success, assign new connection to peer socket object.+ if (new_socket.get() != invalid_socket)+ {+ if (peer_endpoint)+ peer_endpoint->resize(addr_len);+ peer.assign(impl.protocol_, new_socket.get(), ec);+ if (!ec)+ new_socket.release();+ }++ return ec;+ }++ // Start an asynchronous accept. The peer and peer_endpoint objects+ // must be valid until the accept's handler is invoked.+ template <typename Socket, typename Handler, typename IoExecutor>+ void async_accept(implementation_type& impl, Socket& peer,+ endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_socket_accept_op<Socket,+ protocol_type, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ bool enable_connection_aborted =+ (impl.state_ & socket_ops::enable_connection_aborted) != 0;+ p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_,+ peer_endpoint, enable_connection_aborted, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_accept"));++ start_accept_op(impl, peer.is_open(), p.p->new_socket(),+ impl.protocol_.family(), impl.protocol_.type(),+ impl.protocol_.protocol(), p.p->output_buffer(),+ p.p->address_length(), p.p);+ p.v = p.p = 0;+ }++#if defined(ASIO_HAS_MOVE)+ // Start an asynchronous accept. The peer and peer_endpoint objects+ // must be valid until the accept's handler is invoked.+ template <typename PeerIoExecutor, typename Handler, typename IoExecutor>+ void async_move_accept(implementation_type& impl,+ const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_socket_move_accept_op<+ protocol_type, PeerIoExecutor, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ bool enable_connection_aborted =+ (impl.state_ & socket_ops::enable_connection_aborted) != 0;+ p.p = new (p.v) op(*this, impl.socket_, impl.protocol_,+ peer_io_ex, peer_endpoint, enable_connection_aborted,+ handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_accept"));++ start_accept_op(impl, false, p.p->new_socket(),+ impl.protocol_.family(), impl.protocol_.type(),+ impl.protocol_.protocol(), p.p->output_buffer(),+ p.p->address_length(), p.p);+ p.v = p.p = 0;+ }+#endif // defined(ASIO_HAS_MOVE)++ // Connect the socket to the specified endpoint.+ asio::error_code connect(implementation_type& impl,+ const endpoint_type& peer_endpoint, asio::error_code& ec)+ {+ socket_ops::sync_connect(impl.socket_,+ peer_endpoint.data(), peer_endpoint.size(), ec);+ return ec;+ }++ // Start an asynchronous connect.+ template <typename Handler, typename IoExecutor>+ void async_connect(implementation_type& impl,+ const endpoint_type& peer_endpoint, Handler& handler,+ const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_socket_connect_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl.socket_, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_connect"));++ start_connect_op(impl, impl.protocol_.family(), impl.protocol_.type(),+ peer_endpoint.data(), static_cast<int>(peer_endpoint.size()), p.p);+ p.v = p.p = 0;+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_socket_service_base.hpp view
@@ -0,0 +1,600 @@+//+// detail/win_iocp_socket_service_base.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_SOCKET_SERVICE_BASE_HPP+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_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_IOCP)++#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/socket_base.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/operation.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/select_reactor.hpp"+#include "asio/detail/socket_holder.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/win_iocp_io_context.hpp"+#include "asio/detail/win_iocp_null_buffers_op.hpp"+#include "asio/detail/win_iocp_socket_connect_op.hpp"+#include "asio/detail/win_iocp_socket_send_op.hpp"+#include "asio/detail/win_iocp_socket_recv_op.hpp"+#include "asio/detail/win_iocp_socket_recvmsg_op.hpp"+#include "asio/detail/win_iocp_wait_op.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class win_iocp_socket_service_base+{+public:+ // The implementation type of the socket.+ struct base_implementation_type+ {+ // The native socket representation.+ socket_type socket_;++ // The current state of the socket.+ socket_ops::state_type state_;++ // We use a shared pointer as a cancellation token here to work around the+ // broken Windows support for cancellation. MSDN says that when you call+ // closesocket any outstanding WSARecv or WSASend operations will complete+ // with the error ERROR_OPERATION_ABORTED. In practice they complete with+ // ERROR_NETNAME_DELETED, which means you can't tell the difference between+ // a local cancellation and the socket being hard-closed by the peer.+ socket_ops::shared_cancel_token_type cancel_token_;++ // Per-descriptor data used by the reactor.+ select_reactor::per_descriptor_data reactor_data_;++#if defined(ASIO_ENABLE_CANCELIO)+ // The ID of the thread from which it is safe to cancel asynchronous+ // operations. 0 means no asynchronous operations have been started yet.+ // ~0 means asynchronous operations have been started from more than one+ // thread, and cancellation is not supported for the socket.+ DWORD safe_cancellation_thread_id_;+#endif // defined(ASIO_ENABLE_CANCELIO)++ // Pointers to adjacent socket implementations in linked list.+ base_implementation_type* next_;+ base_implementation_type* prev_;+ };++ // Constructor.+ ASIO_DECL win_iocp_socket_service_base(execution_context& context);++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void base_shutdown();++ // Construct a new socket implementation.+ ASIO_DECL void construct(base_implementation_type& impl);++ // Move-construct a new socket implementation.+ ASIO_DECL void base_move_construct(base_implementation_type& impl,+ base_implementation_type& other_impl) ASIO_NOEXCEPT;++ // Move-assign from another socket implementation.+ ASIO_DECL void base_move_assign(base_implementation_type& impl,+ win_iocp_socket_service_base& other_service,+ base_implementation_type& other_impl);++ // Destroy a socket implementation.+ ASIO_DECL void destroy(base_implementation_type& impl);++ // Determine whether the socket is open.+ bool is_open(const base_implementation_type& impl) const+ {+ return impl.socket_ != invalid_socket;+ }++ // Destroy a socket implementation.+ ASIO_DECL asio::error_code close(+ base_implementation_type& impl, asio::error_code& ec);++ // Release ownership of the socket.+ ASIO_DECL socket_type release(+ base_implementation_type& impl, asio::error_code& ec);++ // Cancel all operations associated with the socket.+ ASIO_DECL asio::error_code cancel(+ base_implementation_type& impl, asio::error_code& ec);++ // Determine whether the socket is at the out-of-band data mark.+ bool at_mark(const base_implementation_type& impl,+ asio::error_code& ec) const+ {+ return socket_ops::sockatmark(impl.socket_, ec);+ }++ // Determine the number of bytes available for reading.+ std::size_t available(const base_implementation_type& impl,+ asio::error_code& ec) const+ {+ return socket_ops::available(impl.socket_, ec);+ }++ // Place the socket into the state where it will listen for new connections.+ asio::error_code listen(base_implementation_type& impl,+ int backlog, asio::error_code& ec)+ {+ socket_ops::listen(impl.socket_, backlog, ec);+ return ec;+ }++ // Perform an IO control command on the socket.+ template <typename IO_Control_Command>+ asio::error_code io_control(base_implementation_type& impl,+ IO_Control_Command& command, asio::error_code& ec)+ {+ socket_ops::ioctl(impl.socket_, impl.state_, command.name(),+ static_cast<ioctl_arg_type*>(command.data()), ec);+ return ec;+ }++ // Gets the non-blocking mode of the socket.+ bool non_blocking(const base_implementation_type& impl) const+ {+ return (impl.state_ & socket_ops::user_set_non_blocking) != 0;+ }++ // Sets the non-blocking mode of the socket.+ asio::error_code non_blocking(base_implementation_type& impl,+ bool mode, asio::error_code& ec)+ {+ socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);+ return ec;+ }++ // Gets the non-blocking mode of the native socket implementation.+ bool native_non_blocking(const base_implementation_type& impl) const+ {+ return (impl.state_ & socket_ops::internal_non_blocking) != 0;+ }++ // Sets the non-blocking mode of the native socket implementation.+ asio::error_code native_non_blocking(base_implementation_type& impl,+ bool mode, asio::error_code& ec)+ {+ socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);+ return ec;+ }++ // Wait for the socket to become ready to read, ready to write, or to have+ // pending error conditions.+ asio::error_code wait(base_implementation_type& impl,+ socket_base::wait_type w, asio::error_code& ec)+ {+ switch (w)+ {+ case socket_base::wait_read:+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);+ break;+ case socket_base::wait_write:+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);+ break;+ case socket_base::wait_error:+ socket_ops::poll_error(impl.socket_, impl.state_, -1, ec);+ break;+ default:+ ec = asio::error::invalid_argument;+ break;+ }++ return ec;+ }++ // Asynchronously wait for the socket to become ready to read, ready to+ // write, or to have pending error conditions.+ template <typename Handler, typename IoExecutor>+ void async_wait(base_implementation_type& impl,+ socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_wait_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_wait"));++ switch (w)+ {+ case socket_base::wait_read:+ start_null_buffers_receive_op(impl, 0, p.p);+ break;+ case socket_base::wait_write:+ start_reactor_op(impl, select_reactor::write_op, p.p);+ break;+ case socket_base::wait_error:+ start_reactor_op(impl, select_reactor::except_op, p.p);+ break;+ default:+ p.p->ec_ = asio::error::invalid_argument;+ iocp_service_.post_immediate_completion(p.p, is_continuation);+ break;+ }++ p.v = p.p = 0;+ }++ // Send the given data to the peer. Returns the number of bytes sent.+ template <typename ConstBufferSequence>+ size_t send(base_implementation_type& impl,+ const ConstBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence> bufs(buffers);++ return socket_ops::sync_send(impl.socket_, impl.state_,+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);+ }++ // Wait until data can be sent without blocking.+ size_t send(base_implementation_type& impl, const null_buffers&,+ socket_base::message_flags, asio::error_code& ec)+ {+ // Wait for socket to become ready.+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);++ return 0;+ }++ // Start an asynchronous send. The data being sent must be valid for the+ // lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_send(base_implementation_type& impl,+ const ConstBufferSequence& buffers, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_socket_send_op<+ ConstBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl.cancel_token_, buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_send"));++ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence> bufs(buffers);++ start_send_op(impl, bufs.buffers(), bufs.count(), flags,+ (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(),+ p.p);+ p.v = p.p = 0;+ }++ // Start an asynchronous wait until data can be sent without blocking.+ template <typename Handler, typename IoExecutor>+ void async_send(base_implementation_type& impl, const null_buffers&,+ socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_send(null_buffers)"));++ start_reactor_op(impl, select_reactor::write_op, p.p);+ p.v = p.p = 0;+ }++ // Receive some data from the peer. Returns the number of bytes received.+ template <typename MutableBufferSequence>+ size_t receive(base_implementation_type& impl,+ const MutableBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs(buffers);++ return socket_ops::sync_recv(impl.socket_, impl.state_,+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);+ }++ // Wait until data can be received without blocking.+ size_t receive(base_implementation_type& impl, const null_buffers&,+ socket_base::message_flags, asio::error_code& ec)+ {+ // Wait for socket to become ready.+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);++ return 0;+ }++ // Start an asynchronous receive. The buffer for the data being received+ // must be valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_receive(base_implementation_type& impl,+ const MutableBufferSequence& buffers, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_socket_recv_op<+ MutableBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl.state_, impl.cancel_token_,+ buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_receive"));++ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs(buffers);++ start_receive_op(impl, bufs.buffers(), bufs.count(), flags,+ (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(),+ p.p);+ p.v = p.p = 0;+ }++ // Wait until data can be received without blocking.+ template <typename Handler, typename IoExecutor>+ void async_receive(base_implementation_type& impl,+ const null_buffers&, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_receive(null_buffers)"));++ start_null_buffers_receive_op(impl, flags, p.p);+ p.v = p.p = 0;+ }++ // Receive some data with associated flags. Returns the number of bytes+ // received.+ template <typename MutableBufferSequence>+ size_t receive_with_flags(base_implementation_type& impl,+ const MutableBufferSequence& buffers,+ socket_base::message_flags in_flags,+ socket_base::message_flags& out_flags, asio::error_code& ec)+ {+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs(buffers);++ return socket_ops::sync_recvmsg(impl.socket_, impl.state_,+ bufs.buffers(), bufs.count(), in_flags, out_flags, ec);+ }++ // Wait until data can be received without blocking.+ size_t receive_with_flags(base_implementation_type& impl,+ const null_buffers&, socket_base::message_flags,+ socket_base::message_flags& out_flags, asio::error_code& ec)+ {+ // Wait for socket to become ready.+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);++ // Clear out_flags, since we cannot give it any other sensible value when+ // performing a null_buffers operation.+ out_flags = 0;++ return 0;+ }++ // Start an asynchronous receive. The buffer for the data being received+ // must be valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_receive_with_flags(base_implementation_type& impl,+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,+ socket_base::message_flags& out_flags, Handler& handler,+ const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_socket_recvmsg_op<+ MutableBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl.cancel_token_,+ buffers, out_flags, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_receive_with_flags"));++ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence> bufs(buffers);++ start_receive_op(impl, bufs.buffers(), bufs.count(), in_flags, false, p.p);+ p.v = p.p = 0;+ }++ // Wait until data can be received without blocking.+ template <typename Handler, typename IoExecutor>+ void async_receive_with_flags(base_implementation_type& impl,+ const null_buffers&, socket_base::message_flags in_flags,+ socket_base::message_flags& out_flags, Handler& handler,+ const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef win_iocp_null_buffers_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(impl.cancel_token_, handler, io_ex);++ ASIO_HANDLER_CREATION((context_, *p.p, "socket",+ &impl, impl.socket_, "async_receive_with_flags(null_buffers)"));++ // Reset out_flags since it can be given no sensible value at this time.+ out_flags = 0;++ start_null_buffers_receive_op(impl, in_flags, p.p);+ p.v = p.p = 0;+ }++ // Helper function to restart an asynchronous accept operation.+ ASIO_DECL void restart_accept_op(socket_type s,+ socket_holder& new_socket, int family, int type, int protocol,+ void* output_buffer, DWORD address_length, operation* op);++protected:+ // Open a new socket implementation.+ ASIO_DECL asio::error_code do_open(+ base_implementation_type& impl, int family, int type,+ int protocol, asio::error_code& ec);++ // Assign a native socket to a socket implementation.+ ASIO_DECL asio::error_code do_assign(+ base_implementation_type& impl, int type,+ socket_type native_socket, asio::error_code& ec);++ // Helper function to start an asynchronous send operation.+ ASIO_DECL void start_send_op(base_implementation_type& impl,+ WSABUF* buffers, std::size_t buffer_count,+ socket_base::message_flags flags, bool noop, operation* op);++ // Helper function to start an asynchronous send_to operation.+ ASIO_DECL void start_send_to_op(base_implementation_type& impl,+ WSABUF* buffers, std::size_t buffer_count,+ const socket_addr_type* addr, int addrlen,+ socket_base::message_flags flags, operation* op);++ // Helper function to start an asynchronous receive operation.+ ASIO_DECL void start_receive_op(base_implementation_type& impl,+ WSABUF* buffers, std::size_t buffer_count,+ socket_base::message_flags flags, bool noop, operation* op);++ // Helper function to start an asynchronous null_buffers receive operation.+ ASIO_DECL void start_null_buffers_receive_op(+ base_implementation_type& impl,+ socket_base::message_flags flags, reactor_op* op);++ // Helper function to start an asynchronous receive_from operation.+ ASIO_DECL void start_receive_from_op(base_implementation_type& impl,+ WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,+ socket_base::message_flags flags, int* addrlen, operation* op);++ // Helper function to start an asynchronous accept operation.+ ASIO_DECL void start_accept_op(base_implementation_type& impl,+ bool peer_is_open, socket_holder& new_socket, int family, int type,+ int protocol, void* output_buffer, DWORD address_length, operation* op);++ // Start an asynchronous read or write operation using the reactor.+ ASIO_DECL void start_reactor_op(base_implementation_type& impl,+ int op_type, reactor_op* op);++ // Start the asynchronous connect operation using the reactor.+ ASIO_DECL void start_connect_op(base_implementation_type& impl,+ int family, int type, const socket_addr_type* remote_addr,+ std::size_t remote_addrlen, win_iocp_socket_connect_op_base* op);++ // Helper function to close a socket when the associated object is being+ // destroyed.+ ASIO_DECL void close_for_destruction(base_implementation_type& impl);++ // Update the ID of the thread from which cancellation is safe.+ ASIO_DECL void update_cancellation_thread_id(+ base_implementation_type& impl);++ // Helper function to get the reactor. If no reactor has been created yet, a+ // new one is obtained from the execution context and a pointer to it is+ // cached in this service.+ ASIO_DECL select_reactor& get_reactor();++ // The type of a ConnectEx function pointer, as old SDKs may not provide it.+ typedef BOOL (PASCAL *connect_ex_fn)(SOCKET,+ const socket_addr_type*, int, void*, DWORD, DWORD*, OVERLAPPED*);++ // Helper function to get the ConnectEx pointer. If no ConnectEx pointer has+ // been obtained yet, one is obtained using WSAIoctl and the pointer is+ // cached. Returns a null pointer if ConnectEx is not available.+ ASIO_DECL connect_ex_fn get_connect_ex(+ base_implementation_type& impl, int type);++ // The type of a NtSetInformationFile function pointer.+ typedef LONG (NTAPI *nt_set_info_fn)(HANDLE, ULONG_PTR*, void*, ULONG, ULONG);++ // Helper function to get the NtSetInformationFile function pointer. If no+ // NtSetInformationFile pointer has been obtained yet, one is obtained using+ // GetProcAddress and the pointer is cached. Returns a null pointer if+ // NtSetInformationFile is not available.+ ASIO_DECL nt_set_info_fn get_nt_set_info();++ // Helper function to emulate InterlockedCompareExchangePointer functionality+ // for:+ // - very old Platform SDKs; and+ // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.+ ASIO_DECL void* interlocked_compare_exchange_pointer(+ void** dest, void* exch, void* cmp);++ // Helper function to emulate InterlockedExchangePointer functionality for:+ // - very old Platform SDKs; and+ // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.+ ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val);++ // The execution context used to obtain the reactor, if required.+ execution_context& context_;++ // The IOCP service used for running asynchronous operations and dispatching+ // handlers.+ win_iocp_io_context& iocp_service_;++ // The reactor used for performing connect operations. This object is created+ // only if needed.+ select_reactor* reactor_;++ // Pointer to ConnectEx implementation.+ void* connect_ex_;++ // Pointer to NtSetInformationFile implementation.+ void* nt_set_info_;++ // Mutex to protect access to the linked list of implementations. + asio::detail::mutex mutex_;++ // The head of a linked list of all implementations.+ base_implementation_type* impl_list_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/win_iocp_socket_service_base.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_thread_info.hpp view
@@ -0,0 +1,34 @@+//+// detail/win_iocp_thread_info.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_THREAD_INFO_HPP+#define ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/thread_info_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++struct win_iocp_thread_info : public thread_info_base+{+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_iocp_wait_op.hpp view
@@ -0,0 +1,128 @@+//+// detail/win_iocp_wait_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_IOCP_WAIT_OP_HPP+#define ASIO_DETAIL_WIN_IOCP_WAIT_OP_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_IOCP)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/reactor_op.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename IoExecutor>+class win_iocp_wait_op : public reactor_op+{+public:+ ASIO_DEFINE_HANDLER_PTR(win_iocp_wait_op);++ win_iocp_wait_op(socket_ops::weak_cancel_token_type cancel_token,+ Handler& handler, const IoExecutor& io_ex)+ : reactor_op(asio::error_code(),+ &win_iocp_wait_op::do_perform,+ &win_iocp_wait_op::do_complete),+ cancel_token_(cancel_token),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static status do_perform(reactor_op*)+ {+ return done;+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code& result_ec,+ std::size_t /*bytes_transferred*/)+ {+ asio::error_code ec(result_ec);++ // Take ownership of the operation object.+ win_iocp_wait_op* o(static_cast<win_iocp_wait_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // The reactor may have stored a result in the operation object.+ if (o->ec_)+ ec = o->ec_;++ // Map non-portable errors to their portable counterparts.+ if (ec.value() == ERROR_NETNAME_DELETED)+ {+ if (o->cancel_token_.expired())+ ec = asio::error::operation_aborted;+ else+ ec = asio::error::connection_reset;+ }+ else if (ec.value() == ERROR_PORT_UNREACHABLE)+ {+ ec = asio::error::connection_refused;+ }++ // 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::binder1<Handler, asio::error_code>+ handler(o->handler_, ec);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ socket_ops::weak_cancel_token_type cancel_token_;+ Handler handler_;+ handler_work<Handler, IoExecutor> work_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_IOCP)++#endif // ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_mutex.hpp view
@@ -0,0 +1,78 @@+//+// detail/win_mutex.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_MUTEX_HPP+#define ASIO_DETAIL_WIN_MUTEX_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_WINDOWS)++#include "asio/detail/noncopyable.hpp"+#include "asio/detail/scoped_lock.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class win_mutex+ : private noncopyable+{+public:+ typedef asio::detail::scoped_lock<win_mutex> scoped_lock;++ // Constructor.+ ASIO_DECL win_mutex();++ // Destructor.+ ~win_mutex()+ {+ ::DeleteCriticalSection(&crit_section_);+ }++ // Lock the mutex.+ void lock()+ {+ ::EnterCriticalSection(&crit_section_);+ }++ // Unlock the mutex.+ void unlock()+ {+ ::LeaveCriticalSection(&crit_section_);+ }++private:+ // Initialisation must be performed in a separate function to the constructor+ // since the compiler does not support the use of structured exceptions and+ // C++ exceptions in the same function.+ ASIO_DECL int do_init();++ ::CRITICAL_SECTION crit_section_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/win_mutex.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_WINDOWS)++#endif // ASIO_DETAIL_WIN_MUTEX_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_object_handle_service.hpp view
@@ -0,0 +1,195 @@+//+// detail/win_object_handle_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2011 Boris Schaeling (boris@highscore.de)+//+// 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_WIN_OBJECT_HANDLE_SERVICE_HPP+#define ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_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_WINDOWS_OBJECT_HANDLE)++#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/wait_handler.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#else // defined(ASIO_HAS_IOCP)+# include "asio/detail/scheduler.hpp"+#endif // defined(ASIO_HAS_IOCP)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class win_object_handle_service :+ public execution_context_service_base<win_object_handle_service>+{+public:+ // The native type of an object handle.+ typedef HANDLE native_handle_type;++ // The implementation type of the object handle.+ class implementation_type+ {+ public:+ // Default constructor.+ implementation_type()+ : handle_(INVALID_HANDLE_VALUE),+ wait_handle_(INVALID_HANDLE_VALUE),+ owner_(0),+ next_(0),+ prev_(0)+ {+ }++ private:+ // Only this service will have access to the internal values.+ friend class win_object_handle_service;++ // The native object handle representation. May be accessed or modified+ // without locking the mutex.+ native_handle_type handle_;++ // The handle used to unregister the wait operation. The mutex must be+ // locked when accessing or modifying this member.+ HANDLE wait_handle_;++ // The operations waiting on the object handle. If there is a registered+ // wait then the mutex must be locked when accessing or modifying this+ // member+ op_queue<wait_op> op_queue_;++ // The service instance that owns the object handle implementation.+ win_object_handle_service* owner_;++ // Pointers to adjacent handle implementations in linked list. The mutex+ // must be locked when accessing or modifying these members.+ implementation_type* next_;+ implementation_type* prev_;+ };++ // Constructor.+ ASIO_DECL win_object_handle_service(execution_context& context);++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Construct a new handle implementation.+ ASIO_DECL void construct(implementation_type& impl);++ // Move-construct a new handle implementation.+ ASIO_DECL void move_construct(implementation_type& impl,+ implementation_type& other_impl);++ // Move-assign from another handle implementation.+ ASIO_DECL void move_assign(implementation_type& impl,+ win_object_handle_service& other_service,+ implementation_type& other_impl);++ // Destroy a handle implementation.+ ASIO_DECL void destroy(implementation_type& impl);++ // Assign a native handle to a handle implementation.+ ASIO_DECL asio::error_code assign(implementation_type& impl,+ const native_handle_type& handle, asio::error_code& ec);++ // Determine whether the handle is open.+ bool is_open(const implementation_type& impl) const+ {+ return impl.handle_ != INVALID_HANDLE_VALUE && impl.handle_ != 0;+ }++ // Destroy a handle implementation.+ ASIO_DECL asio::error_code close(implementation_type& impl,+ asio::error_code& ec);++ // Get the native handle representation.+ native_handle_type native_handle(const implementation_type& impl) const+ {+ return impl.handle_;+ }++ // Cancel all operations associated with the handle.+ ASIO_DECL asio::error_code cancel(implementation_type& impl,+ asio::error_code& ec);++ // Perform a synchronous wait for the object to enter a signalled state.+ ASIO_DECL void wait(implementation_type& impl,+ asio::error_code& ec);++ /// Start an asynchronous wait.+ template <typename Handler, typename IoExecutor>+ void async_wait(implementation_type& impl,+ Handler& handler, const IoExecutor& io_ex)+ {+ // Allocate and construct an operation to wrap the handler.+ typedef wait_handler<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(handler, io_ex);++ ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "object_handle",+ &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "async_wait"));++ start_wait_op(impl, p.p);+ p.v = p.p = 0;+ }++private:+ // Helper function to start an asynchronous wait operation.+ ASIO_DECL void start_wait_op(implementation_type& impl, wait_op* op);++ // Helper function to register a wait operation.+ ASIO_DECL void register_wait_callback(+ implementation_type& impl, mutex::scoped_lock& lock);++ // Callback function invoked when the registered wait completes.+ static ASIO_DECL VOID CALLBACK wait_callback(+ PVOID param, BOOLEAN timeout);++ // The scheduler used to post completions.+#if defined(ASIO_HAS_IOCP)+ typedef class win_iocp_io_context scheduler_impl;+#else+ typedef class scheduler scheduler_impl;+#endif+ scheduler_impl& scheduler_;++ // Mutex to protect access to internal state.+ mutex mutex_;++ // The head of a linked list of all implementations.+ implementation_type* impl_list_;++ // Flag to indicate that the dispatcher has been shut down.+ bool shutdown_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/win_object_handle_service.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)++#endif // ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_static_mutex.hpp view
@@ -0,0 +1,74 @@+//+// detail/win_static_mutex.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_STATIC_MUTEX_HPP+#define ASIO_DETAIL_WIN_STATIC_MUTEX_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_WINDOWS)++#include "asio/detail/scoped_lock.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++struct win_static_mutex+{+ typedef asio::detail::scoped_lock<win_static_mutex> scoped_lock;++ // Initialise the mutex.+ ASIO_DECL void init();++ // Initialisation must be performed in a separate function to the "public"+ // init() function since the compiler does not support the use of structured+ // exceptions and C++ exceptions in the same function.+ ASIO_DECL int do_init();++ // Lock the mutex.+ void lock()+ {+ ::EnterCriticalSection(&crit_section_);+ }++ // Unlock the mutex.+ void unlock()+ {+ ::LeaveCriticalSection(&crit_section_);+ }++ bool initialised_;+ ::CRITICAL_SECTION crit_section_;+};++#if defined(UNDER_CE)+# define ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0 } }+#else // defined(UNDER_CE)+# define ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0, 0 } }+#endif // defined(UNDER_CE)++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/win_static_mutex.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_WINDOWS)++#endif // ASIO_DETAIL_WIN_STATIC_MUTEX_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_thread.hpp view
@@ -0,0 +1,147 @@+//+// detail/win_thread.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_THREAD_HPP+#define ASIO_DETAIL_WIN_THREAD_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_WINDOWS) \+ && !defined(ASIO_WINDOWS_APP) \+ && !defined(UNDER_CE)++#include <cstddef>+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++ASIO_DECL unsigned int __stdcall win_thread_function(void* arg);++#if defined(WINVER) && (WINVER < 0x0500)+ASIO_DECL void __stdcall apc_function(ULONG data);+#else+ASIO_DECL void __stdcall apc_function(ULONG_PTR data);+#endif++template <typename T>+class win_thread_base+{+public:+ static bool terminate_threads()+ {+ return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0;+ }++ static void set_terminate_threads(bool b)+ {+ ::InterlockedExchange(&terminate_threads_, b ? 1 : 0);+ }++private:+ static long terminate_threads_;+};++template <typename T>+long win_thread_base<T>::terminate_threads_ = 0;++class win_thread+ : private noncopyable,+ public win_thread_base<win_thread>+{+public:+ // Constructor.+ template <typename Function>+ win_thread(Function f, unsigned int stack_size = 0)+ : thread_(0),+ exit_event_(0)+ {+ start_thread(new func<Function>(f), stack_size);+ }++ // Destructor.+ ASIO_DECL ~win_thread();++ // Wait for the thread to exit.+ ASIO_DECL void join();++ // Get number of CPUs.+ ASIO_DECL static std::size_t hardware_concurrency();++private:+ friend ASIO_DECL unsigned int __stdcall win_thread_function(void* arg);++#if defined(WINVER) && (WINVER < 0x0500)+ friend ASIO_DECL void __stdcall apc_function(ULONG);+#else+ friend ASIO_DECL void __stdcall apc_function(ULONG_PTR);+#endif++ class func_base+ {+ public:+ virtual ~func_base() {}+ virtual void run() = 0;+ ::HANDLE entry_event_;+ ::HANDLE exit_event_;+ };++ struct auto_func_base_ptr+ {+ func_base* ptr;+ ~auto_func_base_ptr() { delete ptr; }+ };++ template <typename Function>+ class func+ : public func_base+ {+ public:+ func(Function f)+ : f_(f)+ {+ }++ virtual void run()+ {+ f_();+ }++ private:+ Function f_;+ };++ ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size);++ ::HANDLE thread_;+ ::HANDLE exit_event_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/win_thread.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_WINDOWS)+ // && !defined(ASIO_WINDOWS_APP)+ // && !defined(UNDER_CE)++#endif // ASIO_DETAIL_WIN_THREAD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/win_tss_ptr.hpp view
@@ -0,0 +1,79 @@+//+// detail/win_tss_ptr.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WIN_TSS_PTR_HPP+#define ASIO_DETAIL_WIN_TSS_PTR_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_WINDOWS)++#include "asio/detail/noncopyable.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Helper function to create thread-specific storage.+ASIO_DECL DWORD win_tss_ptr_create();++template <typename T>+class win_tss_ptr+ : private noncopyable+{+public:+ // Constructor.+ win_tss_ptr()+ : tss_key_(win_tss_ptr_create())+ {+ }++ // Destructor.+ ~win_tss_ptr()+ {+ ::TlsFree(tss_key_);+ }++ // Get the value.+ operator T*() const+ {+ return static_cast<T*>(::TlsGetValue(tss_key_));+ }++ // Set the value.+ void operator=(T* value)+ {+ ::TlsSetValue(tss_key_, value);+ }++private:+ // Thread-specific storage to allow unlocked access to determine whether a+ // thread is a member of the pool.+ DWORD tss_key_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/win_tss_ptr.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_WINDOWS)++#endif // ASIO_DETAIL_WIN_TSS_PTR_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winapp_thread.hpp view
@@ -0,0 +1,124 @@+//+// detail/winapp_thread.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINAPP_THREAD_HPP+#define ASIO_DETAIL_WINAPP_THREAD_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_WINDOWS) && defined(ASIO_WINDOWS_APP)++#include "asio/detail/noncopyable.hpp"+#include "asio/detail/scoped_ptr.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++DWORD WINAPI winapp_thread_function(LPVOID arg);++class winapp_thread+ : private noncopyable+{+public:+ // Constructor.+ template <typename Function>+ winapp_thread(Function f, unsigned int = 0)+ {+ scoped_ptr<func_base> arg(new func<Function>(f));+ DWORD thread_id = 0;+ thread_ = ::CreateThread(0, 0, winapp_thread_function,+ arg.get(), 0, &thread_id);+ if (!thread_)+ {+ DWORD last_error = ::GetLastError();+ asio::error_code ec(last_error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "thread");+ }+ arg.release();+ }++ // Destructor.+ ~winapp_thread()+ {+ ::CloseHandle(thread_);+ }++ // Wait for the thread to exit.+ void join()+ {+ ::WaitForSingleObjectEx(thread_, INFINITE, false);+ }++ // Get number of CPUs.+ static std::size_t hardware_concurrency()+ {+ SYSTEM_INFO system_info;+ ::GetNativeSystemInfo(&system_info);+ return system_info.dwNumberOfProcessors;+ }++private:+ friend DWORD WINAPI winapp_thread_function(LPVOID arg);++ class func_base+ {+ public:+ virtual ~func_base() {}+ virtual void run() = 0;+ };++ template <typename Function>+ class func+ : public func_base+ {+ public:+ func(Function f)+ : f_(f)+ {+ }++ virtual void run()+ {+ f_();+ }++ private:+ Function f_;+ };++ ::HANDLE thread_;+};++inline DWORD WINAPI winapp_thread_function(LPVOID arg)+{+ scoped_ptr<winapp_thread::func_base> func(+ static_cast<winapp_thread::func_base*>(arg));+ func->run();+ return 0;+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS) && defined(ASIO_WINDOWS_APP)++#endif // ASIO_DETAIL_WINAPP_THREAD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/wince_thread.hpp view
@@ -0,0 +1,124 @@+//+// detail/wince_thread.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINCE_THREAD_HPP+#define ASIO_DETAIL_WINCE_THREAD_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_WINDOWS) && defined(UNDER_CE)++#include "asio/detail/noncopyable.hpp"+#include "asio/detail/scoped_ptr.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++DWORD WINAPI wince_thread_function(LPVOID arg);++class wince_thread+ : private noncopyable+{+public:+ // Constructor.+ template <typename Function>+ wince_thread(Function f, unsigned int = 0)+ {+ scoped_ptr<func_base> arg(new func<Function>(f));+ DWORD thread_id = 0;+ thread_ = ::CreateThread(0, 0, wince_thread_function,+ arg.get(), 0, &thread_id);+ if (!thread_)+ {+ DWORD last_error = ::GetLastError();+ asio::error_code ec(last_error,+ asio::error::get_system_category());+ asio::detail::throw_error(ec, "thread");+ }+ arg.release();+ }++ // Destructor.+ ~wince_thread()+ {+ ::CloseHandle(thread_);+ }++ // Wait for the thread to exit.+ void join()+ {+ ::WaitForSingleObject(thread_, INFINITE);+ }++ // Get number of CPUs.+ static std::size_t hardware_concurrency()+ {+ SYSTEM_INFO system_info;+ ::GetSystemInfo(&system_info);+ return system_info.dwNumberOfProcessors;+ }++private:+ friend DWORD WINAPI wince_thread_function(LPVOID arg);++ class func_base+ {+ public:+ virtual ~func_base() {}+ virtual void run() = 0;+ };++ template <typename Function>+ class func+ : public func_base+ {+ public:+ func(Function f)+ : f_(f)+ {+ }++ virtual void run()+ {+ f_();+ }++ private:+ Function f_;+ };++ ::HANDLE thread_;+};++inline DWORD WINAPI wince_thread_function(LPVOID arg)+{+ scoped_ptr<wince_thread::func_base> func(+ static_cast<wince_thread::func_base*>(arg));+ func->run();+ return 0;+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS) && defined(UNDER_CE)++#endif // ASIO_DETAIL_WINCE_THREAD_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winrt_async_manager.hpp view
@@ -0,0 +1,305 @@+//+// detail/winrt_async_manager.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINRT_ASYNC_MANAGER_HPP+#define ASIO_DETAIL_WINRT_ASYNC_MANAGER_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_WINDOWS_RUNTIME)++#include <future>+#include "asio/detail/atomic_count.hpp"+#include "asio/detail/winrt_async_op.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#else // defined(ASIO_HAS_IOCP)+# include "asio/detail/scheduler.hpp"+#endif // defined(ASIO_HAS_IOCP)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class winrt_async_manager+ : public execution_context_service_base<winrt_async_manager>+{+public:+ // Constructor.+ winrt_async_manager(execution_context& context)+ : execution_context_service_base<winrt_async_manager>(context),+ scheduler_(use_service<scheduler_impl>(context)),+ outstanding_ops_(1)+ {+ }++ // Destructor.+ ~winrt_async_manager()+ {+ }++ // Destroy all user-defined handler objects owned by the service.+ void shutdown()+ {+ if (--outstanding_ops_ > 0)+ {+ // Block until last operation is complete.+ std::future<void> f = promise_.get_future();+ f.wait();+ }+ }++ void sync(Windows::Foundation::IAsyncAction^ action,+ asio::error_code& ec)+ {+ using namespace Windows::Foundation;+ using Windows::Foundation::AsyncStatus;++ auto promise = std::make_shared<std::promise<asio::error_code>>();+ auto future = promise->get_future();++ action->Completed = ref new AsyncActionCompletedHandler(+ [promise](IAsyncAction^ action, AsyncStatus status)+ {+ switch (status)+ {+ case AsyncStatus::Canceled:+ promise->set_value(asio::error::operation_aborted);+ break;+ case AsyncStatus::Error:+ case AsyncStatus::Completed:+ default:+ asio::error_code ec(+ action->ErrorCode.Value,+ asio::system_category());+ promise->set_value(ec);+ break;+ }+ });++ ec = future.get();+ }++ template <typename TResult>+ TResult sync(Windows::Foundation::IAsyncOperation<TResult>^ operation,+ asio::error_code& ec)+ {+ using namespace Windows::Foundation;+ using Windows::Foundation::AsyncStatus;++ auto promise = std::make_shared<std::promise<asio::error_code>>();+ auto future = promise->get_future();++ operation->Completed = ref new AsyncOperationCompletedHandler<TResult>(+ [promise](IAsyncOperation<TResult>^ operation, AsyncStatus status)+ {+ switch (status)+ {+ case AsyncStatus::Canceled:+ promise->set_value(asio::error::operation_aborted);+ break;+ case AsyncStatus::Error:+ case AsyncStatus::Completed:+ default:+ asio::error_code ec(+ operation->ErrorCode.Value,+ asio::system_category());+ promise->set_value(ec);+ break;+ }+ });++ ec = future.get();+ return operation->GetResults();+ }++ template <typename TResult, typename TProgress>+ TResult sync(+ Windows::Foundation::IAsyncOperationWithProgress<+ TResult, TProgress>^ operation,+ asio::error_code& ec)+ {+ using namespace Windows::Foundation;+ using Windows::Foundation::AsyncStatus;++ auto promise = std::make_shared<std::promise<asio::error_code>>();+ auto future = promise->get_future();++ operation->Completed+ = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>(+ [promise](IAsyncOperationWithProgress<TResult, TProgress>^ operation,+ AsyncStatus status)+ {+ switch (status)+ {+ case AsyncStatus::Canceled:+ promise->set_value(asio::error::operation_aborted);+ break;+ case AsyncStatus::Started:+ break;+ case AsyncStatus::Error:+ case AsyncStatus::Completed:+ default:+ asio::error_code ec(+ operation->ErrorCode.Value,+ asio::system_category());+ promise->set_value(ec);+ break;+ }+ });++ ec = future.get();+ return operation->GetResults();+ }++ void async(Windows::Foundation::IAsyncAction^ action,+ winrt_async_op<void>* handler)+ {+ using namespace Windows::Foundation;+ using Windows::Foundation::AsyncStatus;++ auto on_completed = ref new AsyncActionCompletedHandler(+ [this, handler](IAsyncAction^ action, AsyncStatus status)+ {+ switch (status)+ {+ case AsyncStatus::Canceled:+ handler->ec_ = asio::error::operation_aborted;+ break;+ case AsyncStatus::Started:+ return;+ case AsyncStatus::Completed:+ case AsyncStatus::Error:+ default:+ handler->ec_ = asio::error_code(+ action->ErrorCode.Value,+ asio::system_category());+ break;+ }+ scheduler_.post_deferred_completion(handler);+ if (--outstanding_ops_ == 0)+ promise_.set_value();+ });++ scheduler_.work_started();+ ++outstanding_ops_;+ action->Completed = on_completed;+ }++ template <typename TResult>+ void async(Windows::Foundation::IAsyncOperation<TResult>^ operation,+ winrt_async_op<TResult>* handler)+ {+ using namespace Windows::Foundation;+ using Windows::Foundation::AsyncStatus;++ auto on_completed = ref new AsyncOperationCompletedHandler<TResult>(+ [this, handler](IAsyncOperation<TResult>^ operation, AsyncStatus status)+ {+ switch (status)+ {+ case AsyncStatus::Canceled:+ handler->ec_ = asio::error::operation_aborted;+ break;+ case AsyncStatus::Started:+ return;+ case AsyncStatus::Completed:+ handler->result_ = operation->GetResults();+ // Fall through.+ case AsyncStatus::Error:+ default:+ handler->ec_ = asio::error_code(+ operation->ErrorCode.Value,+ asio::system_category());+ break;+ }+ scheduler_.post_deferred_completion(handler);+ if (--outstanding_ops_ == 0)+ promise_.set_value();+ });++ scheduler_.work_started();+ ++outstanding_ops_;+ operation->Completed = on_completed;+ }++ template <typename TResult, typename TProgress>+ void async(+ Windows::Foundation::IAsyncOperationWithProgress<+ TResult, TProgress>^ operation,+ winrt_async_op<TResult>* handler)+ {+ using namespace Windows::Foundation;+ using Windows::Foundation::AsyncStatus;++ auto on_completed+ = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>(+ [this, handler](IAsyncOperationWithProgress<+ TResult, TProgress>^ operation, AsyncStatus status)+ {+ switch (status)+ {+ case AsyncStatus::Canceled:+ handler->ec_ = asio::error::operation_aborted;+ break;+ case AsyncStatus::Started:+ return;+ case AsyncStatus::Completed:+ handler->result_ = operation->GetResults();+ // Fall through.+ case AsyncStatus::Error:+ default:+ handler->ec_ = asio::error_code(+ operation->ErrorCode.Value,+ asio::system_category());+ break;+ }+ scheduler_.post_deferred_completion(handler);+ if (--outstanding_ops_ == 0)+ promise_.set_value();+ });++ scheduler_.work_started();+ ++outstanding_ops_;+ operation->Completed = on_completed;+ }++private:+ // The scheduler implementation used to post completed handlers.+#if defined(ASIO_HAS_IOCP)+ typedef class win_iocp_io_context scheduler_impl;+#else+ typedef class scheduler scheduler_impl;+#endif+ scheduler_impl& scheduler_;++ // Count of outstanding operations.+ atomic_count outstanding_ops_;++ // Used to keep wait for outstanding operations to complete.+ std::promise<void> promise_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winrt_async_op.hpp view
@@ -0,0 +1,65 @@+//+// detail/winrt_async_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINRT_ASYNC_OP_HPP+#define ASIO_DETAIL_WINRT_ASYNC_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/operation.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename TResult>+class winrt_async_op+ : public operation+{+public:+ // The error code to be passed to the completion handler.+ asio::error_code ec_;++ // The result of the operation, to be passed to the completion handler.+ TResult result_;++protected:+ winrt_async_op(func_type complete_func)+ : operation(complete_func),+ result_()+ {+ }+};++template <>+class winrt_async_op<void>+ : public operation+{+public:+ // The error code to be passed to the completion handler.+ asio::error_code ec_;++protected:+ winrt_async_op(func_type complete_func)+ : operation(complete_func)+ {+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_WINRT_ASYNC_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winrt_resolve_op.hpp view
@@ -0,0 +1,125 @@+//+// detail/winrt_resolve_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINRT_RESOLVE_OP_HPP+#define ASIO_DETAIL_WINRT_RESOLVE_OP_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_WINDOWS_RUNTIME)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/winrt_async_op.hpp"+#include "asio/ip/basic_resolver_results.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Protocol, typename Handler, typename IoExecutor>+class winrt_resolve_op :+ public winrt_async_op<+ Windows::Foundation::Collections::IVectorView<+ Windows::Networking::EndpointPair^>^>+{+public:+ ASIO_DEFINE_HANDLER_PTR(winrt_resolve_op);++ typedef typename Protocol::endpoint endpoint_type;+ typedef asio::ip::basic_resolver_query<Protocol> query_type;+ typedef asio::ip::basic_resolver_results<Protocol> results_type;++ winrt_resolve_op(const query_type& query,+ Handler& handler, const IoExecutor& io_ex)+ : winrt_async_op<+ Windows::Foundation::Collections::IVectorView<+ Windows::Networking::EndpointPair^>^>(+ &winrt_resolve_op::do_complete),+ query_(query),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code&, std::size_t)+ {+ // Take ownership of the operation object.+ winrt_resolve_op* o(static_cast<winrt_resolve_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ results_type results = results_type();+ if (!o->ec_)+ {+ try+ {+ results = results_type::create(o->result_, o->query_.hints(),+ o->query_.host_name(), o->query_.service_name());+ }+ catch (Platform::Exception^ e)+ {+ o->ec_ = asio::error_code(e->HResult,+ asio::system_category());+ }+ }++ // 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, results_type>+ handler(o->handler_, o->ec_, results);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ query_type query_;+ Handler handler_;+ handler_work<Handler, IoExecutor> executor_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_WINRT_RESOLVE_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winrt_resolver_service.hpp view
@@ -0,0 +1,212 @@+//+// detail/winrt_resolver_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINRT_RESOLVER_SERVICE_HPP+#define ASIO_DETAIL_WINRT_RESOLVER_SERVICE_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_WINDOWS_RUNTIME)++#include "asio/ip/basic_resolver_query.hpp"+#include "asio/ip/basic_resolver_results.hpp"+#include "asio/post.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/winrt_async_manager.hpp"+#include "asio/detail/winrt_resolve_op.hpp"+#include "asio/detail/winrt_utils.hpp"++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#else // defined(ASIO_HAS_IOCP)+# include "asio/detail/scheduler.hpp"+#endif // defined(ASIO_HAS_IOCP)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Protocol>+class winrt_resolver_service :+ public execution_context_service_base<winrt_resolver_service<Protocol> >+{+public:+ // The implementation type of the resolver. A cancellation token is used to+ // indicate to the asynchronous operation that the operation has been+ // cancelled.+ typedef socket_ops::shared_cancel_token_type implementation_type;++ // The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ // The query type.+ typedef asio::ip::basic_resolver_query<Protocol> query_type;++ // The results type.+ typedef asio::ip::basic_resolver_results<Protocol> results_type;++ // Constructor.+ winrt_resolver_service(execution_context& context)+ : execution_context_service_base<+ winrt_resolver_service<Protocol> >(context),+ scheduler_(use_service<scheduler_impl>(context)),+ async_manager_(use_service<winrt_async_manager>(context))+ {+ }++ // Destructor.+ ~winrt_resolver_service()+ {+ }++ // Destroy all user-defined handler objects owned by the service.+ void shutdown()+ {+ }++ // Perform any fork-related housekeeping.+ void notify_fork(execution_context::fork_event)+ {+ }++ // Construct a new resolver implementation.+ void construct(implementation_type&)+ {+ }++ // Move-construct a new resolver implementation.+ void move_construct(implementation_type&,+ implementation_type&)+ {+ }++ // Move-assign from another resolver implementation.+ void move_assign(implementation_type&,+ winrt_resolver_service&, implementation_type&)+ {+ }++ // Destroy a resolver implementation.+ void destroy(implementation_type&)+ {+ }++ // Cancel pending asynchronous operations.+ void cancel(implementation_type&)+ {+ }++ // Resolve a query to a list of entries.+ results_type resolve(implementation_type&,+ const query_type& query, asio::error_code& ec)+ {+ try+ {+ using namespace Windows::Networking::Sockets;+ auto endpoint_pairs = async_manager_.sync(+ DatagramSocket::GetEndpointPairsAsync(+ winrt_utils::host_name(query.host_name()),+ winrt_utils::string(query.service_name())), ec);++ if (ec)+ return results_type();++ return results_type::create(+ endpoint_pairs, query.hints(),+ query.host_name(), query.service_name());+ }+ catch (Platform::Exception^ e)+ {+ ec = asio::error_code(e->HResult,+ asio::system_category());+ return results_type();+ }+ }++ // Asynchronously resolve a query to a list of entries.+ template <typename Handler, typename IoExecutor>+ void async_resolve(implementation_type& impl, const query_type& query,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef winrt_resolve_op<Protocol, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(query, handler, io_ex);++ ASIO_HANDLER_CREATION((scheduler_.context(),+ *p.p, "resolver", &impl, 0, "async_resolve"));+ (void)impl;++ try+ {+ using namespace Windows::Networking::Sockets;+ async_manager_.async(DatagramSocket::GetEndpointPairsAsync(+ winrt_utils::host_name(query.host_name()),+ winrt_utils::string(query.service_name())), p.p);+ p.v = p.p = 0;+ }+ catch (Platform::Exception^ e)+ {+ p.p->ec_ = asio::error_code(+ e->HResult, asio::system_category());+ scheduler_.post_immediate_completion(p.p, is_continuation);+ p.v = p.p = 0;+ }+ }++ // Resolve an endpoint to a list of entries.+ results_type resolve(implementation_type&,+ const endpoint_type&, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return results_type();+ }++ // Asynchronously resolve an endpoint to a list of entries.+ template <typename Handler, typename IoExecutor>+ void async_resolve(implementation_type&, const endpoint_type&,+ Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const results_type results;+ asio::post(io_ex, detail::bind_handler(handler, ec, results));+ }++private:+ // The scheduler implementation used for delivering completions.+#if defined(ASIO_HAS_IOCP)+ typedef class win_iocp_io_context scheduler_impl;+#else+ typedef class scheduler scheduler_impl;+#endif+ scheduler_impl& scheduler_;++ winrt_async_manager& async_manager_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_connect_op.hpp view
@@ -0,0 +1,98 @@+//+// detail/winrt_socket_connect_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINRT_SOCKET_CONNECT_OP_HPP+#define ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_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_WINDOWS_RUNTIME)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/winrt_async_op.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename IoExecutor>+class winrt_socket_connect_op :+ public winrt_async_op<void>+{+public:+ ASIO_DEFINE_HANDLER_PTR(winrt_socket_connect_op);++ winrt_socket_connect_op(Handler& handler, const IoExecutor& io_ex)+ : winrt_async_op<void>(&winrt_socket_connect_op::do_complete),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code&, std::size_t)+ {+ // Take ownership of the operation object.+ winrt_socket_connect_op* o(static_cast<winrt_socket_connect_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++ // 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::binder1<Handler, asio::error_code>+ handler(o->handler_, o->ec_);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ Handler handler_;+ handler_work<Handler, IoExecutor> executor_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_recv_op.hpp view
@@ -0,0 +1,119 @@+//+// detail/winrt_socket_recv_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINRT_SOCKET_RECV_OP_HPP+#define ASIO_DETAIL_WINRT_SOCKET_RECV_OP_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_WINDOWS_RUNTIME)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/winrt_async_op.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename MutableBufferSequence, typename Handler, typename IoExecutor>+class winrt_socket_recv_op :+ public winrt_async_op<Windows::Storage::Streams::IBuffer^>+{+public:+ ASIO_DEFINE_HANDLER_PTR(winrt_socket_recv_op);++ winrt_socket_recv_op(const MutableBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ : winrt_async_op<Windows::Storage::Streams::IBuffer^>(+ &winrt_socket_recv_op::do_complete),+ buffers_(buffers),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code&, std::size_t)+ {+ // Take ownership of the operation object.+ winrt_socket_recv_op* o(static_cast<winrt_socket_recv_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ // Check whether buffers are still valid.+ if (owner)+ {+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::validate(o->buffers_);+ }+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)++ std::size_t bytes_transferred = o->result_ ? o->result_->Length : 0;+ if (bytes_transferred == 0 && !o->ec_ &&+ !buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::all_empty(o->buffers_))+ {+ o->ec_ = asio::error::eof;+ }++ // 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_, bytes_transferred);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ MutableBufferSequence buffers_;+ Handler handler_;+ handler_work<Handler, IoExecutor> executor_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winrt_socket_send_op.hpp view
@@ -0,0 +1,110 @@+//+// detail/winrt_socket_send_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINRT_SOCKET_SEND_OP_HPP+#define ASIO_DETAIL_WINRT_SOCKET_SEND_OP_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_WINDOWS_RUNTIME)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_work.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/winrt_async_op.hpp"+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+class winrt_socket_send_op :+ public winrt_async_op<unsigned int>+{+public:+ ASIO_DEFINE_HANDLER_PTR(winrt_socket_send_op);++ winrt_socket_send_op(const ConstBufferSequence& buffers,+ Handler& handler, const IoExecutor& io_ex)+ : winrt_async_op<unsigned int>(&winrt_socket_send_op::do_complete),+ buffers_(buffers),+ handler_(ASIO_MOVE_CAST(Handler)(handler)),+ work_(handler_, io_ex)+ {+ }++ static void do_complete(void* owner, operation* base,+ const asio::error_code&, std::size_t)+ {+ // Take ownership of the operation object.+ winrt_socket_send_op* o(static_cast<winrt_socket_send_op*>(base));+ ptr p = { asio::detail::addressof(o->handler_), o, o };++ ASIO_HANDLER_COMPLETION((*o));++ // Take ownership of the operation's outstanding work.+ handler_work<Handler, IoExecutor> w(+ ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(+ o->work_));++#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)+ // Check whether buffers are still valid.+ if (owner)+ {+ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::validate(o->buffers_);+ }+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)++ // 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->result_);+ p.h = asio::detail::addressof(handler.handler_);+ p.reset();++ // Make the upcall if required.+ if (owner)+ {+ fenced_block b(fenced_block::half);+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));+ w.complete(handler, handler.handler_);+ ASIO_HANDLER_INVOCATION_END;+ }+ }++private:+ ConstBufferSequence buffers_;+ Handler handler_;+ handler_work<Handler, IoExecutor> executor_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winrt_ssocket_service.hpp view
@@ -0,0 +1,250 @@+//+// detail/winrt_ssocket_service.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINRT_SSOCKET_SERVICE_HPP+#define ASIO_DETAIL_WINRT_SSOCKET_SERVICE_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_WINDOWS_RUNTIME)++#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/winrt_socket_connect_op.hpp"+#include "asio/detail/winrt_ssocket_service_base.hpp"+#include "asio/detail/winrt_utils.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Protocol>+class winrt_ssocket_service :+ public execution_context_service_base<winrt_ssocket_service<Protocol> >,+ public winrt_ssocket_service_base+{+public:+ // The protocol type.+ typedef Protocol protocol_type;++ // The endpoint type.+ typedef typename Protocol::endpoint endpoint_type;++ // The native type of a socket.+ typedef Windows::Networking::Sockets::StreamSocket^ native_handle_type;++ // The implementation type of the socket.+ struct implementation_type : base_implementation_type+ {+ // Default constructor.+ implementation_type()+ : base_implementation_type(),+ protocol_(endpoint_type().protocol())+ {+ }++ // The protocol associated with the socket.+ protocol_type protocol_;+ };++ // Constructor.+ winrt_ssocket_service(execution_context& context)+ : execution_context_service_base<winrt_ssocket_service<Protocol> >(context),+ winrt_ssocket_service_base(context)+ {+ }++ // Destroy all user-defined handler objects owned by the service.+ void shutdown()+ {+ this->base_shutdown();+ }++ // Move-construct a new socket implementation.+ void move_construct(implementation_type& impl,+ implementation_type& other_impl) ASIO_NOEXCEPT+ {+ this->base_move_construct(impl, other_impl);++ impl.protocol_ = other_impl.protocol_;+ other_impl.protocol_ = endpoint_type().protocol();+ }++ // Move-assign from another socket implementation.+ void move_assign(implementation_type& impl,+ winrt_ssocket_service& other_service,+ implementation_type& other_impl)+ {+ this->base_move_assign(impl, other_service, other_impl);++ impl.protocol_ = other_impl.protocol_;+ other_impl.protocol_ = endpoint_type().protocol();+ }++ // Move-construct a new socket implementation from another protocol type.+ template <typename Protocol1>+ void converting_move_construct(implementation_type& impl,+ winrt_ssocket_service<Protocol1>&,+ typename winrt_ssocket_service<+ Protocol1>::implementation_type& other_impl)+ {+ this->base_move_construct(impl, other_impl);++ impl.protocol_ = protocol_type(other_impl.protocol_);+ other_impl.protocol_ = typename Protocol1::endpoint().protocol();+ }++ // Open a new socket implementation.+ asio::error_code open(implementation_type& impl,+ const protocol_type& protocol, asio::error_code& ec)+ {+ if (is_open(impl))+ {+ ec = asio::error::already_open;+ return ec;+ }++ try+ {+ impl.socket_ = ref new Windows::Networking::Sockets::StreamSocket;+ impl.protocol_ = protocol;+ ec = asio::error_code();+ }+ catch (Platform::Exception^ e)+ {+ ec = asio::error_code(e->HResult,+ asio::system_category());+ }++ return ec;+ }++ // Assign a native socket to a socket implementation.+ asio::error_code assign(implementation_type& impl,+ const protocol_type& protocol, const native_handle_type& native_socket,+ asio::error_code& ec)+ {+ if (is_open(impl))+ {+ ec = asio::error::already_open;+ return ec;+ }++ impl.socket_ = native_socket;+ impl.protocol_ = protocol;+ ec = asio::error_code();++ return ec;+ }++ // Bind the socket to the specified local endpoint.+ asio::error_code bind(implementation_type&,+ const endpoint_type&, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Get the local endpoint.+ endpoint_type local_endpoint(const implementation_type& impl,+ asio::error_code& ec) const+ {+ endpoint_type endpoint;+ endpoint.resize(do_get_endpoint(impl, true,+ endpoint.data(), endpoint.size(), ec));+ return endpoint;+ }++ // Get the remote endpoint.+ endpoint_type remote_endpoint(const implementation_type& impl,+ asio::error_code& ec) const+ {+ endpoint_type endpoint;+ endpoint.resize(do_get_endpoint(impl, false,+ endpoint.data(), endpoint.size(), ec));+ return endpoint;+ }++ // Disable sends or receives on the socket.+ asio::error_code shutdown(implementation_type&,+ socket_base::shutdown_type, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Set a socket option.+ template <typename Option>+ asio::error_code set_option(implementation_type& impl,+ const Option& option, asio::error_code& ec)+ {+ return do_set_option(impl, option.level(impl.protocol_),+ option.name(impl.protocol_), option.data(impl.protocol_),+ option.size(impl.protocol_), ec);+ }++ // Get a socket option.+ template <typename Option>+ asio::error_code get_option(const implementation_type& impl,+ Option& option, asio::error_code& ec) const+ {+ std::size_t size = option.size(impl.protocol_);+ do_get_option(impl, option.level(impl.protocol_),+ option.name(impl.protocol_),+ option.data(impl.protocol_), &size, ec);+ if (!ec)+ option.resize(impl.protocol_, size);+ return ec;+ }++ // Connect the socket to the specified endpoint.+ asio::error_code connect(implementation_type& impl,+ const endpoint_type& peer_endpoint, asio::error_code& ec)+ {+ return do_connect(impl, peer_endpoint.data(), ec);+ }++ // Start an asynchronous connect.+ template <typename Handler, typename IoExecutor>+ void async_connect(implementation_type& impl,+ const endpoint_type& peer_endpoint,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef winrt_socket_connect_op<Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(handler, io_ex);++ ASIO_HANDLER_CREATION((scheduler_.context(),+ *p.p, "socket", &impl, 0, "async_connect"));++ start_connect_op(impl, peer_endpoint.data(), p.p, is_continuation);+ p.v = p.p = 0;+ }+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winrt_ssocket_service_base.hpp view
@@ -0,0 +1,362 @@+//+// detail/winrt_ssocket_service_base.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINRT_SSOCKET_SERVICE_BASE_HPP+#define ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_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_WINDOWS_RUNTIME)++#include "asio/buffer.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/socket_base.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/winrt_async_manager.hpp"+#include "asio/detail/winrt_socket_recv_op.hpp"+#include "asio/detail/winrt_socket_send_op.hpp"++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#else // defined(ASIO_HAS_IOCP)+# include "asio/detail/scheduler.hpp"+#endif // defined(ASIO_HAS_IOCP)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class winrt_ssocket_service_base+{+public:+ // The native type of a socket.+ typedef Windows::Networking::Sockets::StreamSocket^ native_handle_type;++ // The implementation type of the socket.+ struct base_implementation_type+ {+ // Default constructor.+ base_implementation_type()+ : socket_(nullptr),+ next_(0),+ prev_(0)+ {+ }++ // The underlying native socket.+ native_handle_type socket_;++ // Pointers to adjacent socket implementations in linked list.+ base_implementation_type* next_;+ base_implementation_type* prev_;+ };++ // Constructor.+ ASIO_DECL winrt_ssocket_service_base(execution_context& context);++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void base_shutdown();++ // Construct a new socket implementation.+ ASIO_DECL void construct(base_implementation_type&);++ // Move-construct a new socket implementation.+ ASIO_DECL void base_move_construct(base_implementation_type& impl,+ base_implementation_type& other_impl) ASIO_NOEXCEPT;++ // Move-assign from another socket implementation.+ ASIO_DECL void base_move_assign(base_implementation_type& impl,+ winrt_ssocket_service_base& other_service,+ base_implementation_type& other_impl);++ // Destroy a socket implementation.+ ASIO_DECL void destroy(base_implementation_type& impl);++ // Determine whether the socket is open.+ bool is_open(const base_implementation_type& impl) const+ {+ return impl.socket_ != nullptr;+ }++ // Destroy a socket implementation.+ ASIO_DECL asio::error_code close(+ base_implementation_type& impl, asio::error_code& ec);++ // Release ownership of the socket.+ ASIO_DECL native_handle_type release(+ base_implementation_type& impl, asio::error_code& ec);++ // Get the native socket representation.+ native_handle_type native_handle(base_implementation_type& impl)+ {+ return impl.socket_;+ }++ // Cancel all operations associated with the socket.+ asio::error_code cancel(base_implementation_type&,+ asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Determine whether the socket is at the out-of-band data mark.+ bool at_mark(const base_implementation_type&,+ asio::error_code& ec) const+ {+ ec = asio::error::operation_not_supported;+ return false;+ }++ // Determine the number of bytes available for reading.+ std::size_t available(const base_implementation_type&,+ asio::error_code& ec) const+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Perform an IO control command on the socket.+ template <typename IO_Control_Command>+ asio::error_code io_control(base_implementation_type&,+ IO_Control_Command&, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Gets the non-blocking mode of the socket.+ bool non_blocking(const base_implementation_type&) const+ {+ return false;+ }++ // Sets the non-blocking mode of the socket.+ asio::error_code non_blocking(base_implementation_type&,+ bool, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Gets the non-blocking mode of the native socket implementation.+ bool native_non_blocking(const base_implementation_type&) const+ {+ return false;+ }++ // Sets the non-blocking mode of the native socket implementation.+ asio::error_code native_non_blocking(base_implementation_type&,+ bool, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return ec;+ }++ // Send the given data to the peer.+ template <typename ConstBufferSequence>+ std::size_t send(base_implementation_type& impl,+ const ConstBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ return do_send(impl,+ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::first(buffers), flags, ec);+ }++ // Wait until data can be sent without blocking.+ std::size_t send(base_implementation_type&, const null_buffers&,+ socket_base::message_flags, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Start an asynchronous send. The data being sent must be valid for the+ // lifetime of the asynchronous operation.+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>+ void async_send(base_implementation_type& impl,+ const ConstBufferSequence& buffers, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef winrt_socket_send_op<ConstBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((scheduler_.context(),+ *p.p, "socket", &impl, 0, "async_send"));++ start_send_op(impl,+ buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::first(buffers),+ flags, p.p, is_continuation);+ p.v = p.p = 0;+ }++ // Start an asynchronous wait until data can be sent without blocking.+ template <typename Handler, typename IoExecutor>+ void async_send(base_implementation_type&, const null_buffers&,+ socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex,+ detail::bind_handler(handler, ec, bytes_transferred));+ }++ // Receive some data from the peer. Returns the number of bytes received.+ template <typename MutableBufferSequence>+ std::size_t receive(base_implementation_type& impl,+ const MutableBufferSequence& buffers,+ socket_base::message_flags flags, asio::error_code& ec)+ {+ return do_receive(impl,+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::first(buffers), flags, ec);+ }++ // Wait until data can be received without blocking.+ std::size_t receive(base_implementation_type&, const null_buffers&,+ socket_base::message_flags, asio::error_code& ec)+ {+ ec = asio::error::operation_not_supported;+ return 0;+ }++ // Start an asynchronous receive. The buffer for the data being received+ // must be valid for the lifetime of the asynchronous operation.+ template <typename MutableBufferSequence,+ typename Handler, typename IoExecutor>+ void async_receive(base_implementation_type& impl,+ const MutableBufferSequence& buffers, socket_base::message_flags flags,+ Handler& handler, const IoExecutor& io_ex)+ {+ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler);++ // Allocate and construct an operation to wrap the handler.+ typedef winrt_socket_recv_op<MutableBufferSequence, Handler, IoExecutor> op;+ typename op::ptr p = { asio::detail::addressof(handler),+ op::ptr::allocate(handler), 0 };+ p.p = new (p.v) op(buffers, handler, io_ex);++ ASIO_HANDLER_CREATION((scheduler_.context(),+ *p.p, "socket", &impl, 0, "async_receive"));++ start_receive_op(impl,+ buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::first(buffers),+ flags, p.p, is_continuation);+ p.v = p.p = 0;+ }++ // Wait until data can be received without blocking.+ template <typename Handler, typename IoExecutor>+ void async_receive(base_implementation_type&, const null_buffers&,+ socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)+ {+ asio::error_code ec = asio::error::operation_not_supported;+ const std::size_t bytes_transferred = 0;+ asio::post(io_ex,+ detail::bind_handler(handler, ec, bytes_transferred));+ }++protected:+ // Helper function to obtain endpoints associated with the connection.+ ASIO_DECL std::size_t do_get_endpoint(+ const base_implementation_type& impl, bool local,+ void* addr, std::size_t addr_len, asio::error_code& ec) const;++ // Helper function to set a socket option.+ ASIO_DECL asio::error_code do_set_option(+ base_implementation_type& impl,+ int level, int optname, const void* optval,+ std::size_t optlen, asio::error_code& ec);++ // Helper function to get a socket option.+ ASIO_DECL void do_get_option(+ const base_implementation_type& impl,+ int level, int optname, void* optval,+ std::size_t* optlen, asio::error_code& ec) const;++ // Helper function to perform a synchronous connect.+ ASIO_DECL asio::error_code do_connect(+ base_implementation_type& impl,+ const void* addr, asio::error_code& ec);++ // Helper function to start an asynchronous connect.+ ASIO_DECL void start_connect_op(+ base_implementation_type& impl, const void* addr,+ winrt_async_op<void>* op, bool is_continuation);++ // Helper function to perform a synchronous send.+ ASIO_DECL std::size_t do_send(+ base_implementation_type& impl, const asio::const_buffer& data,+ socket_base::message_flags flags, asio::error_code& ec);++ // Helper function to start an asynchronous send.+ ASIO_DECL void start_send_op(base_implementation_type& impl,+ const asio::const_buffer& data, socket_base::message_flags flags,+ winrt_async_op<unsigned int>* op, bool is_continuation);++ // Helper function to perform a synchronous receive.+ ASIO_DECL std::size_t do_receive(+ base_implementation_type& impl, const asio::mutable_buffer& data,+ socket_base::message_flags flags, asio::error_code& ec);++ // Helper function to start an asynchronous receive.+ ASIO_DECL void start_receive_op(base_implementation_type& impl,+ const asio::mutable_buffer& data, socket_base::message_flags flags,+ winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,+ bool is_continuation);++ // The scheduler implementation used for delivering completions.+#if defined(ASIO_HAS_IOCP)+ typedef class win_iocp_io_context scheduler_impl;+#else+ typedef class scheduler scheduler_impl;+#endif+ scheduler_impl& scheduler_;++ // The manager that keeps track of outstanding operations.+ winrt_async_manager& async_manager_;++ // Mutex to protect access to the linked list of implementations. + asio::detail::mutex mutex_;++ // The head of a linked list of all implementations.+ base_implementation_type* impl_list_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/winrt_ssocket_service_base.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winrt_timer_scheduler.hpp view
@@ -0,0 +1,147 @@+//+// detail/winrt_timer_scheduler.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINRT_TIMER_SCHEDULER_HPP+#define ASIO_DETAIL_WINRT_TIMER_SCHEDULER_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_WINDOWS_RUNTIME)++#include <cstddef>+#include "asio/detail/event.hpp"+#include "asio/detail/limits.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/op_queue.hpp"+#include "asio/detail/thread.hpp"+#include "asio/detail/timer_queue_base.hpp"+#include "asio/detail/timer_queue_set.hpp"+#include "asio/detail/wait_op.hpp"+#include "asio/execution_context.hpp"++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#else // defined(ASIO_HAS_IOCP)+# include "asio/detail/scheduler.hpp"+#endif // defined(ASIO_HAS_IOCP)++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/thread.hpp"+#endif // defined(ASIO_HAS_IOCP)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class winrt_timer_scheduler+ : public execution_context_service_base<winrt_timer_scheduler>+{+public:+ // Constructor.+ ASIO_DECL winrt_timer_scheduler(execution_context& context);++ // Destructor.+ ASIO_DECL ~winrt_timer_scheduler();++ // Destroy all user-defined handler objects owned by the service.+ ASIO_DECL void shutdown();++ // Recreate internal descriptors following a fork.+ ASIO_DECL void notify_fork(execution_context::fork_event fork_ev);++ // Initialise the task. No effect as this class uses its own thread.+ ASIO_DECL void init_task();++ // Add a new timer queue to the reactor.+ template <typename Time_Traits>+ void add_timer_queue(timer_queue<Time_Traits>& queue);++ // Remove a timer queue from the reactor.+ template <typename Time_Traits>+ void remove_timer_queue(timer_queue<Time_Traits>& queue);++ // Schedule a new operation in the given timer queue to expire at the+ // specified absolute time.+ template <typename Time_Traits>+ void schedule_timer(timer_queue<Time_Traits>& queue,+ const typename Time_Traits::time_type& time,+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);++ // Cancel the timer operations associated with the given token. Returns the+ // number of operations that have been posted or dispatched.+ template <typename Time_Traits>+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& timer,+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());++ // Move the timer operations associated with the given timer.+ template <typename Time_Traits>+ void move_timer(timer_queue<Time_Traits>& queue,+ typename timer_queue<Time_Traits>::per_timer_data& to,+ typename timer_queue<Time_Traits>::per_timer_data& from);++private:+ // Run the select loop in the thread.+ ASIO_DECL void run_thread();++ // Entry point for the select loop thread.+ ASIO_DECL static void call_run_thread(winrt_timer_scheduler* reactor);++ // Helper function to add a new timer queue.+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);++ // Helper function to remove a timer queue.+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);++ // The scheduler implementation used to post completions.+#if defined(ASIO_HAS_IOCP)+ typedef class win_iocp_io_context scheduler_impl;+#else+ typedef class scheduler scheduler_impl;+#endif+ scheduler_impl& scheduler_;++ // Mutex used to protect internal variables.+ asio::detail::mutex mutex_;++ // Event used to wake up background thread.+ asio::detail::event event_;++ // The timer queues.+ timer_queue_set timer_queues_;++ // The background thread that is waiting for timers to expire.+ asio::detail::thread* thread_;++ // Does the background thread need to stop.+ bool stop_thread_;++ // Whether the service has been shut down.+ bool shutdown_;+};++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/detail/impl/winrt_timer_scheduler.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/winrt_timer_scheduler.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winrt_utils.hpp view
@@ -0,0 +1,106 @@+//+// detail/winrt_utils.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINRT_UTILS_HPP+#define ASIO_DETAIL_WINRT_UTILS_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_WINDOWS_RUNTIME)++#include <codecvt>+#include <cstdlib>+#include <future>+#include <locale>+#include <robuffer.h>+#include <windows.storage.streams.h>+#include <wrl/implements.h>+#include "asio/buffer.hpp"+#include "asio/error_code.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/socket_ops.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {+namespace winrt_utils {++inline Platform::String^ string(const char* from)+{+ std::wstring tmp(from, from + std::strlen(from));+ return ref new Platform::String(tmp.c_str());+}++inline Platform::String^ string(const std::string& from)+{+ std::wstring tmp(from.begin(), from.end());+ return ref new Platform::String(tmp.c_str());+}++inline std::string string(Platform::String^ from)+{+ std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;+ return converter.to_bytes(from->Data());+}++inline Platform::String^ string(unsigned short from)+{+ return string(std::to_string(from));+}++template <typename T>+inline Platform::String^ string(const T& from)+{+ return string(from.to_string());+}++inline int integer(Platform::String^ from)+{+ return _wtoi(from->Data());+}++template <typename T>+inline Windows::Networking::HostName^ host_name(const T& from)+{+ return ref new Windows::Networking::HostName((string)(from));+}++template <typename ConstBufferSequence>+inline Windows::Storage::Streams::IBuffer^ buffer_dup(+ const ConstBufferSequence& buffers)+{+ using Microsoft::WRL::ComPtr;+ using asio::buffer_size;+ std::size_t size = buffer_size(buffers);+ auto b = ref new Windows::Storage::Streams::Buffer(size);+ ComPtr<IInspectable> insp = reinterpret_cast<IInspectable*>(b);+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> bacc;+ insp.As(&bacc);+ byte* bytes = nullptr;+ bacc->Buffer(&bytes);+ asio::buffer_copy(asio::buffer(bytes, size), buffers);+ b->Length = size;+ return b;+}++} // namespace winrt_utils+} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_WINDOWS_RUNTIME)++#endif // ASIO_DETAIL_WINRT_UTILS_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/winsock_init.hpp view
@@ -0,0 +1,128 @@+//+// detail/winsock_init.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINSOCK_INIT_HPP+#define ASIO_DETAIL_WINSOCK_INIT_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_WINDOWS) || defined(__CYGWIN__)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class winsock_init_base+{+protected:+ // Structure to track result of initialisation and number of uses. POD is used+ // to ensure that the values are zero-initialised prior to any code being run.+ struct data+ {+ long init_count_;+ long result_;+ };++ ASIO_DECL static void startup(data& d,+ unsigned char major, unsigned char minor);++ ASIO_DECL static void manual_startup(data& d);++ ASIO_DECL static void cleanup(data& d);++ ASIO_DECL static void manual_cleanup(data& d);++ ASIO_DECL static void throw_on_error(data& d);+};++template <int Major = 2, int Minor = 0>+class winsock_init : private winsock_init_base+{+public:+ winsock_init(bool allow_throw = true)+ {+ startup(data_, Major, Minor);+ if (allow_throw)+ throw_on_error(data_);+ }++ winsock_init(const winsock_init&)+ {+ startup(data_, Major, Minor);+ throw_on_error(data_);+ }++ ~winsock_init()+ {+ cleanup(data_);+ }++ // This class may be used to indicate that user code will manage Winsock+ // initialisation and cleanup. This may be required in the case of a DLL, for+ // example, where it is not safe to initialise Winsock from global object+ // constructors.+ //+ // To prevent asio from initialising Winsock, the object must be constructed+ // before any Asio's own global objects. With MSVC, this may be accomplished+ // by adding the following code to the DLL:+ //+ // #pragma warning(push)+ // #pragma warning(disable:4073)+ // #pragma init_seg(lib)+ // asio::detail::winsock_init<>::manual manual_winsock_init;+ // #pragma warning(pop)+ class manual+ {+ public:+ manual()+ {+ manual_startup(data_);+ }++ manual(const manual&)+ {+ manual_startup(data_);+ }++ ~manual()+ {+ manual_cleanup(data_);+ }+ };++private:+ friend class manual;+ static data data_;+};++template <int Major, int Minor>+winsock_init_base::data winsock_init<Major, Minor>::data_;++// Static variable to ensure that winsock is initialised before main, and+// therefore before any other threads can get started.+static const winsock_init<>& winsock_init_instance = winsock_init<>(false);++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/detail/impl/winsock_init.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)++#endif // ASIO_DETAIL_WINSOCK_INIT_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/work_dispatcher.hpp view
@@ -0,0 +1,148 @@+//+// detail/work_dispatcher.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WORK_DISPATCHER_HPP+#define ASIO_DETAIL_WORK_DISPATCHER_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_executor.hpp"+#include "asio/associated_allocator.hpp"+#include "asio/executor_work_guard.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution/allocator.hpp"+#include "asio/execution/blocking.hpp"+#include "asio/execution/outstanding_work.hpp"+#include "asio/prefer.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Handler, typename Executor, typename = void>+struct is_work_dispatcher_required : true_type+{+};++template <typename Handler, typename Executor>+struct is_work_dispatcher_required<Handler, Executor,+ typename enable_if<+ is_same<+ typename associated_executor<Handler,+ Executor>::asio_associated_executor_is_unspecialised,+ void+ >::value+ >::type> : false_type+{+};++template <typename Handler, typename Executor, typename = void>+class work_dispatcher+{+public:+ template <typename CompletionHandler>+ work_dispatcher(ASIO_MOVE_ARG(CompletionHandler) handler,+ const Executor& handler_ex)+ : handler_(ASIO_MOVE_CAST(CompletionHandler)(handler)),+ executor_(asio::prefer(handler_ex,+ execution::outstanding_work.tracked))+ {+ }++#if defined(ASIO_HAS_MOVE)+ work_dispatcher(const work_dispatcher& other)+ : handler_(other.handler_),+ executor_(other.executor_)+ {+ }++ work_dispatcher(work_dispatcher&& other)+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),+ executor_(ASIO_MOVE_CAST(work_executor_type)(other.executor_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()()+ {+ execution::execute(+ asio::prefer(executor_,+ execution::blocking.possibly,+ execution::allocator((get_associated_allocator)(handler_))),+ ASIO_MOVE_CAST(Handler)(handler_));+ }++private:+ typedef typename decay<+ typename prefer_result<const Executor&,+ execution::outstanding_work_t::tracked_t+ >::type+ >::type work_executor_type;++ Handler handler_;+ work_executor_type executor_;+};++#if !defined(ASIO_NO_TS_EXECUTORS)++template <typename Handler, typename Executor>+class work_dispatcher<Handler, Executor,+ typename enable_if<!execution::is_executor<Executor>::value>::type>+{+public:+ template <typename CompletionHandler>+ work_dispatcher(ASIO_MOVE_ARG(CompletionHandler) handler,+ const Executor& handler_ex)+ : work_(handler_ex),+ handler_(ASIO_MOVE_CAST(CompletionHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ work_dispatcher(const work_dispatcher& other)+ : work_(other.work_),+ handler_(other.handler_)+ {+ }++ work_dispatcher(work_dispatcher&& other)+ : work_(ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_)),+ handler_(ASIO_MOVE_CAST(Handler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()()+ {+ typename associated_allocator<Handler>::type alloc(+ (get_associated_allocator)(handler_));+ work_.get_executor().dispatch(+ ASIO_MOVE_CAST(Handler)(handler_), alloc);+ work_.reset();+ }++private:+ executor_work_guard<Executor> work_;+ Handler handler_;+};++#endif // !defined(ASIO_NO_TS_EXECUTORS)++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_WORK_DISPATCHER_HPP
+ link/modules/asio-standalone/asio/include/asio/detail/wrapped_handler.hpp view
@@ -0,0 +1,327 @@+//+// detail/wrapped_handler.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WRAPPED_HANDLER_HPP+#define ASIO_DETAIL_WRAPPED_HANDLER_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/bind_handler.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_cont_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++struct is_continuation_delegated+{+ template <typename Dispatcher, typename Handler>+ bool operator()(Dispatcher&, Handler& handler) const+ {+ return asio_handler_cont_helpers::is_continuation(handler);+ }+};++struct is_continuation_if_running+{+ template <typename Dispatcher, typename Handler>+ bool operator()(Dispatcher& dispatcher, Handler&) const+ {+ return dispatcher.running_in_this_thread();+ }+};++template <typename Dispatcher, typename Handler,+ typename IsContinuation = is_continuation_delegated>+class wrapped_handler+{+public:+ typedef void result_type;++ wrapped_handler(Dispatcher dispatcher, Handler& handler)+ : dispatcher_(dispatcher),+ handler_(ASIO_MOVE_CAST(Handler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ wrapped_handler(const wrapped_handler& other)+ : dispatcher_(other.dispatcher_),+ handler_(other.handler_)+ {+ }++ wrapped_handler(wrapped_handler&& other)+ : dispatcher_(other.dispatcher_),+ handler_(ASIO_MOVE_CAST(Handler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()()+ {+ dispatcher_.dispatch(ASIO_MOVE_CAST(Handler)(handler_));+ }++ void operator()() const+ {+ dispatcher_.dispatch(handler_);+ }++ template <typename Arg1>+ void operator()(const Arg1& arg1)+ {+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1));+ }++ template <typename Arg1>+ void operator()(const Arg1& arg1) const+ {+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1));+ }++ template <typename Arg1, typename Arg2>+ void operator()(const Arg1& arg1, const Arg2& arg2)+ {+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2));+ }++ template <typename Arg1, typename Arg2>+ void operator()(const Arg1& arg1, const Arg2& arg2) const+ {+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2));+ }++ template <typename Arg1, typename Arg2, typename Arg3>+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)+ {+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3));+ }++ template <typename Arg1, typename Arg2, typename Arg3>+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) const+ {+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3));+ }++ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,+ const Arg4& arg4)+ {+ dispatcher_.dispatch(+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4));+ }++ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,+ const Arg4& arg4) const+ {+ dispatcher_.dispatch(+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4));+ }++ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,+ typename Arg5>+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,+ const Arg4& arg4, const Arg5& arg5)+ {+ dispatcher_.dispatch(+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5));+ }++ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,+ typename Arg5>+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,+ const Arg4& arg4, const Arg5& arg5) const+ {+ dispatcher_.dispatch(+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5));+ }++//private:+ Dispatcher dispatcher_;+ Handler handler_;+};++template <typename Handler, typename Context>+class rewrapped_handler+{+public:+ explicit rewrapped_handler(Handler& handler, const Context& context)+ : context_(context),+ handler_(ASIO_MOVE_CAST(Handler)(handler))+ {+ }++ explicit rewrapped_handler(const Handler& handler, const Context& context)+ : context_(context),+ handler_(handler)+ {+ }++#if defined(ASIO_HAS_MOVE)+ rewrapped_handler(const rewrapped_handler& other)+ : context_(other.context_),+ handler_(other.handler_)+ {+ }++ rewrapped_handler(rewrapped_handler&& other)+ : context_(ASIO_MOVE_CAST(Context)(other.context_)),+ handler_(ASIO_MOVE_CAST(Handler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()()+ {+ handler_();+ }++ void operator()() const+ {+ handler_();+ }++//private:+ Context context_;+ Handler handler_;+};++template <typename Dispatcher, typename Handler, typename IsContinuation>+inline asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size,+ wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)+{+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Dispatcher, typename Handler, typename IsContinuation>+inline asio_handler_deallocate_is_deprecated+asio_handler_deallocate(void* pointer, std::size_t size,+ wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)+{+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Dispatcher, typename Handler, typename IsContinuation>+inline bool asio_handler_is_continuation(+ wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)+{+ return IsContinuation()(this_handler->dispatcher_, this_handler->handler_);+}++template <typename Function, typename Dispatcher,+ typename Handler, typename IsContinuation>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(Function& function,+ wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)+{+ this_handler->dispatcher_.dispatch(+ rewrapped_handler<Function, Handler>(+ function, this_handler->handler_));+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Function, typename Dispatcher,+ typename Handler, typename IsContinuation>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(const Function& function,+ wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)+{+ this_handler->dispatcher_.dispatch(+ rewrapped_handler<Function, Handler>(+ function, this_handler->handler_));+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Context>+inline asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size,+ rewrapped_handler<Handler, Context>* this_handler)+{+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler, typename Context>+inline asio_handler_deallocate_is_deprecated+asio_handler_deallocate(void* pointer, std::size_t size,+ rewrapped_handler<Handler, Context>* this_handler)+{+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->context_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Dispatcher, typename Context>+inline bool asio_handler_is_continuation(+ rewrapped_handler<Dispatcher, Context>* this_handler)+{+ return asio_handler_cont_helpers::is_continuation(+ this_handler->context_);+}++template <typename Function, typename Handler, typename Context>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(Function& function,+ rewrapped_handler<Handler, Context>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->context_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Function, typename Handler, typename Context>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(const Function& function,+ rewrapped_handler<Handler, Context>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->context_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_DETAIL_WRAPPED_HANDLER_HPP
+ link/modules/asio-standalone/asio/include/asio/dispatch.hpp view
@@ -0,0 +1,121 @@+//+// dispatch.hpp+// ~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_DISPATCH_HPP+#define ASIO_DISPATCH_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/async_result.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution_context.hpp"+#include "asio/execution/executor.hpp"+#include "asio/is_executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Submits a completion token or function object for execution.+/**+ * This function submits an object for execution using the object's associated+ * executor. The function object may be called from the current thread prior to+ * returning from <tt>dispatch()</tt>. Otherwise, it is queued for execution.+ *+ * This function has the following effects:+ *+ * @li Constructs a function object handler of type @c Handler, initialized+ * with <tt>handler(forward<CompletionToken>(token))</tt>.+ *+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,+ * initializing the object as <tt>result(handler)</tt>.+ *+ * @li Obtains the handler's associated executor object @c ex by performing+ * <tt>get_associated_executor(handler)</tt>.+ *+ * @li Obtains the handler's associated allocator object @c alloc by performing+ * <tt>get_associated_allocator(handler)</tt>.+ *+ * @li Performs <tt>ex.dispatch(std::move(handler), alloc)</tt>.+ *+ * @li Returns <tt>result.get()</tt>.+ */+template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(+ ASIO_MOVE_ARG(CompletionToken) token);++/// Submits a completion token or function object for execution.+/**+ * This function submits an object for execution using the specified executor.+ * The function object may be called from the current thread prior to returning+ * from <tt>dispatch()</tt>. Otherwise, it is queued for execution.+ *+ * This function has the following effects:+ *+ * @li Constructs a function object handler of type @c Handler, initialized+ * with <tt>handler(forward<CompletionToken>(token))</tt>.+ *+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,+ * initializing the object as <tt>result(handler)</tt>.+ *+ * @li Obtains the handler's associated executor object @c ex1 by performing+ * <tt>get_associated_executor(handler)</tt>.+ *+ * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>.+ *+ * @li Obtains the handler's associated allocator object @c alloc by performing+ * <tt>get_associated_allocator(handler)</tt>.+ *+ * @li Constructs a function object @c f with a function call operator that+ * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by+ * <tt>w.reset()</tt>.+ *+ * @li Performs <tt>Executor(ex).dispatch(std::move(f), alloc)</tt>.+ *+ * @li Returns <tt>result.get()</tt>.+ */+template <typename Executor,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(+ const Executor& ex,+ ASIO_MOVE_ARG(CompletionToken) token+ ASIO_DEFAULT_COMPLETION_TOKEN(Executor),+ typename enable_if<+ execution::is_executor<Executor>::value || is_executor<Executor>::value+ >::type* = 0);++/// Submits a completion token or function object for execution.+/**+ * @returns <tt>dispatch(ctx.get_executor(),+ * forward<CompletionToken>(token))</tt>.+ */+template <typename ExecutionContext,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename ExecutionContext::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(+ ExecutionContext& ctx,+ ASIO_MOVE_ARG(CompletionToken) token+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename ExecutionContext::executor_type),+ typename enable_if<is_convertible<+ ExecutionContext&, execution_context&>::value>::type* = 0);++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/dispatch.hpp"++#endif // ASIO_DISPATCH_HPP
+ link/modules/asio-standalone/asio/include/asio/error.hpp view
@@ -0,0 +1,356 @@+//+// error.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 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_ERROR_HPP+#define ASIO_ERROR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/error_code.hpp"+#include "asio/system_error.hpp"+#if defined(ASIO_WINDOWS) \+ || defined(__CYGWIN__) \+ || defined(ASIO_WINDOWS_RUNTIME)+# include <winerror.h>+#else+# include <cerrno>+# include <netdb.h>+#endif++#if defined(GENERATING_DOCUMENTATION)+/// INTERNAL ONLY.+# define ASIO_NATIVE_ERROR(e) implementation_defined+/// INTERNAL ONLY.+# define ASIO_SOCKET_ERROR(e) implementation_defined+/// INTERNAL ONLY.+# define ASIO_NETDB_ERROR(e) implementation_defined+/// INTERNAL ONLY.+# define ASIO_GETADDRINFO_ERROR(e) implementation_defined+/// INTERNAL ONLY.+# define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined+#elif defined(ASIO_WINDOWS_RUNTIME)+# define ASIO_NATIVE_ERROR(e) __HRESULT_FROM_WIN32(e)+# define ASIO_SOCKET_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e)+# define ASIO_NETDB_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e)+# define ASIO_GETADDRINFO_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e)+# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# define ASIO_NATIVE_ERROR(e) e+# define ASIO_SOCKET_ERROR(e) WSA ## e+# define ASIO_NETDB_ERROR(e) WSA ## e+# define ASIO_GETADDRINFO_ERROR(e) WSA ## e+# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win+#else+# define ASIO_NATIVE_ERROR(e) e+# define ASIO_SOCKET_ERROR(e) e+# define ASIO_NETDB_ERROR(e) e+# define ASIO_GETADDRINFO_ERROR(e) e+# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix+#endif++#include "asio/detail/push_options.hpp"++namespace asio {+namespace error {++enum basic_errors+{+ /// Permission denied.+ access_denied = ASIO_SOCKET_ERROR(EACCES),++ /// Address family not supported by protocol.+ address_family_not_supported = ASIO_SOCKET_ERROR(EAFNOSUPPORT),++ /// Address already in use.+ address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE),++ /// Transport endpoint is already connected.+ already_connected = ASIO_SOCKET_ERROR(EISCONN),++ /// Operation already in progress.+ already_started = ASIO_SOCKET_ERROR(EALREADY),++ /// Broken pipe.+ broken_pipe = ASIO_WIN_OR_POSIX(+ ASIO_NATIVE_ERROR(ERROR_BROKEN_PIPE),+ ASIO_NATIVE_ERROR(EPIPE)),++ /// A connection has been aborted.+ connection_aborted = ASIO_SOCKET_ERROR(ECONNABORTED),++ /// Connection refused.+ connection_refused = ASIO_SOCKET_ERROR(ECONNREFUSED),++ /// Connection reset by peer.+ connection_reset = ASIO_SOCKET_ERROR(ECONNRESET),++ /// Bad file descriptor.+ bad_descriptor = ASIO_SOCKET_ERROR(EBADF),++ /// Bad address.+ fault = ASIO_SOCKET_ERROR(EFAULT),++ /// No route to host.+ host_unreachable = ASIO_SOCKET_ERROR(EHOSTUNREACH),++ /// Operation now in progress.+ in_progress = ASIO_SOCKET_ERROR(EINPROGRESS),++ /// Interrupted system call.+ interrupted = ASIO_SOCKET_ERROR(EINTR),++ /// Invalid argument.+ invalid_argument = ASIO_SOCKET_ERROR(EINVAL),++ /// Message too long.+ message_size = ASIO_SOCKET_ERROR(EMSGSIZE),++ /// The name was too long.+ name_too_long = ASIO_SOCKET_ERROR(ENAMETOOLONG),++ /// Network is down.+ network_down = ASIO_SOCKET_ERROR(ENETDOWN),++ /// Network dropped connection on reset.+ network_reset = ASIO_SOCKET_ERROR(ENETRESET),++ /// Network is unreachable.+ network_unreachable = ASIO_SOCKET_ERROR(ENETUNREACH),++ /// Too many open files.+ no_descriptors = ASIO_SOCKET_ERROR(EMFILE),++ /// No buffer space available.+ no_buffer_space = ASIO_SOCKET_ERROR(ENOBUFS),++ /// Cannot allocate memory.+ no_memory = ASIO_WIN_OR_POSIX(+ ASIO_NATIVE_ERROR(ERROR_OUTOFMEMORY),+ ASIO_NATIVE_ERROR(ENOMEM)),++ /// Operation not permitted.+ no_permission = ASIO_WIN_OR_POSIX(+ ASIO_NATIVE_ERROR(ERROR_ACCESS_DENIED),+ ASIO_NATIVE_ERROR(EPERM)),++ /// Protocol not available.+ no_protocol_option = ASIO_SOCKET_ERROR(ENOPROTOOPT),++ /// No such device.+ no_such_device = ASIO_WIN_OR_POSIX(+ ASIO_NATIVE_ERROR(ERROR_BAD_UNIT),+ ASIO_NATIVE_ERROR(ENODEV)),++ /// Transport endpoint is not connected.+ not_connected = ASIO_SOCKET_ERROR(ENOTCONN),++ /// Socket operation on non-socket.+ not_socket = ASIO_SOCKET_ERROR(ENOTSOCK),++ /// Operation cancelled.+ operation_aborted = ASIO_WIN_OR_POSIX(+ ASIO_NATIVE_ERROR(ERROR_OPERATION_ABORTED),+ ASIO_NATIVE_ERROR(ECANCELED)),++ /// Operation not supported.+ operation_not_supported = ASIO_SOCKET_ERROR(EOPNOTSUPP),++ /// Cannot send after transport endpoint shutdown.+ shut_down = ASIO_SOCKET_ERROR(ESHUTDOWN),++ /// Connection timed out.+ timed_out = ASIO_SOCKET_ERROR(ETIMEDOUT),++ /// Resource temporarily unavailable.+ try_again = ASIO_WIN_OR_POSIX(+ ASIO_NATIVE_ERROR(ERROR_RETRY),+ ASIO_NATIVE_ERROR(EAGAIN)),++ /// The socket is marked non-blocking and the requested operation would block.+ would_block = ASIO_SOCKET_ERROR(EWOULDBLOCK)+};++enum netdb_errors+{+ /// Host not found (authoritative).+ host_not_found = ASIO_NETDB_ERROR(HOST_NOT_FOUND),++ /// Host not found (non-authoritative).+ host_not_found_try_again = ASIO_NETDB_ERROR(TRY_AGAIN),++ /// The query is valid but does not have associated address data.+ no_data = ASIO_NETDB_ERROR(NO_DATA),++ /// A non-recoverable error occurred.+ no_recovery = ASIO_NETDB_ERROR(NO_RECOVERY)+};++enum addrinfo_errors+{+ /// The service is not supported for the given socket type.+ service_not_found = ASIO_WIN_OR_POSIX(+ ASIO_NATIVE_ERROR(WSATYPE_NOT_FOUND),+ ASIO_GETADDRINFO_ERROR(EAI_SERVICE)),++ /// The socket type is not supported.+ socket_type_not_supported = ASIO_WIN_OR_POSIX(+ ASIO_NATIVE_ERROR(WSAESOCKTNOSUPPORT),+ ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE))+};++enum misc_errors+{+ /// Already open.+ already_open = 1,++ /// End of file or stream.+ eof,++ /// Element not found.+ not_found,++ /// The descriptor cannot fit into the select system call's fd_set.+ fd_set_failure+};++inline const asio::error_category& get_system_category()+{+ return asio::system_category();+}++#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++extern ASIO_DECL+const asio::error_category& get_netdb_category();++extern ASIO_DECL+const asio::error_category& get_addrinfo_category();++#else // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++inline const asio::error_category& get_netdb_category()+{+ return get_system_category();+}++inline const asio::error_category& get_addrinfo_category()+{+ return get_system_category();+}++#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++extern ASIO_DECL+const asio::error_category& get_misc_category();++static const asio::error_category&+ system_category ASIO_UNUSED_VARIABLE+ = asio::error::get_system_category();+static const asio::error_category&+ netdb_category ASIO_UNUSED_VARIABLE+ = asio::error::get_netdb_category();+static const asio::error_category&+ addrinfo_category ASIO_UNUSED_VARIABLE+ = asio::error::get_addrinfo_category();+static const asio::error_category&+ misc_category ASIO_UNUSED_VARIABLE+ = asio::error::get_misc_category();++} // namespace error+} // namespace asio++#if defined(ASIO_HAS_STD_SYSTEM_ERROR)+namespace std {++template<> struct is_error_code_enum<asio::error::basic_errors>+{+ static const bool value = true;+};++template<> struct is_error_code_enum<asio::error::netdb_errors>+{+ static const bool value = true;+};++template<> struct is_error_code_enum<asio::error::addrinfo_errors>+{+ static const bool value = true;+};++template<> struct is_error_code_enum<asio::error::misc_errors>+{+ static const bool value = true;+};++} // namespace std+#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)++namespace asio {+namespace error {++inline asio::error_code make_error_code(basic_errors e)+{+ return asio::error_code(+ static_cast<int>(e), get_system_category());+}++inline asio::error_code make_error_code(netdb_errors e)+{+ return asio::error_code(+ static_cast<int>(e), get_netdb_category());+}++inline asio::error_code make_error_code(addrinfo_errors e)+{+ return asio::error_code(+ static_cast<int>(e), get_addrinfo_category());+}++inline asio::error_code make_error_code(misc_errors e)+{+ return asio::error_code(+ static_cast<int>(e), get_misc_category());+}++} // namespace error+namespace stream_errc {+ // Simulates the proposed stream_errc scoped enum.+ using error::eof;+ using error::not_found;+} // namespace stream_errc+namespace socket_errc {+ // Simulates the proposed socket_errc scoped enum.+ using error::already_open;+ using error::not_found;+} // namespace socket_errc+namespace resolver_errc {+ // Simulates the proposed resolver_errc scoped enum.+ using error::host_not_found;+ const error::netdb_errors try_again = error::host_not_found_try_again;+ using error::service_not_found;+} // namespace resolver_errc+} // namespace asio++#include "asio/detail/pop_options.hpp"++#undef ASIO_NATIVE_ERROR+#undef ASIO_SOCKET_ERROR+#undef ASIO_NETDB_ERROR+#undef ASIO_GETADDRINFO_ERROR+#undef ASIO_WIN_OR_POSIX++#if defined(ASIO_HEADER_ONLY)+# include "asio/impl/error.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_ERROR_HPP
+ link/modules/asio-standalone/asio/include/asio/error_code.hpp view
@@ -0,0 +1,202 @@+//+// error_code.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_ERROR_CODE_HPP+#define ASIO_ERROR_CODE_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_STD_SYSTEM_ERROR)+# include <system_error>+#else // defined(ASIO_HAS_STD_SYSTEM_ERROR)+# include <string>+# include "asio/detail/noncopyable.hpp"+# if !defined(ASIO_NO_IOSTREAM)+# include <iosfwd>+# endif // !defined(ASIO_NO_IOSTREAM)+#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(ASIO_HAS_STD_SYSTEM_ERROR)++typedef std::error_category error_category;++#else // defined(ASIO_HAS_STD_SYSTEM_ERROR)++/// Base class for all error categories.+class error_category : private noncopyable+{+public:+ /// Destructor.+ virtual ~error_category()+ {+ }++ /// Returns a string naming the error gategory.+ virtual const char* name() const = 0;++ /// Returns a string describing the error denoted by @c value.+ virtual std::string message(int value) const = 0;++ /// Equality operator to compare two error categories.+ bool operator==(const error_category& rhs) const+ {+ return this == &rhs;+ }++ /// Inequality operator to compare two error categories.+ bool operator!=(const error_category& rhs) const+ {+ return !(*this == rhs);+ }+};++#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)++/// Returns the error category used for the system errors produced by asio.+extern ASIO_DECL const error_category& system_category();++#if defined(ASIO_HAS_STD_SYSTEM_ERROR)++typedef std::error_code error_code;++#else // defined(ASIO_HAS_STD_SYSTEM_ERROR)++/// Class to represent an error code value.+class error_code+{+public:+ /// Default constructor.+ error_code()+ : value_(0),+ category_(&system_category())+ {+ }++ /// Construct with specific error code and category.+ error_code(int v, const error_category& c)+ : value_(v),+ category_(&c)+ {+ }++ /// Construct from an error code enum.+ template <typename ErrorEnum>+ error_code(ErrorEnum e)+ {+ *this = make_error_code(e);+ }++ /// Clear the error value to the default.+ void clear()+ {+ value_ = 0;+ category_ = &system_category();+ }++ /// Assign a new error value.+ void assign(int v, const error_category& c)+ {+ value_ = v;+ category_ = &c;+ }++ /// Get the error value.+ int value() const+ {+ return value_;+ }++ /// Get the error category.+ const error_category& category() const+ {+ return *category_;+ }++ /// Get the message associated with the error.+ std::string message() const+ {+ return category_->message(value_);+ }++ struct unspecified_bool_type_t+ {+ };++ typedef void (*unspecified_bool_type)(unspecified_bool_type_t);++ static void unspecified_bool_true(unspecified_bool_type_t) {}++ /// Operator returns non-null if there is a non-success error code.+ operator unspecified_bool_type() const+ {+ if (value_ == 0)+ return 0;+ else+ return &error_code::unspecified_bool_true;+ }++ /// Operator to test if the error represents success.+ bool operator!() const+ {+ return value_ == 0;+ }++ /// Equality operator to compare two error objects.+ friend bool operator==(const error_code& e1, const error_code& e2)+ {+ return e1.value_ == e2.value_ && e1.category_ == e2.category_;+ }++ /// Inequality operator to compare two error objects.+ friend bool operator!=(const error_code& e1, const error_code& e2)+ {+ return e1.value_ != e2.value_ || e1.category_ != e2.category_;+ }++private:+ // The value associated with the error code.+ int value_;++ // The category associated with the error code.+ const error_category* category_;+};++# if !defined(ASIO_NO_IOSTREAM)++/// Output an error code.+template <typename Elem, typename Traits>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os, const error_code& ec)+{+ os << ec.category().name() << ':' << ec.value();+ return os;+}++# endif // !defined(ASIO_NO_IOSTREAM)++#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/impl/error_code.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_ERROR_CODE_HPP
+ link/modules/asio-standalone/asio/include/asio/execution.hpp view
@@ -0,0 +1,48 @@+//+// execution.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_HPP+#define ASIO_EXECUTION_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/execution/allocator.hpp"+#include "asio/execution/any_executor.hpp"+#include "asio/execution/bad_executor.hpp"+#include "asio/execution/blocking.hpp"+#include "asio/execution/blocking_adaptation.hpp"+#include "asio/execution/bulk_execute.hpp"+#include "asio/execution/bulk_guarantee.hpp"+#include "asio/execution/connect.hpp"+#include "asio/execution/context.hpp"+#include "asio/execution/context_as.hpp"+#include "asio/execution/execute.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/operation_state.hpp"+#include "asio/execution/outstanding_work.hpp"+#include "asio/execution/prefer_only.hpp"+#include "asio/execution/receiver.hpp"+#include "asio/execution/receiver_invocation_error.hpp"+#include "asio/execution/relationship.hpp"+#include "asio/execution/schedule.hpp"+#include "asio/execution/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/execution/set_done.hpp"+#include "asio/execution/set_error.hpp"+#include "asio/execution/set_value.hpp"+#include "asio/execution/start.hpp"+#include "asio/execution/submit.hpp"++#endif // ASIO_EXECUTION_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/allocator.hpp view
@@ -0,0 +1,249 @@+//+// execution/allocator.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_ALLOCATOR_HPP+#define ASIO_EXECUTION_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/execution/executor.hpp"+#include "asio/execution/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/is_applicable_property.hpp"+#include "asio/traits/query_static_constexpr_member.hpp"+#include "asio/traits/static_query.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// A property to describe which allocator an executor will use to allocate the+/// memory required to store a submitted function object.+template <typename ProtoAllocator>+struct allocator_t+{+ /// The allocator_t property applies to executors, senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The allocator_t property can be required.+ static constexpr bool is_requirable = true;++ /// The allocator_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// Default constructor.+ constexpr allocator_t();++ /// Obtain the allocator stored in the allocator_t property object.+ /**+ * Present only if @c ProtoAllocator is non-void.+ */+ constexpr ProtoAllocator value() const;++ /// Create an allocator_t object with a different allocator.+ /**+ * Present only if @c ProtoAllocator is void.+ */+ template <typename OtherAllocator>+ allocator_t<OtherAllocator operator()(const OtherAllocator& a);+};++/// A special value used for accessing the allocator_t property.+constexpr allocator_t<void> allocator;++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {++template <typename ProtoAllocator>+struct allocator_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, allocator_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, allocator_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, allocator_t>::value();+ }++ template <typename E, typename T = decltype(allocator_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = allocator_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ ASIO_CONSTEXPR ProtoAllocator value() const+ {+ return a_;+ }++private:+ friend struct allocator_t<void>;++ explicit ASIO_CONSTEXPR allocator_t(const ProtoAllocator& a)+ : a_(a)+ {+ }++ ProtoAllocator a_;+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <typename ProtoAllocator> template <typename E, typename T>+const T allocator_t<ProtoAllocator>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <>+struct allocator_t<void>+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);++ ASIO_CONSTEXPR allocator_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, allocator_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, allocator_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, allocator_t>::value();+ }++ template <typename E, typename T = decltype(allocator_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = allocator_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ template <typename OtherProtoAllocator>+ ASIO_CONSTEXPR allocator_t<OtherProtoAllocator> operator()(+ const OtherProtoAllocator& a) const+ {+ return allocator_t<OtherProtoAllocator>(a);+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <typename E, typename T>+const T allocator_t<void>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr allocator_t<void> allocator;+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+template <typename T>+struct allocator_instance+{+ static allocator_t<T> instance;+};++template <typename T>+allocator_t<T> allocator_instance<T>::instance;++namespace {+static const allocator_t<void>& allocator = allocator_instance<void>::instance;+} // namespace+#endif++} // namespace execution++#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename ProtoAllocator>+struct is_applicable_property<T, execution::allocator_t<ProtoAllocator> >+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename T, typename ProtoAllocator>+struct static_query<T, execution::allocator_t<ProtoAllocator>,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::allocator_t<ProtoAllocator> >::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::allocator_t<ProtoAllocator> >::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::allocator_t<ProtoAllocator> >::value();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_ALLOCATOR_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/any_executor.hpp view
@@ -0,0 +1,2264 @@+//+// execution/any_executor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_ANY_EXECUTOR_HPP+#define ASIO_EXECUTION_ANY_EXECUTOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <new>+#include <typeinfo>+#include "asio/detail/assert.hpp"+#include "asio/detail/cstddef.hpp"+#include "asio/detail/executor_function.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/non_const_lvalue.hpp"+#include "asio/detail/scoped_ptr.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/detail/variadic_templates.hpp"+#include "asio/execution/bad_executor.hpp"+#include "asio/execution/blocking.hpp"+#include "asio/execution/execute.hpp"+#include "asio/execution/executor.hpp"+#include "asio/prefer.hpp"+#include "asio/query.hpp"+#include "asio/require.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// Polymorphic executor wrapper.+template <typename... SupportableProperties>+class any_executor+{+public:+ /// Default constructor.+ any_executor() noexcept;++ /// Construct in an empty state. Equivalent effects to default constructor.+ any_executor(nullptr_t) noexcept;++ /// Copy constructor.+ any_executor(const any_executor& e) noexcept;++ /// Move constructor.+ any_executor(any_executor&& e) noexcept;++ /// Construct to point to the same target as another any_executor.+ template <class... OtherSupportableProperties>+ any_executor(any_executor<OtherSupportableProperties...> e);++ /// Construct a polymorphic wrapper for the specified executor.+ template <typename Executor>+ any_executor(Executor e);++ /// Assignment operator.+ any_executor& operator=(const any_executor& e) noexcept;++ /// Move assignment operator.+ any_executor& operator=(any_executor&& e) noexcept;++ /// Assignment operator that sets the polymorphic wrapper to the empty state.+ any_executor& operator=(nullptr_t);++ /// Assignment operator to create a polymorphic wrapper for the specified+ /// executor.+ template <typename Executor>+ any_executor& operator=(Executor e);++ /// Destructor.+ ~any_executor();++ /// Swap targets with another polymorphic wrapper.+ void swap(any_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 execution::any_executor<execution::blocking_t::possibly_t> ex = ...;+ * auto ex2 = asio::requre(ex, execution::blocking.possibly); @endcode+ */+ template <typename Property>+ any_executor require(Property) const;++ /// 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 execution::any_executor<execution::blocking_t::possibly_t> ex = ...;+ * auto ex2 = asio::prefer(ex, execution::blocking.possibly); @endcode+ */+ template <typename Property>+ any_executor prefer(Property) const;++ /// Obtain the value associated with the specified property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code execution::any_executor<execution::occupancy_t> ex = ...;+ * size_t n = asio::query(ex, execution::occupancy); @endcode+ */+ template <typename Property>+ typename Property::polymorphic_query_result_type query(Property) const;++ /// Execute the function on the target executor.+ /**+ * Do not call this function directly. It is intended for use with the+ * execution::execute customisation point.+ *+ * For example:+ * @code execution::any_executor<> ex = ...;+ * execution::execute(ex, my_function_object); @endcode+ *+ * Throws asio::bad_executor if the polymorphic wrapper has no target.+ */+ template <typename Function>+ void execute(Function&& f) const;++ /// Obtain the underlying execution context.+ /**+ * This function is provided for backward compatibility. It is automatically+ * defined when the @c SupportableProperties... list includes a property of+ * type <tt>execution::context_as<U></tt>, for some type <tt>U</tt>.+ */+ automatically_determined context() const;++ /// Determine whether the wrapper has a target executor.+ /**+ * @returns @c true if the polymorphic wrapper has a target executor,+ * otherwise false.+ */+ explicit operator bool() const noexcept;++ /// Get the type of the target executor.+ const type_info& target_type() const noexcept;++ /// Get a pointer to the target executor.+ template <typename Executor> Executor* target() noexcept;++ /// Get a pointer to the target executor.+ template <typename Executor> const Executor* target() const noexcept;+};++/// Equality operator.+/**+ * @relates any_executor+ */+template <typename... SupportableProperties>+bool operator==(const any_executor<SupportableProperties...>& a,+ const any_executor<SupportableProperties...>& b) noexcept;++/// Equality operator.+/**+ * @relates any_executor+ */+template <typename... SupportableProperties>+bool operator==(const any_executor<SupportableProperties...>& a,+ nullptr_t) noexcept;++/// Equality operator.+/**+ * @relates any_executor+ */+template <typename... SupportableProperties>+bool operator==(nullptr_t,+ const any_executor<SupportableProperties...>& b) noexcept;++/// Inequality operator.+/**+ * @relates any_executor+ */+template <typename... SupportableProperties>+bool operator!=(const any_executor<SupportableProperties...>& a,+ const any_executor<SupportableProperties...>& b) noexcept;++/// Inequality operator.+/**+ * @relates any_executor+ */+template <typename... SupportableProperties>+bool operator!=(const any_executor<SupportableProperties...>& a,+ nullptr_t) noexcept;++/// Inequality operator.+/**+ * @relates any_executor+ */+template <typename... SupportableProperties>+bool operator!=(nullptr_t,+ const any_executor<SupportableProperties...>& b) noexcept;++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {++#if !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)+#define ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename... SupportableProperties>+class any_executor;++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename = void, typename = void, typename = void,+ typename = void, typename = void, typename = void,+ typename = void, typename = void, typename = void>+class any_executor;++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#endif // !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)++template <typename U>+struct context_as_t;++namespace detail {++// Traits used to detect whether a property is requirable or preferable, taking+// into account that T::is_requirable or T::is_preferable may not not be well+// formed.++template <typename T, typename = void>+struct is_requirable : false_type {};++template <typename T>+struct is_requirable<T, typename enable_if<T::is_requirable>::type> :+ true_type {};++template <typename T, typename = void>+struct is_preferable : false_type {};++template <typename T>+struct is_preferable<T, typename enable_if<T::is_preferable>::type> :+ true_type {};++// Trait used to detect context_as property, for backward compatibility.++template <typename T>+struct is_context_as : false_type {};++template <typename U>+struct is_context_as<context_as_t<U> > : true_type {};++// Helper template to:+// - Check if a target can supply the supportable properties.+// - Find the first convertible-from-T property in the list.++template <std::size_t I, typename Props>+struct supportable_properties;++template <std::size_t I, typename Prop>+struct supportable_properties<I, void(Prop)>+{+ template <typename T>+ struct is_valid_target : integral_constant<bool,+ (+ is_requirable<Prop>::value+ ? can_require<T, Prop>::value+ : true+ )+ &&+ (+ is_preferable<Prop>::value+ ? can_prefer<T, Prop>::value+ : true+ )+ &&+ (+ !is_requirable<Prop>::value && !is_preferable<Prop>::value+ ? can_query<T, Prop>::value+ : true+ )+ >+ {+ };++ struct found+ {+ ASIO_STATIC_CONSTEXPR(bool, value = true);+ typedef Prop type;+ typedef typename Prop::polymorphic_query_result_type query_result_type;+ ASIO_STATIC_CONSTEXPR(std::size_t, index = I);+ };++ struct not_found+ {+ ASIO_STATIC_CONSTEXPR(bool, value = false);+ };++ template <typename T>+ struct find_convertible_property :+ conditional<+ is_same<T, Prop>::value || is_convertible<T, Prop>::value,+ found,+ not_found+ >::type {};++ template <typename T>+ struct find_convertible_requirable_property :+ conditional<+ is_requirable<Prop>::value+ && (is_same<T, Prop>::value || is_convertible<T, Prop>::value),+ found,+ not_found+ >::type {};++ template <typename T>+ struct find_convertible_preferable_property :+ conditional<+ is_preferable<Prop>::value+ && (is_same<T, Prop>::value || is_convertible<T, Prop>::value),+ found,+ not_found+ >::type {};++ struct find_context_as_property :+ conditional<+ is_context_as<Prop>::value,+ found,+ not_found+ >::type {};+};++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <std::size_t I, typename Head, typename... Tail>+struct supportable_properties<I, void(Head, Tail...)>+{+ template <typename T>+ struct is_valid_target : integral_constant<bool,+ (+ supportable_properties<I,+ void(Head)>::template is_valid_target<T>::value+ &&+ supportable_properties<I + 1,+ void(Tail...)>::template is_valid_target<T>::value+ )+ >+ {+ };++ template <typename T>+ struct find_convertible_property :+ conditional<+ is_convertible<T, Head>::value,+ typename supportable_properties<I, void(Head)>::found,+ typename supportable_properties<I + 1,+ void(Tail...)>::template find_convertible_property<T>+ >::type {};++ template <typename T>+ struct find_convertible_requirable_property :+ conditional<+ is_requirable<Head>::value+ && is_convertible<T, Head>::value,+ typename supportable_properties<I, void(Head)>::found,+ typename supportable_properties<I + 1,+ void(Tail...)>::template find_convertible_requirable_property<T>+ >::type {};++ template <typename T>+ struct find_convertible_preferable_property :+ conditional<+ is_preferable<Head>::value+ && is_convertible<T, Head>::value,+ typename supportable_properties<I, void(Head)>::found,+ typename supportable_properties<I + 1,+ void(Tail...)>::template find_convertible_preferable_property<T>+ >::type {};++ struct find_context_as_property :+ conditional<+ is_context_as<Head>::value,+ typename supportable_properties<I, void(Head)>::found,+ typename supportable_properties<I + 1,+ void(Tail...)>::find_context_as_property+ >::type {};+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#define ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF(n) \+ template <std::size_t I, \+ typename Head, ASIO_VARIADIC_TPARAMS(n)> \+ struct supportable_properties<I, \+ void(Head, ASIO_VARIADIC_TARGS(n))> \+ { \+ template <typename T> \+ struct is_valid_target : integral_constant<bool, \+ ( \+ supportable_properties<I, \+ void(Head)>::template is_valid_target<T>::value \+ && \+ supportable_properties<I + 1, \+ void(ASIO_VARIADIC_TARGS(n))>::template \+ is_valid_target<T>::value \+ ) \+ > \+ { \+ }; \+ \+ template <typename T> \+ struct find_convertible_property : \+ conditional< \+ is_convertible<T, Head>::value, \+ typename supportable_properties<I, void(Head)>::found, \+ typename supportable_properties<I + 1, \+ void(ASIO_VARIADIC_TARGS(n))>::template \+ find_convertible_property<T> \+ >::type {}; \+ \+ template <typename T> \+ struct find_convertible_requirable_property : \+ conditional< \+ is_requirable<Head>::value \+ && is_convertible<T, Head>::value, \+ typename supportable_properties<I, void(Head)>::found, \+ typename supportable_properties<I + 1, \+ void(ASIO_VARIADIC_TARGS(n))>::template \+ find_convertible_requirable_property<T> \+ >::type {}; \+ \+ template <typename T> \+ struct find_convertible_preferable_property : \+ conditional< \+ is_preferable<Head>::value \+ && is_convertible<T, Head>::value, \+ typename supportable_properties<I, void(Head)>::found, \+ typename supportable_properties<I + 1, \+ void(ASIO_VARIADIC_TARGS(n))>::template \+ find_convertible_preferable_property<T> \+ >::type {}; \+ \+ struct find_context_as_property : \+ conditional< \+ is_context_as<Head>::value, \+ typename supportable_properties<I, void(Head)>::found, \+ typename supportable_properties<I + 1, void( \+ ASIO_VARIADIC_TARGS(n))>::find_context_as_property \+ >::type {}; \+ }; \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF)+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename Props>+struct is_valid_target_executor :+ conditional<+ is_executor<T>::value,+ typename supportable_properties<0, Props>::template is_valid_target<T>,+ false_type+ >::type+{+};++class any_executor_base+{+public:+ any_executor_base() ASIO_NOEXCEPT+ : object_fns_(object_fns_table<void>()),+ target_(0),+ target_fns_(target_fns_table<void>())+ {+ }++ template <ASIO_EXECUTION_EXECUTOR Executor>+ any_executor_base(Executor ex, false_type)+ : target_fns_(target_fns_table<Executor>(+ any_executor_base::query_blocking(ex,+ can_query<const Executor&, const execution::blocking_t&>())+ == execution::blocking.always))+ {+ any_executor_base::construct_object(ex,+ integral_constant<bool,+ sizeof(Executor) <= sizeof(object_type)+ && alignment_of<Executor>::value <= alignment_of<object_type>::value+ >());+ }++ template <ASIO_EXECUTION_EXECUTOR Executor>+ any_executor_base(Executor other, true_type)+ : object_fns_(object_fns_table<asio::detail::shared_ptr<void> >()),+ target_fns_(other.target_fns_)+ {+ asio::detail::shared_ptr<Executor> p =+ asio::detail::make_shared<Executor>(+ ASIO_MOVE_CAST(Executor)(other));+ target_ = p->template target<void>();+ new (&object_) asio::detail::shared_ptr<void>(+ ASIO_MOVE_CAST(asio::detail::shared_ptr<Executor>)(p));+ }++ any_executor_base(const any_executor_base& other) ASIO_NOEXCEPT+ : object_fns_(other.object_fns_),+ target_fns_(other.target_fns_)+ {+ object_fns_->copy(*this, other);+ }++ ~any_executor_base() ASIO_NOEXCEPT+ {+ object_fns_->destroy(*this);+ }++ any_executor_base& operator=(+ const any_executor_base& other) ASIO_NOEXCEPT+ {+ if (this != &other)+ {+ object_fns_->destroy(*this);+ object_fns_ = other.object_fns_;+ target_fns_ = other.target_fns_;+ object_fns_->copy(*this, other);+ }+ return *this;+ }++ any_executor_base& operator=(nullptr_t) ASIO_NOEXCEPT+ {+ object_fns_->destroy(*this);+ target_ = 0;+ object_fns_ = object_fns_table<void>();+ target_fns_ = target_fns_table<void>();+ return *this;+ }++#if defined(ASIO_HAS_MOVE)++ any_executor_base(any_executor_base&& other) ASIO_NOEXCEPT+ : object_fns_(other.object_fns_),+ target_fns_(other.target_fns_)+ {+ other.object_fns_ = object_fns_table<void>();+ other.target_fns_ = target_fns_table<void>();+ object_fns_->move(*this, other);+ other.target_ = 0;+ }++ any_executor_base& operator=(+ any_executor_base&& other) ASIO_NOEXCEPT+ {+ if (this != &other)+ {+ object_fns_->destroy(*this);+ object_fns_ = other.object_fns_;+ other.object_fns_ = object_fns_table<void>();+ target_fns_ = other.target_fns_;+ other.target_fns_ = target_fns_table<void>();+ object_fns_->move(*this, other);+ other.target_ = 0;+ }+ return *this;+ }++#endif // defined(ASIO_HAS_MOVE)++ void swap(any_executor_base& other) ASIO_NOEXCEPT+ {+ if (this != &other)+ {+ any_executor_base tmp(ASIO_MOVE_CAST(any_executor_base)(other));+ other = ASIO_MOVE_CAST(any_executor_base)(*this);+ *this = ASIO_MOVE_CAST(any_executor_base)(tmp);+ }+ }++ template <typename F>+ void execute(ASIO_MOVE_ARG(F) f) const+ {+ if (target_fns_->blocking_execute != 0)+ {+ asio::detail::non_const_lvalue<F> f2(f);+ target_fns_->blocking_execute(*this, function_view(f2.value));+ }+ else+ {+ target_fns_->execute(*this,+ function(ASIO_MOVE_CAST(F)(f), std::allocator<void>()));+ }+ }++ template <typename Executor>+ Executor* target()+ {+ return static_cast<Executor*>(target_);+ }++ template <typename Executor>+ const Executor* target() const+ {+ return static_cast<Executor*>(target_);+ }++ const std::type_info& target_type() const+ {+ return target_fns_->target_type();+ }++ struct unspecified_bool_type_t {};+ typedef void (*unspecified_bool_type)(unspecified_bool_type_t);+ static void unspecified_bool_true(unspecified_bool_type_t) {}++ operator unspecified_bool_type() const ASIO_NOEXCEPT+ {+ return target_ ? &any_executor_base::unspecified_bool_true : 0;+ }++ bool operator!() const ASIO_NOEXCEPT+ {+ return target_ == 0;+ }++protected:+ bool equality_helper(const any_executor_base& other) const ASIO_NOEXCEPT+ {+ if (target_ == other.target_)+ return true;+ if (target_ && !other.target_)+ return false;+ if (!target_ && other.target_)+ return false;+ if (target_fns_ != other.target_fns_)+ return false;+ return target_fns_->equal(*this, other);+ }++ template <typename Ex>+ Ex& object()+ {+ return *static_cast<Ex*>(static_cast<void*>(&object_));+ }++ template <typename Ex>+ const Ex& object() const+ {+ return *static_cast<const Ex*>(static_cast<const void*>(&object_));+ }++ struct object_fns+ {+ void (*destroy)(any_executor_base&);+ void (*copy)(any_executor_base&, const any_executor_base&);+ void (*move)(any_executor_base&, any_executor_base&);+ const void* (*target)(const any_executor_base&);+ };++ static void destroy_void(any_executor_base&)+ {+ }++ static void copy_void(any_executor_base& ex1, const any_executor_base&)+ {+ ex1.target_ = 0;+ }++ static void move_void(any_executor_base& ex1, any_executor_base&)+ {+ ex1.target_ = 0;+ }++ static const void* target_void(const any_executor_base&)+ {+ return 0;+ }++ template <typename Obj>+ static const object_fns* object_fns_table(+ typename enable_if<+ is_same<Obj, void>::value+ >::type* = 0)+ {+ static const object_fns fns =+ {+ &any_executor_base::destroy_void,+ &any_executor_base::copy_void,+ &any_executor_base::move_void,+ &any_executor_base::target_void+ };+ return &fns;+ }++ static void destroy_shared(any_executor_base& ex)+ {+ typedef asio::detail::shared_ptr<void> type;+ ex.object<type>().~type();+ }++ static void copy_shared(any_executor_base& ex1, const any_executor_base& ex2)+ {+ typedef asio::detail::shared_ptr<void> type;+ new (&ex1.object_) type(ex2.object<type>());+ ex1.target_ = ex2.target_;+ }++ static void move_shared(any_executor_base& ex1, any_executor_base& ex2)+ {+ typedef asio::detail::shared_ptr<void> type;+ new (&ex1.object_) type(ASIO_MOVE_CAST(type)(ex2.object<type>()));+ ex1.target_ = ex2.target_;+ ex2.object<type>().~type();+ }++ static const void* target_shared(const any_executor_base& ex)+ {+ typedef asio::detail::shared_ptr<void> type;+ return ex.object<type>().get();+ }++ template <typename Obj>+ static const object_fns* object_fns_table(+ typename enable_if<+ is_same<Obj, asio::detail::shared_ptr<void> >::value+ >::type* = 0)+ {+ static const object_fns fns =+ {+ &any_executor_base::destroy_shared,+ &any_executor_base::copy_shared,+ &any_executor_base::move_shared,+ &any_executor_base::target_shared+ };+ return &fns;+ }++ template <typename Obj>+ static void destroy_object(any_executor_base& ex)+ {+ ex.object<Obj>().~Obj();+ }++ template <typename Obj>+ static void copy_object(any_executor_base& ex1, const any_executor_base& ex2)+ {+ new (&ex1.object_) Obj(ex2.object<Obj>());+ ex1.target_ = &ex1.object<Obj>();+ }++ template <typename Obj>+ static void move_object(any_executor_base& ex1, any_executor_base& ex2)+ {+ new (&ex1.object_) Obj(ASIO_MOVE_CAST(Obj)(ex2.object<Obj>()));+ ex1.target_ = &ex1.object<Obj>();+ ex2.object<Obj>().~Obj();+ }++ template <typename Obj>+ static const void* target_object(const any_executor_base& ex)+ {+ return &ex.object<Obj>();+ }++ template <typename Obj>+ static const object_fns* object_fns_table(+ typename enable_if<+ !is_same<Obj, void>::value+ && !is_same<Obj, asio::detail::shared_ptr<void> >::value+ >::type* = 0)+ {+ static const object_fns fns =+ {+ &any_executor_base::destroy_object<Obj>,+ &any_executor_base::copy_object<Obj>,+ &any_executor_base::move_object<Obj>,+ &any_executor_base::target_object<Obj>+ };+ return &fns;+ }++ typedef asio::detail::executor_function function;+ typedef asio::detail::executor_function_view function_view;++ struct target_fns+ {+ const std::type_info& (*target_type)();+ bool (*equal)(const any_executor_base&, const any_executor_base&);+ void (*execute)(const any_executor_base&, ASIO_MOVE_ARG(function));+ void (*blocking_execute)(const any_executor_base&, function_view);+ };++ static const std::type_info& target_type_void()+ {+ return typeid(void);+ }++ static bool equal_void(const any_executor_base&, const any_executor_base&)+ {+ return true;+ }++ static void execute_void(const any_executor_base&,+ ASIO_MOVE_ARG(function))+ {+ bad_executor ex;+ asio::detail::throw_exception(ex);+ }++ static void blocking_execute_void(const any_executor_base&, function_view)+ {+ bad_executor ex;+ asio::detail::throw_exception(ex);+ }++ template <typename Ex>+ static const target_fns* target_fns_table(+ typename enable_if<+ is_same<Ex, void>::value+ >::type* = 0)+ {+ static const target_fns fns =+ {+ &any_executor_base::target_type_void,+ &any_executor_base::equal_void,+ &any_executor_base::execute_void,+ &any_executor_base::blocking_execute_void+ };+ return &fns;+ }++ template <typename Ex>+ static const std::type_info& target_type_ex()+ {+ return typeid(Ex);+ }++ template <typename Ex>+ static bool equal_ex(const any_executor_base& ex1,+ const any_executor_base& ex2)+ {+ return *ex1.target<Ex>() == *ex2.target<Ex>();+ }++ template <typename Ex>+ static void execute_ex(const any_executor_base& ex,+ ASIO_MOVE_ARG(function) f)+ {+ execution::execute(*ex.target<Ex>(), ASIO_MOVE_CAST(function)(f));+ }++ template <typename Ex>+ static void blocking_execute_ex(const any_executor_base& ex, function_view f)+ {+ execution::execute(*ex.target<Ex>(), f);+ }++ template <typename Ex>+ static const target_fns* target_fns_table(bool is_always_blocking,+ typename enable_if<+ !is_same<Ex, void>::value+ >::type* = 0)+ {+ static const target_fns fns_with_execute =+ {+ &any_executor_base::target_type_ex<Ex>,+ &any_executor_base::equal_ex<Ex>,+ &any_executor_base::execute_ex<Ex>,+ 0+ };++ static const target_fns fns_with_blocking_execute =+ {+ &any_executor_base::target_type_ex<Ex>,+ &any_executor_base::equal_ex<Ex>,+ 0,+ &any_executor_base::blocking_execute_ex<Ex>+ };++ return is_always_blocking ? &fns_with_blocking_execute : &fns_with_execute;+ }++#if defined(ASIO_MSVC)+# pragma warning (push)+# pragma warning (disable:4702)+#endif // defined(ASIO_MSVC)++ static void query_fn_void(void*, const void*, const void*)+ {+ bad_executor ex;+ asio::detail::throw_exception(ex);+ }++ template <typename Ex, class Prop>+ static void query_fn_non_void(void*, const void* ex, const void* prop,+ typename enable_if<+ asio::can_query<const Ex&, const Prop&>::value+ && is_same<typename Prop::polymorphic_query_result_type, void>::value+ >::type*)+ {+ asio::query(*static_cast<const Ex*>(ex),+ *static_cast<const Prop*>(prop));+ }++ template <typename Ex, class Prop>+ static void query_fn_non_void(void*, const void*, const void*,+ typename enable_if<+ !asio::can_query<const Ex&, const Prop&>::value+ && is_same<typename Prop::polymorphic_query_result_type, void>::value+ >::type*)+ {+ }++ template <typename Ex, class Prop>+ static void query_fn_non_void(void* result, const void* ex, const void* prop,+ typename enable_if<+ asio::can_query<const Ex&, const Prop&>::value+ && !is_same<typename Prop::polymorphic_query_result_type, void>::value+ && is_reference<typename Prop::polymorphic_query_result_type>::value+ >::type*)+ {+ *static_cast<typename remove_reference<+ typename Prop::polymorphic_query_result_type>::type**>(result)+ = &static_cast<typename Prop::polymorphic_query_result_type>(+ asio::query(*static_cast<const Ex*>(ex),+ *static_cast<const Prop*>(prop)));+ }++ template <typename Ex, class Prop>+ static void query_fn_non_void(void*, const void*, const void*,+ typename enable_if<+ !asio::can_query<const Ex&, const Prop&>::value+ && !is_same<typename Prop::polymorphic_query_result_type, void>::value+ && is_reference<typename Prop::polymorphic_query_result_type>::value+ >::type*)+ {+ std::terminate(); // Combination should not be possible.+ }++ template <typename Ex, class Prop>+ static void query_fn_non_void(void* result, const void* ex, const void* prop,+ typename enable_if<+ asio::can_query<const Ex&, const Prop&>::value+ && !is_same<typename Prop::polymorphic_query_result_type, void>::value+ && is_scalar<typename Prop::polymorphic_query_result_type>::value+ >::type*)+ {+ *static_cast<typename Prop::polymorphic_query_result_type*>(result)+ = static_cast<typename Prop::polymorphic_query_result_type>(+ asio::query(*static_cast<const Ex*>(ex),+ *static_cast<const Prop*>(prop)));+ }++ template <typename Ex, class Prop>+ static void query_fn_non_void(void* result, const void*, const void*,+ typename enable_if<+ !asio::can_query<const Ex&, const Prop&>::value+ && !is_same<typename Prop::polymorphic_query_result_type, void>::value+ && is_scalar<typename Prop::polymorphic_query_result_type>::value+ >::type*)+ {+ *static_cast<typename Prop::polymorphic_query_result_type*>(result)+ = typename Prop::polymorphic_query_result_type();+ }++ template <typename Ex, class Prop>+ static void query_fn_non_void(void* result, const void* ex, const void* prop,+ typename enable_if<+ asio::can_query<const Ex&, const Prop&>::value+ && !is_same<typename Prop::polymorphic_query_result_type, void>::value+ && !is_reference<typename Prop::polymorphic_query_result_type>::value+ && !is_scalar<typename Prop::polymorphic_query_result_type>::value+ >::type*)+ {+ *static_cast<typename Prop::polymorphic_query_result_type**>(result)+ = new typename Prop::polymorphic_query_result_type(+ asio::query(*static_cast<const Ex*>(ex),+ *static_cast<const Prop*>(prop)));+ }++ template <typename Ex, class Prop>+ static void query_fn_non_void(void* result, const void*, const void*, ...)+ {+ *static_cast<typename Prop::polymorphic_query_result_type**>(result)+ = new typename Prop::polymorphic_query_result_type();+ }++ template <typename Ex, class Prop>+ static void query_fn_impl(void* result, const void* ex, const void* prop,+ typename enable_if<+ is_same<Ex, void>::value+ >::type*)+ {+ query_fn_void(result, ex, prop);+ }++ template <typename Ex, class Prop>+ static void query_fn_impl(void* result, const void* ex, const void* prop,+ typename enable_if<+ !is_same<Ex, void>::value+ >::type*)+ {+ query_fn_non_void<Ex, Prop>(result, ex, prop, 0);+ }++ template <typename Ex, class Prop>+ static void query_fn(void* result, const void* ex, const void* prop)+ {+ query_fn_impl<Ex, Prop>(result, ex, prop, 0);+ }++ template <typename Poly, typename Ex, class Prop>+ static Poly require_fn_impl(const void*, const void*,+ typename enable_if<+ is_same<Ex, void>::value+ >::type*)+ {+ bad_executor ex;+ asio::detail::throw_exception(ex);+ return Poly();+ }++ template <typename Poly, typename Ex, class Prop>+ static Poly require_fn_impl(const void* ex, const void* prop,+ typename enable_if<+ !is_same<Ex, void>::value && Prop::is_requirable+ >::type*)+ {+ return asio::require(*static_cast<const Ex*>(ex),+ *static_cast<const Prop*>(prop));+ }++ template <typename Poly, typename Ex, class Prop>+ static Poly require_fn_impl(const void*, const void*, ...)+ {+ return Poly();+ }++ template <typename Poly, typename Ex, class Prop>+ static Poly require_fn(const void* ex, const void* prop)+ {+ return require_fn_impl<Poly, Ex, Prop>(ex, prop, 0);+ }++ template <typename Poly, typename Ex, class Prop>+ static Poly prefer_fn_impl(const void*, const void*,+ typename enable_if<+ is_same<Ex, void>::value+ >::type*)+ {+ bad_executor ex;+ asio::detail::throw_exception(ex);+ return Poly();+ }++ template <typename Poly, typename Ex, class Prop>+ static Poly prefer_fn_impl(const void* ex, const void* prop,+ typename enable_if<+ !is_same<Ex, void>::value && Prop::is_preferable+ >::type*)+ {+ return asio::prefer(*static_cast<const Ex*>(ex),+ *static_cast<const Prop*>(prop));+ }++ template <typename Poly, typename Ex, class Prop>+ static Poly prefer_fn_impl(const void*, const void*, ...)+ {+ return Poly();+ }++ template <typename Poly, typename Ex, class Prop>+ static Poly prefer_fn(const void* ex, const void* prop)+ {+ return prefer_fn_impl<Poly, Ex, Prop>(ex, prop, 0);+ }++ template <typename Poly>+ struct prop_fns+ {+ void (*query)(void*, const void*, const void*);+ Poly (*require)(const void*, const void*);+ Poly (*prefer)(const void*, const void*);+ };++#if defined(ASIO_MSVC)+# pragma warning (pop)+#endif // defined(ASIO_MSVC)++private:+ template <typename Executor>+ static execution::blocking_t query_blocking(const Executor& ex, true_type)+ {+ return asio::query(ex, execution::blocking);+ }++ template <typename Executor>+ static execution::blocking_t query_blocking(const Executor&, false_type)+ {+ return execution::blocking_t();+ }++ template <typename Executor>+ void construct_object(Executor& ex, true_type)+ {+ object_fns_ = object_fns_table<Executor>();+ target_ = new (&object_) Executor(ASIO_MOVE_CAST(Executor)(ex));+ }++ template <typename Executor>+ void construct_object(Executor& ex, false_type)+ {+ object_fns_ = object_fns_table<asio::detail::shared_ptr<void> >();+ asio::detail::shared_ptr<Executor> p =+ asio::detail::make_shared<Executor>(+ ASIO_MOVE_CAST(Executor)(ex));+ target_ = p.get();+ new (&object_) asio::detail::shared_ptr<void>(+ ASIO_MOVE_CAST(asio::detail::shared_ptr<Executor>)(p));+ }++/*private:*/public:+// template <typename...> friend class any_executor;++ typedef aligned_storage<+ sizeof(asio::detail::shared_ptr<void>),+ alignment_of<asio::detail::shared_ptr<void> >::value+ >::type object_type;++ object_type object_;+ const object_fns* object_fns_;+ void* target_;+ const target_fns* target_fns_;+};++template <typename Derived, typename Property, typename = void>+struct any_executor_context+{+};++#if !defined(ASIO_NO_TS_EXECUTORS)++template <typename Derived, typename Property>+struct any_executor_context<Derived, Property,+ typename enable_if<Property::value>::type>+{+ typename Property::query_result_type context() const+ {+ return static_cast<const Derived*>(this)->query(typename Property::type());+ }+};++#endif // !defined(ASIO_NO_TS_EXECUTORS)++} // namespace detail++template <>+class any_executor<> : public detail::any_executor_base+{+public:+ any_executor() ASIO_NOEXCEPT+ : detail::any_executor_base()+ {+ }++ any_executor(nullptr_t) ASIO_NOEXCEPT+ : detail::any_executor_base()+ {+ }++ template <typename Executor>+ any_executor(Executor ex,+ typename enable_if<+ conditional<+ !is_same<Executor, any_executor>::value+ && !is_base_of<detail::any_executor_base, Executor>::value,+ is_executor<Executor>,+ false_type+ >::type::value+ >::type* = 0)+ : detail::any_executor_base(+ ASIO_MOVE_CAST(Executor)(ex), false_type())+ {+ }++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename... OtherSupportableProperties>+ any_executor(any_executor<OtherSupportableProperties...> other)+ : detail::any_executor_base(+ static_cast<const detail::any_executor_base&>(other))+ {+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename U0, typename U1, typename U2, typename U3,+ typename U4, typename U5, typename U6, typename U7>+ any_executor(any_executor<U0, U1, U2, U3, U4, U5, U6, U7> other)+ : detail::any_executor_base(+ static_cast<const detail::any_executor_base&>(other))+ {+ }++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ any_executor(const any_executor& other) ASIO_NOEXCEPT+ : detail::any_executor_base(+ static_cast<const detail::any_executor_base&>(other))+ {+ }++ any_executor& operator=(const any_executor& other) ASIO_NOEXCEPT+ {+ if (this != &other)+ {+ detail::any_executor_base::operator=(+ static_cast<const detail::any_executor_base&>(other));+ }+ return *this;+ }++ any_executor& operator=(nullptr_t p) ASIO_NOEXCEPT+ {+ detail::any_executor_base::operator=(p);+ return *this;+ }++#if defined(ASIO_HAS_MOVE)++ any_executor(any_executor&& other) ASIO_NOEXCEPT+ : detail::any_executor_base(+ static_cast<any_executor_base&&>(+ static_cast<any_executor_base&>(other)))+ {+ }++ any_executor& operator=(any_executor&& other) ASIO_NOEXCEPT+ {+ if (this != &other)+ {+ detail::any_executor_base::operator=(+ static_cast<detail::any_executor_base&&>(+ static_cast<detail::any_executor_base&>(other)));+ }+ return *this;+ }++#endif // defined(ASIO_HAS_MOVE)++ void swap(any_executor& other) ASIO_NOEXCEPT+ {+ detail::any_executor_base::swap(+ static_cast<detail::any_executor_base&>(other));+ }++ using detail::any_executor_base::execute;+ using detail::any_executor_base::target;+ using detail::any_executor_base::target_type;+ using detail::any_executor_base::operator unspecified_bool_type;+ using detail::any_executor_base::operator!;++ bool equality_helper(const any_executor& other) const ASIO_NOEXCEPT+ {+ return any_executor_base::equality_helper(other);+ }+};++inline bool operator==(const any_executor<>& a,+ const any_executor<>& b) ASIO_NOEXCEPT+{+ return a.equality_helper(b);+}++inline bool operator==(const any_executor<>& a, nullptr_t) ASIO_NOEXCEPT+{+ return !a;+}++inline bool operator==(nullptr_t, const any_executor<>& b) ASIO_NOEXCEPT+{+ return !b;+}++inline bool operator!=(const any_executor<>& a,+ const any_executor<>& b) ASIO_NOEXCEPT+{+ return !a.equality_helper(b);+}++inline bool operator!=(const any_executor<>& a, nullptr_t) ASIO_NOEXCEPT+{+ return !!a;+}++inline bool operator!=(nullptr_t, const any_executor<>& b) ASIO_NOEXCEPT+{+ return !!b;+}++inline void swap(any_executor<>& a, any_executor<>& b) ASIO_NOEXCEPT+{+ return a.swap(b);+}++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename... SupportableProperties>+class any_executor :+ public detail::any_executor_base,+ public detail::any_executor_context<+ any_executor<SupportableProperties...>,+ typename detail::supportable_properties<+ 0, void(SupportableProperties...)>::find_context_as_property>+{+public:+ any_executor() ASIO_NOEXCEPT+ : detail::any_executor_base(),+ prop_fns_(prop_fns_table<void>())+ {+ }++ any_executor(nullptr_t) ASIO_NOEXCEPT+ : detail::any_executor_base(),+ prop_fns_(prop_fns_table<void>())+ {+ }++ template <typename Executor>+ any_executor(Executor ex,+ typename enable_if<+ conditional<+ !is_same<Executor, any_executor>::value+ && !is_base_of<detail::any_executor_base, Executor>::value,+ detail::is_valid_target_executor<+ Executor, void(SupportableProperties...)>,+ false_type+ >::type::value+ >::type* = 0)+ : detail::any_executor_base(+ ASIO_MOVE_CAST(Executor)(ex), false_type()),+ prop_fns_(prop_fns_table<Executor>())+ {+ }++ template <typename... OtherSupportableProperties>+ any_executor(any_executor<OtherSupportableProperties...> other,+ typename enable_if<+ conditional<+ !is_same<+ any_executor<OtherSupportableProperties...>,+ any_executor+ >::value,+ typename detail::supportable_properties<+ 0, void(SupportableProperties...)>::template is_valid_target<+ any_executor<OtherSupportableProperties...> >,+ false_type+ >::type::value+ >::type* = 0)+ : detail::any_executor_base(ASIO_MOVE_CAST(+ any_executor<OtherSupportableProperties...>)(other), true_type()),+ prop_fns_(prop_fns_table<any_executor<OtherSupportableProperties...> >())+ {+ }++ any_executor(const any_executor& other) ASIO_NOEXCEPT+ : detail::any_executor_base(+ static_cast<const detail::any_executor_base&>(other)),+ prop_fns_(other.prop_fns_)+ {+ }++ any_executor& operator=(const any_executor& other) ASIO_NOEXCEPT+ {+ if (this != &other)+ {+ prop_fns_ = other.prop_fns_;+ detail::any_executor_base::operator=(+ static_cast<const detail::any_executor_base&>(other));+ }+ return *this;+ }++ any_executor& operator=(nullptr_t p) ASIO_NOEXCEPT+ {+ prop_fns_ = prop_fns_table<void>();+ detail::any_executor_base::operator=(p);+ return *this;+ }++#if defined(ASIO_HAS_MOVE)++ any_executor(any_executor&& other) ASIO_NOEXCEPT+ : detail::any_executor_base(+ static_cast<any_executor_base&&>(+ static_cast<any_executor_base&>(other))),+ prop_fns_(other.prop_fns_)+ {+ other.prop_fns_ = prop_fns_table<void>();+ }++ any_executor& operator=(any_executor&& other) ASIO_NOEXCEPT+ {+ if (this != &other)+ {+ prop_fns_ = other.prop_fns_;+ detail::any_executor_base::operator=(+ static_cast<detail::any_executor_base&&>(+ static_cast<detail::any_executor_base&>(other)));+ }+ return *this;+ }++#endif // defined(ASIO_HAS_MOVE)++ void swap(any_executor& other) ASIO_NOEXCEPT+ {+ if (this != &other)+ {+ detail::any_executor_base::swap(+ static_cast<detail::any_executor_base&>(other));+ const prop_fns<any_executor>* tmp_prop_fns = other.prop_fns_;+ other.prop_fns_ = prop_fns_;+ prop_fns_ = tmp_prop_fns;+ }+ }++ using detail::any_executor_base::execute;+ using detail::any_executor_base::target;+ using detail::any_executor_base::target_type;+ using detail::any_executor_base::operator unspecified_bool_type;+ using detail::any_executor_base::operator!;++ bool equality_helper(const any_executor& other) const ASIO_NOEXCEPT+ {+ return any_executor_base::equality_helper(other);+ }++ template <typename T>+ struct find_convertible_property :+ detail::supportable_properties<+ 0, void(SupportableProperties...)>::template+ find_convertible_property<T> {};++ template <typename Property>+ void query(const Property& p,+ typename enable_if<+ is_same<+ typename find_convertible_property<Property>::query_result_type,+ void+ >::value+ >::type* = 0) const+ {+ typedef find_convertible_property<Property> found;+ prop_fns_[found::index].query(0, object_fns_->target(*this),+ &static_cast<const typename found::type&>(p));+ }++ template <typename Property>+ typename find_convertible_property<Property>::query_result_type+ query(const Property& p,+ typename enable_if<+ !is_same<+ typename find_convertible_property<Property>::query_result_type,+ void+ >::value+ &&+ is_reference<+ typename find_convertible_property<Property>::query_result_type+ >::value+ >::type* = 0) const+ {+ typedef find_convertible_property<Property> found;+ typename remove_reference<+ typename found::query_result_type>::type* result = 0;+ prop_fns_[found::index].query(&result, object_fns_->target(*this),+ &static_cast<const typename found::type&>(p));+ return *result;+ }++ template <typename Property>+ typename find_convertible_property<Property>::query_result_type+ query(const Property& p,+ typename enable_if<+ !is_same<+ typename find_convertible_property<Property>::query_result_type,+ void+ >::value+ &&+ is_scalar<+ typename find_convertible_property<Property>::query_result_type+ >::value+ >::type* = 0) const+ {+ typedef find_convertible_property<Property> found;+ typename found::query_result_type result;+ prop_fns_[found::index].query(&result, object_fns_->target(*this),+ &static_cast<const typename found::type&>(p));+ return result;+ }++ template <typename Property>+ typename find_convertible_property<Property>::query_result_type+ query(const Property& p,+ typename enable_if<+ !is_same<+ typename find_convertible_property<Property>::query_result_type,+ void+ >::value+ &&+ !is_reference<+ typename find_convertible_property<Property>::query_result_type+ >::value+ &&+ !is_scalar<+ typename find_convertible_property<Property>::query_result_type+ >::value+ >::type* = 0) const+ {+ typedef find_convertible_property<Property> found;+ typename found::query_result_type* result;+ prop_fns_[found::index].query(&result, object_fns_->target(*this),+ &static_cast<const typename found::type&>(p));+ return *asio::detail::scoped_ptr<+ typename found::query_result_type>(result);+ }++ template <typename T>+ struct find_convertible_requirable_property :+ detail::supportable_properties<+ 0, void(SupportableProperties...)>::template+ find_convertible_requirable_property<T> {};++ template <typename Property>+ any_executor require(const Property& p,+ typename enable_if<+ find_convertible_requirable_property<Property>::value+ >::type* = 0) const+ {+ typedef find_convertible_requirable_property<Property> found;+ return prop_fns_[found::index].require(object_fns_->target(*this),+ &static_cast<const typename found::type&>(p));+ }++ template <typename T>+ struct find_convertible_preferable_property :+ detail::supportable_properties<+ 0, void(SupportableProperties...)>::template+ find_convertible_preferable_property<T> {};++ template <typename Property>+ any_executor prefer(const Property& p,+ typename enable_if<+ find_convertible_preferable_property<Property>::value+ >::type* = 0) const+ {+ typedef find_convertible_preferable_property<Property> found;+ return prop_fns_[found::index].prefer(object_fns_->target(*this),+ &static_cast<const typename found::type&>(p));+ }++//private:+ template <typename Ex>+ static const prop_fns<any_executor>* prop_fns_table()+ {+ static const prop_fns<any_executor> fns[] =+ {+ {+ &detail::any_executor_base::query_fn<+ Ex, SupportableProperties>,+ &detail::any_executor_base::require_fn<+ any_executor, Ex, SupportableProperties>,+ &detail::any_executor_base::prefer_fn<+ any_executor, Ex, SupportableProperties>+ }...+ };+ return fns;+ }++ const prop_fns<any_executor>* prop_fns_;+};++template <typename... SupportableProperties>+inline bool operator==(const any_executor<SupportableProperties...>& a,+ const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT+{+ return a.equality_helper(b);+}++template <typename... SupportableProperties>+inline bool operator==(const any_executor<SupportableProperties...>& a,+ nullptr_t) ASIO_NOEXCEPT+{+ return !a;+}++template <typename... SupportableProperties>+inline bool operator==(nullptr_t,+ const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT+{+ return !b;+}++template <typename... SupportableProperties>+inline bool operator!=(const any_executor<SupportableProperties...>& a,+ const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT+{+ return !a.equality_helper(b);+}++template <typename... SupportableProperties>+inline bool operator!=(const any_executor<SupportableProperties...>& a,+ nullptr_t) ASIO_NOEXCEPT+{+ return !!a;+}++template <typename... SupportableProperties>+inline bool operator!=(nullptr_t,+ const any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT+{+ return !!b;+}++template <typename... SupportableProperties>+inline void swap(any_executor<SupportableProperties...>& a,+ any_executor<SupportableProperties...>& b) ASIO_NOEXCEPT+{+ return a.swap(b);+}++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \+ ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_##n++#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1 \+ { \+ &detail::any_executor_base::query_fn<Ex, T1>, \+ &detail::any_executor_base::require_fn<any_executor, Ex, T1>, \+ &detail::any_executor_base::prefer_fn<any_executor, Ex, T1> \+ }+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2 \+ ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1, \+ { \+ &detail::any_executor_base::query_fn<Ex, T2>, \+ &detail::any_executor_base::require_fn<any_executor, Ex, T2>, \+ &detail::any_executor_base::prefer_fn<any_executor, Ex, T2> \+ }+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3 \+ ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2, \+ { \+ &detail::any_executor_base::query_fn<Ex, T3>, \+ &detail::any_executor_base::require_fn<any_executor, Ex, T3>, \+ &detail::any_executor_base::prefer_fn<any_executor, Ex, T3> \+ }+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4 \+ ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3, \+ { \+ &detail::any_executor_base::query_fn<Ex, T4>, \+ &detail::any_executor_base::require_fn<any_executor, Ex, T4>, \+ &detail::any_executor_base::prefer_fn<any_executor, Ex, T4> \+ }+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5 \+ ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4, \+ { \+ &detail::any_executor_base::query_fn<Ex, T5>, \+ &detail::any_executor_base::require_fn<any_executor, Ex, T5>, \+ &detail::any_executor_base::prefer_fn<any_executor, Ex, T5> \+ }+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6 \+ ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5, \+ { \+ &detail::any_executor_base::query_fn<Ex, T6>, \+ &detail::any_executor_base::require_fn<any_executor, Ex, T6>, \+ &detail::any_executor_base::prefer_fn<any_executor, Ex, T6> \+ }+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7 \+ ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6, \+ { \+ &detail::any_executor_base::query_fn<Ex, T7>, \+ &detail::any_executor_base::require_fn<any_executor, Ex, T7>, \+ &detail::any_executor_base::prefer_fn<any_executor, Ex, T7> \+ }+#define ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8 \+ ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7, \+ { \+ &detail::any_executor_base::query_fn<Ex, T8>, \+ &detail::any_executor_base::require_fn<any_executor, Ex, T8>, \+ &detail::any_executor_base::prefer_fn<any_executor, Ex, T8> \+ }++#if defined(ASIO_HAS_MOVE)++# define ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \+ any_executor(any_executor&& other) ASIO_NOEXCEPT \+ : detail::any_executor_base( \+ static_cast<any_executor_base&&>( \+ static_cast<any_executor_base&>(other))), \+ prop_fns_(other.prop_fns_) \+ { \+ other.prop_fns_ = prop_fns_table<void>(); \+ } \+ \+ any_executor& operator=(any_executor&& other) ASIO_NOEXCEPT \+ { \+ if (this != &other) \+ { \+ prop_fns_ = other.prop_fns_; \+ detail::any_executor_base::operator=( \+ static_cast<detail::any_executor_base&&>( \+ static_cast<detail::any_executor_base&>(other))); \+ } \+ return *this; \+ } \+ /**/+#else // defined(ASIO_HAS_MOVE)++# define ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS++#endif // defined(ASIO_HAS_MOVE)++#define ASIO_PRIVATE_ANY_EXECUTOR_DEF(n) \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ class any_executor<ASIO_VARIADIC_TARGS(n)> : \+ public detail::any_executor_base, \+ public detail::any_executor_context< \+ any_executor<ASIO_VARIADIC_TARGS(n)>, \+ typename detail::supportable_properties< \+ 0, void(ASIO_VARIADIC_TARGS(n))>::find_context_as_property> \+ { \+ public: \+ any_executor() ASIO_NOEXCEPT \+ : detail::any_executor_base(), \+ prop_fns_(prop_fns_table<void>()) \+ { \+ } \+ \+ any_executor(nullptr_t) ASIO_NOEXCEPT \+ : detail::any_executor_base(), \+ prop_fns_(prop_fns_table<void>()) \+ { \+ } \+ \+ template <ASIO_EXECUTION_EXECUTOR Executor> \+ any_executor(Executor ex, \+ typename enable_if< \+ conditional< \+ !is_same<Executor, any_executor>::value \+ && !is_base_of<detail::any_executor_base, Executor>::value, \+ detail::is_valid_target_executor< \+ Executor, void(ASIO_VARIADIC_TARGS(n))>, \+ false_type \+ >::type::value \+ >::type* = 0) \+ : detail::any_executor_base(ASIO_MOVE_CAST( \+ Executor)(ex), false_type()), \+ prop_fns_(prop_fns_table<Executor>()) \+ { \+ } \+ \+ any_executor(const any_executor& other) ASIO_NOEXCEPT \+ : detail::any_executor_base( \+ static_cast<const detail::any_executor_base&>(other)), \+ prop_fns_(other.prop_fns_) \+ { \+ } \+ \+ any_executor(any_executor<> other) \+ : detail::any_executor_base(ASIO_MOVE_CAST( \+ any_executor<>)(other), true_type()), \+ prop_fns_(prop_fns_table<any_executor<> >()) \+ { \+ } \+ \+ template <typename OtherAnyExecutor> \+ any_executor(OtherAnyExecutor other, \+ typename enable_if< \+ conditional< \+ !is_same<OtherAnyExecutor, any_executor>::value \+ && is_base_of<detail::any_executor_base, \+ OtherAnyExecutor>::value, \+ typename detail::supportable_properties< \+ 0, void(ASIO_VARIADIC_TARGS(n))>::template \+ is_valid_target<OtherAnyExecutor>, \+ false_type \+ >::type::value \+ >::type* = 0) \+ : detail::any_executor_base(ASIO_MOVE_CAST( \+ OtherAnyExecutor)(other), true_type()), \+ prop_fns_(prop_fns_table<OtherAnyExecutor>()) \+ { \+ } \+ \+ any_executor& operator=(const any_executor& other) ASIO_NOEXCEPT \+ { \+ if (this != &other) \+ { \+ prop_fns_ = other.prop_fns_; \+ detail::any_executor_base::operator=( \+ static_cast<const detail::any_executor_base&>(other)); \+ } \+ return *this; \+ } \+ \+ any_executor& operator=(nullptr_t p) ASIO_NOEXCEPT \+ { \+ prop_fns_ = prop_fns_table<void>(); \+ detail::any_executor_base::operator=(p); \+ return *this; \+ } \+ \+ ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \+ \+ void swap(any_executor& other) ASIO_NOEXCEPT \+ { \+ if (this != &other) \+ { \+ detail::any_executor_base::swap( \+ static_cast<detail::any_executor_base&>(other)); \+ const prop_fns<any_executor>* tmp_prop_fns = other.prop_fns_; \+ other.prop_fns_ = prop_fns_; \+ prop_fns_ = tmp_prop_fns; \+ } \+ } \+ \+ using detail::any_executor_base::execute; \+ using detail::any_executor_base::target; \+ using detail::any_executor_base::target_type; \+ using detail::any_executor_base::operator unspecified_bool_type; \+ using detail::any_executor_base::operator!; \+ \+ bool equality_helper(const any_executor& other) const ASIO_NOEXCEPT \+ { \+ return any_executor_base::equality_helper(other); \+ } \+ \+ template <typename T> \+ struct find_convertible_property : \+ detail::supportable_properties< \+ 0, void(ASIO_VARIADIC_TARGS(n))>::template \+ find_convertible_property<T> {}; \+ \+ template <typename Property> \+ void query(const Property& p, \+ typename enable_if< \+ is_same< \+ typename find_convertible_property<Property>::query_result_type, \+ void \+ >::value \+ >::type* = 0) const \+ { \+ typedef find_convertible_property<Property> found; \+ prop_fns_[found::index].query(0, object_fns_->target(*this), \+ &static_cast<const typename found::type&>(p)); \+ } \+ \+ template <typename Property> \+ typename find_convertible_property<Property>::query_result_type \+ query(const Property& p, \+ typename enable_if< \+ !is_same< \+ typename find_convertible_property<Property>::query_result_type, \+ void \+ >::value \+ && \+ is_reference< \+ typename find_convertible_property<Property>::query_result_type \+ >::value \+ >::type* = 0) const \+ { \+ typedef find_convertible_property<Property> found; \+ typename remove_reference< \+ typename found::query_result_type>::type* result; \+ prop_fns_[found::index].query(&result, object_fns_->target(*this), \+ &static_cast<const typename found::type&>(p)); \+ return *result; \+ } \+ \+ template <typename Property> \+ typename find_convertible_property<Property>::query_result_type \+ query(const Property& p, \+ typename enable_if< \+ !is_same< \+ typename find_convertible_property<Property>::query_result_type, \+ void \+ >::value \+ && \+ is_scalar< \+ typename find_convertible_property<Property>::query_result_type \+ >::value \+ >::type* = 0) const \+ { \+ typedef find_convertible_property<Property> found; \+ typename found::query_result_type result; \+ prop_fns_[found::index].query(&result, object_fns_->target(*this), \+ &static_cast<const typename found::type&>(p)); \+ return result; \+ } \+ \+ template <typename Property> \+ typename find_convertible_property<Property>::query_result_type \+ query(const Property& p, \+ typename enable_if< \+ !is_same< \+ typename find_convertible_property<Property>::query_result_type, \+ void \+ >::value \+ && \+ !is_reference< \+ typename find_convertible_property<Property>::query_result_type \+ >::value \+ && \+ !is_scalar< \+ typename find_convertible_property<Property>::query_result_type \+ >::value \+ >::type* = 0) const \+ { \+ typedef find_convertible_property<Property> found; \+ typename found::query_result_type* result; \+ prop_fns_[found::index].query(&result, object_fns_->target(*this), \+ &static_cast<const typename found::type&>(p)); \+ return *asio::detail::scoped_ptr< \+ typename found::query_result_type>(result); \+ } \+ \+ template <typename T> \+ struct find_convertible_requirable_property : \+ detail::supportable_properties< \+ 0, void(ASIO_VARIADIC_TARGS(n))>::template \+ find_convertible_requirable_property<T> {}; \+ \+ template <typename Property> \+ any_executor require(const Property& p, \+ typename enable_if< \+ find_convertible_requirable_property<Property>::value \+ >::type* = 0) const \+ { \+ typedef find_convertible_requirable_property<Property> found; \+ return prop_fns_[found::index].require(object_fns_->target(*this), \+ &static_cast<const typename found::type&>(p)); \+ } \+ \+ template <typename T> \+ struct find_convertible_preferable_property : \+ detail::supportable_properties< \+ 0, void(ASIO_VARIADIC_TARGS(n))>::template \+ find_convertible_preferable_property<T> {}; \+ \+ template <typename Property> \+ any_executor prefer(const Property& p, \+ typename enable_if< \+ find_convertible_preferable_property<Property>::value \+ >::type* = 0) const \+ { \+ typedef find_convertible_preferable_property<Property> found; \+ return prop_fns_[found::index].prefer(object_fns_->target(*this), \+ &static_cast<const typename found::type&>(p)); \+ } \+ \+ template <typename Ex> \+ static const prop_fns<any_executor>* prop_fns_table() \+ { \+ static const prop_fns<any_executor> fns[] = \+ { \+ ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \+ }; \+ return fns; \+ } \+ \+ const prop_fns<any_executor>* prop_fns_; \+ typedef detail::supportable_properties<0, \+ void(ASIO_VARIADIC_TARGS(n))> supportable_properties_type; \+ }; \+ \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ inline bool operator==(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \+ const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \+ { \+ return a.equality_helper(b); \+ } \+ \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ inline bool operator==(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \+ nullptr_t) ASIO_NOEXCEPT \+ { \+ return !a; \+ } \+ \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ inline bool operator==(nullptr_t, \+ const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \+ { \+ return !b; \+ } \+ \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ inline bool operator!=(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \+ const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \+ { \+ return !a.equality_helper(b); \+ } \+ \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ inline bool operator!=(const any_executor<ASIO_VARIADIC_TARGS(n)>& a, \+ nullptr_t) ASIO_NOEXCEPT \+ { \+ return !!a; \+ } \+ \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ inline bool operator!=(nullptr_t, \+ const any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \+ { \+ return !!b; \+ } \+ \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ inline void swap(any_executor<ASIO_VARIADIC_TARGS(n)>& a, \+ any_executor<ASIO_VARIADIC_TARGS(n)>& b) ASIO_NOEXCEPT \+ { \+ return a.swap(b); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_DEF)+#undef ASIO_PRIVATE_ANY_EXECUTOR_DEF+#undef ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7+#undef ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8++#endif // if defined(ASIO_HAS_VARIADIC_TEMPLATES)++} // namespace execution+namespace traits {++#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename... SupportableProperties>+struct equality_comparable<execution::any_executor<SupportableProperties...> >+{+ static const bool is_valid = true;+ static const bool is_noexcept = true;+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <>+struct equality_comparable<execution::any_executor<> >+{+ static const bool is_valid = true;+ static const bool is_noexcept = true;+};++#define ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF(n) \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ struct equality_comparable< \+ execution::any_executor<ASIO_VARIADIC_TARGS(n)> > \+ { \+ static const bool is_valid = true; \+ static const bool is_noexcept = true; \+ }; \+ /**/+ ASIO_VARIADIC_GENERATE(+ ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF)+#undef ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename F, typename... SupportableProperties>+struct execute_member<execution::any_executor<SupportableProperties...>, F>+{+ static const bool is_valid = true;+ static const bool is_noexcept = false;+ typedef void result_type;+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename F>+struct execute_member<execution::any_executor<>, F>+{+ static const bool is_valid = true;+ static const bool is_noexcept = false;+ typedef void result_type;+};++#define ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF(n) \+ template <typename F, ASIO_VARIADIC_TPARAMS(n)> \+ struct execute_member< \+ execution::any_executor<ASIO_VARIADIC_TARGS(n)>, F> \+ { \+ static const bool is_valid = true; \+ static const bool is_noexcept = false; \+ typedef void result_type; \+ }; \+ /**/+ ASIO_VARIADIC_GENERATE(+ ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF)+#undef ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename Prop, typename... SupportableProperties>+struct query_member<+ execution::any_executor<SupportableProperties...>, Prop,+ typename enable_if<+ execution::detail::supportable_properties<+ 0, void(SupportableProperties...)>::template+ find_convertible_property<Prop>::value+ >::type>+{+ static const bool is_valid = true;+ static const bool is_noexcept = false;+ typedef typename execution::detail::supportable_properties<+ 0, void(SupportableProperties...)>::template+ find_convertible_property<Prop>::query_result_type result_type;+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#define ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF(n) \+ template <typename Prop, ASIO_VARIADIC_TPARAMS(n)> \+ struct query_member< \+ execution::any_executor<ASIO_VARIADIC_TARGS(n)>, Prop, \+ typename enable_if< \+ execution::detail::supportable_properties< \+ 0, void(ASIO_VARIADIC_TARGS(n))>::template \+ find_convertible_property<Prop>::value \+ >::type> \+ { \+ static const bool is_valid = true; \+ static const bool is_noexcept = false; \+ typedef typename execution::detail::supportable_properties< \+ 0, void(ASIO_VARIADIC_TARGS(n))>::template \+ find_convertible_property<Prop>::query_result_type result_type; \+ }; \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF)+#undef ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename Prop, typename... SupportableProperties>+struct require_member<+ execution::any_executor<SupportableProperties...>, Prop,+ typename enable_if<+ execution::detail::supportable_properties<+ 0, void(SupportableProperties...)>::template+ find_convertible_requirable_property<Prop>::value+ >::type>+{+ static const bool is_valid = true;+ static const bool is_noexcept = false;+ typedef execution::any_executor<SupportableProperties...> result_type;+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#define ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF(n) \+ template <typename Prop, ASIO_VARIADIC_TPARAMS(n)> \+ struct require_member< \+ execution::any_executor<ASIO_VARIADIC_TARGS(n)>, Prop, \+ typename enable_if< \+ execution::detail::supportable_properties< \+ 0, void(ASIO_VARIADIC_TARGS(n))>::template \+ find_convertible_requirable_property<Prop>::value \+ >::type> \+ { \+ static const bool is_valid = true; \+ static const bool is_noexcept = false; \+ typedef execution::any_executor<ASIO_VARIADIC_TARGS(n)> result_type; \+ }; \+ /**/+ ASIO_VARIADIC_GENERATE(+ ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF)+#undef ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename Prop, typename... SupportableProperties>+struct prefer_member<+ execution::any_executor<SupportableProperties...>, Prop,+ typename enable_if<+ execution::detail::supportable_properties<+ 0, void(SupportableProperties...)>::template+ find_convertible_preferable_property<Prop>::value+ >::type>+{+ static const bool is_valid = true;+ static const bool is_noexcept = false;+ typedef execution::any_executor<SupportableProperties...> result_type;+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#define ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF(n) \+ template <typename Prop, ASIO_VARIADIC_TPARAMS(n)> \+ struct prefer_member< \+ execution::any_executor<ASIO_VARIADIC_TARGS(n)>, Prop, \+ typename enable_if< \+ execution::detail::supportable_properties< \+ 0, void(ASIO_VARIADIC_TARGS(n))>::template \+ find_convertible_preferable_property<Prop>::value \+ >::type> \+ { \+ static const bool is_valid = true; \+ static const bool is_noexcept = false; \+ typedef execution::any_executor<ASIO_VARIADIC_TARGS(n)> result_type; \+ }; \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF)+#undef ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+#endif // !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_ANY_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/bad_executor.hpp view
@@ -0,0 +1,47 @@+//+// execution/bad_executor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_BAD_EXECUTOR_HPP+#define ASIO_EXECUTION_BAD_EXECUTOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <exception>+#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {++/// Exception thrown when trying to access an empty polymorphic executor.+class bad_executor+ : public std::exception+{+public:+ /// Constructor.+ ASIO_DECL bad_executor() ASIO_NOEXCEPT;++ /// Obtain message associated with exception.+ ASIO_DECL virtual const char* what() const+ ASIO_NOEXCEPT_OR_NOTHROW;+};++} // namespace execution+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/execution/impl/bad_executor.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_EXECUTION_BAD_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/blocking.hpp view
@@ -0,0 +1,1351 @@+//+// execution/blocking.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_BLOCKING_HPP+#define ASIO_EXECUTION_BLOCKING_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/execute.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/is_applicable_property.hpp"+#include "asio/prefer.hpp"+#include "asio/query.hpp"+#include "asio/require.hpp"+#include "asio/traits/query_free.hpp"+#include "asio/traits/query_member.hpp"+#include "asio/traits/query_static_constexpr_member.hpp"+#include "asio/traits/static_query.hpp"+#include "asio/traits/static_require.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// A property to describe what guarantees an executor makes about the blocking+/// behaviour of their execution functions.+struct blocking_t+{+ /// The blocking_t property applies to executors, senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The top-level blocking_t property cannot be required.+ static constexpr bool is_requirable = false;++ /// The top-level blocking_t property cannot be preferred.+ static constexpr bool is_preferable = false;++ /// The type returned by queries against an @c any_executor.+ typedef blocking_t polymorphic_query_result_type;++ /// A sub-property that indicates that invocation of an executor's execution+ /// function may block pending completion of one or more invocations of the+ /// submitted function object.+ struct possibly_t+ {+ /// The blocking_t::possibly_t property applies to executors, senders, and+ /// schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The blocking_t::possibly_t property can be required.+ static constexpr bool is_requirable = true;++ /// The blocking_t::possibly_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef blocking_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr possibly_t();++ /// Get the value associated with a property object.+ /**+ * @returns possibly_t();+ */+ static constexpr blocking_t value();+ };++ /// A sub-property that indicates that invocation of an executor's execution+ /// function shall block until completion of all invocations of the submitted+ /// function object.+ struct always_t+ {+ /// The blocking_t::always_t property applies to executors, senders, and+ /// schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The blocking_t::always_t property can be required.+ static constexpr bool is_requirable = true;++ /// The blocking_t::always_t property can be preferred.+ static constexpr bool is_preferable = false;++ /// The type returned by queries against an @c any_executor.+ typedef blocking_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr always_t();++ /// Get the value associated with a property object.+ /**+ * @returns always_t();+ */+ static constexpr blocking_t value();+ };++ /// A sub-property that indicates that invocation of an executor's execution+ /// function shall not block pending completion of the invocations of the+ /// submitted function object.+ struct never_t+ {+ /// The blocking_t::never_t property applies to executors, senders, and+ /// schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The blocking_t::never_t property can be required.+ static constexpr bool is_requirable = true;++ /// The blocking_t::never_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef blocking_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr never_t();++ /// Get the value associated with a property object.+ /**+ * @returns never_t();+ */+ static constexpr blocking_t value();+ };++ /// A special value used for accessing the blocking_t::possibly_t property.+ static constexpr possibly_t possibly;++ /// A special value used for accessing the blocking_t::always_t property.+ static constexpr always_t always;++ /// A special value used for accessing the blocking_t::never_t property.+ static constexpr never_t never;++ /// Default constructor.+ constexpr blocking_t();++ /// Construct from a sub-property value.+ constexpr blocking_t(possibly_t);++ /// Construct from a sub-property value.+ constexpr blocking_t(always_t);++ /// Construct from a sub-property value.+ constexpr blocking_t(never_t);++ /// Compare property values for equality.+ friend constexpr bool operator==(+ const blocking_t& a, const blocking_t& b) noexcept;++ /// Compare property values for inequality.+ friend constexpr bool operator!=(+ const blocking_t& a, const blocking_t& b) noexcept;+};++/// A special value used for accessing the blocking_t property.+constexpr blocking_t blocking;++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {+namespace detail {+namespace blocking {++template <int I> struct possibly_t;+template <int I> struct always_t;+template <int I> struct never_t;++} // namespace blocking+namespace blocking_adaptation {++template <int I> struct allowed_t;++template <typename Executor, typename Function>+void blocking_execute(+ ASIO_MOVE_ARG(Executor) ex,+ ASIO_MOVE_ARG(Function) func);++} // namespace blocking_adaptation++template <int I = 0>+struct blocking_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);+ typedef blocking_t polymorphic_query_result_type;++ typedef detail::blocking::possibly_t<I> possibly_t;+ typedef detail::blocking::always_t<I> always_t;+ typedef detail::blocking::never_t<I> never_t;++ ASIO_CONSTEXPR blocking_t()+ : value_(-1)+ {+ }++ ASIO_CONSTEXPR blocking_t(possibly_t)+ : value_(0)+ {+ }++ ASIO_CONSTEXPR blocking_t(always_t)+ : value_(1)+ {+ }++ ASIO_CONSTEXPR blocking_t(never_t)+ : value_(2)+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, blocking_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, blocking_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, blocking_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, possibly_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, blocking_t>::is_valid+ && !traits::query_member<T, blocking_t>::is_valid+ && traits::static_query<T, possibly_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, possibly_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, always_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, blocking_t>::is_valid+ && !traits::query_member<T, blocking_t>::is_valid+ && !traits::static_query<T, possibly_t>::is_valid+ && traits::static_query<T, always_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, always_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, never_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, blocking_t>::is_valid+ && !traits::query_member<T, blocking_t>::is_valid+ && !traits::static_query<T, possibly_t>::is_valid+ && !traits::static_query<T, always_t>::is_valid+ && traits::static_query<T, never_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, never_t>::value();+ }++ template <typename E, typename T = decltype(blocking_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = blocking_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ friend ASIO_CONSTEXPR bool operator==(+ const blocking_t& a, const blocking_t& b)+ {+ return a.value_ == b.value_;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const blocking_t& a, const blocking_t& b)+ {+ return a.value_ != b.value_;+ }++ struct convertible_from_blocking_t+ {+ ASIO_CONSTEXPR convertible_from_blocking_t(blocking_t) {}+ };++ template <typename Executor>+ friend ASIO_CONSTEXPR blocking_t query(+ const Executor& ex, convertible_from_blocking_t,+ typename enable_if<+ can_query<const Executor&, possibly_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, blocking_t<>::possibly_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, possibly_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, possibly_t());+ }++ template <typename Executor>+ friend ASIO_CONSTEXPR blocking_t query(+ const Executor& ex, convertible_from_blocking_t,+ typename enable_if<+ !can_query<const Executor&, possibly_t>::value+ && can_query<const Executor&, always_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, blocking_t<>::always_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, always_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, always_t());+ }++ template <typename Executor>+ friend ASIO_CONSTEXPR blocking_t query(+ const Executor& ex, convertible_from_blocking_t,+ typename enable_if<+ !can_query<const Executor&, possibly_t>::value+ && !can_query<const Executor&, always_t>::value+ && can_query<const Executor&, never_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, blocking_t<>::never_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, never_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, never_t());+ }++ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(possibly_t, possibly);+ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(always_t, always);+ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(never_t, never);++#if !defined(ASIO_HAS_CONSTEXPR)+ static const blocking_t instance;+#endif // !defined(ASIO_HAS_CONSTEXPR)++private:+ int value_;+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T blocking_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_CONSTEXPR)+template <int I>+const blocking_t<I> blocking_t<I>::instance;+#endif++template <int I>+const typename blocking_t<I>::possibly_t blocking_t<I>::possibly;++template <int I>+const typename blocking_t<I>::always_t blocking_t<I>::always;++template <int I>+const typename blocking_t<I>::never_t blocking_t<I>::never;++namespace blocking {++template <int I = 0>+struct possibly_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef blocking_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR possibly_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, possibly_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, possibly_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, possibly_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR possibly_t static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, possibly_t>::is_valid+ && !traits::query_member<T, possibly_t>::is_valid+ && !traits::query_free<T, possibly_t>::is_valid+ && !can_query<T, always_t<I> >::value+ && !can_query<T, never_t<I> >::value+ >::type* = 0) ASIO_NOEXCEPT+ {+ return possibly_t();+ }++ template <typename E, typename T = decltype(possibly_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = possibly_t::static_query<E>();+#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR blocking_t<I> value()+ {+ return possibly_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const possibly_t&, const possibly_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const possibly_t&, const possibly_t&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const possibly_t&, const always_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const possibly_t&, const always_t<I>&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const possibly_t&, const never_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const possibly_t&, const never_t<I>&)+ {+ return true;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T possibly_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename Executor>+class adapter+{+public:+ adapter(int, const Executor& e) ASIO_NOEXCEPT+ : executor_(e)+ {+ }++ adapter(const adapter& other) ASIO_NOEXCEPT+ : executor_(other.executor_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ adapter(adapter&& other) ASIO_NOEXCEPT+ : executor_(ASIO_MOVE_CAST(Executor)(other.executor_))+ {+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ template <int I>+ static ASIO_CONSTEXPR always_t<I> query(+ blocking_t<I>) ASIO_NOEXCEPT+ {+ return always_t<I>();+ }++ template <int I>+ static ASIO_CONSTEXPR always_t<I> query(+ possibly_t<I>) ASIO_NOEXCEPT+ {+ return always_t<I>();+ }++ template <int I>+ static ASIO_CONSTEXPR always_t<I> query(+ always_t<I>) ASIO_NOEXCEPT+ {+ return always_t<I>();+ }++ template <int I>+ static ASIO_CONSTEXPR always_t<I> query(+ never_t<I>) ASIO_NOEXCEPT+ {+ return always_t<I>();+ }++ template <typename Property>+ typename enable_if<+ can_query<const Executor&, Property>::value,+ typename query_result<const Executor&, Property>::type+ >::type query(const Property& p) const+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, Property>::value))+ {+ return asio::query(executor_, p);+ }++ template <int I>+ typename enable_if<+ can_require<const Executor&, possibly_t<I> >::value,+ typename require_result<const Executor&, possibly_t<I> >::type+ >::type require(possibly_t<I>) const ASIO_NOEXCEPT+ {+ return asio::require(executor_, possibly_t<I>());+ }++ template <int I>+ typename enable_if<+ can_require<const Executor&, never_t<I> >::value,+ typename require_result<const Executor&, never_t<I> >::type+ >::type require(never_t<I>) const ASIO_NOEXCEPT+ {+ return asio::require(executor_, never_t<I>());+ }++ template <typename Property>+ typename enable_if<+ can_require<const Executor&, Property>::value,+ adapter<typename decay<+ typename require_result<const Executor&, Property>::type+ >::type>+ >::type require(const Property& p) const+ ASIO_NOEXCEPT_IF((+ is_nothrow_require<const Executor&, Property>::value))+ {+ return adapter<typename decay<+ typename require_result<const Executor&, Property>::type+ >::type>(0, asio::require(executor_, p));+ }++ template <typename Property>+ typename enable_if<+ can_prefer<const Executor&, Property>::value,+ adapter<typename decay<+ typename prefer_result<const Executor&, Property>::type+ >::type>+ >::type prefer(const Property& p) const+ ASIO_NOEXCEPT_IF((+ is_nothrow_prefer<const Executor&, Property>::value))+ {+ return adapter<typename decay<+ typename prefer_result<const Executor&, Property>::type+ >::type>(0, asio::prefer(executor_, p));+ }++ template <typename Function>+ typename enable_if<+ execution::can_execute<const Executor&, Function>::value+ >::type execute(ASIO_MOVE_ARG(Function) f) const+ {+ blocking_adaptation::blocking_execute(+ executor_, ASIO_MOVE_CAST(Function)(f));+ }++ friend bool operator==(const adapter& a, const adapter& b) ASIO_NOEXCEPT+ {+ return a.executor_ == b.executor_;+ }++ friend bool operator!=(const adapter& a, const adapter& b) ASIO_NOEXCEPT+ {+ return a.executor_ != b.executor_;+ }++private:+ Executor executor_;+};++template <int I = 0>+struct always_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);+ typedef blocking_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR always_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, always_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, always_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, always_t>::value();+ }++ template <typename E, typename T = decltype(always_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = always_t::static_query<E>();+#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR blocking_t<I> value()+ {+ return always_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const always_t&, const always_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const always_t&, const always_t&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const always_t&, const possibly_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const always_t&, const possibly_t<I>&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const always_t&, const never_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const always_t&, const never_t<I>&)+ {+ return true;+ }++ template <typename Executor>+ friend adapter<Executor> require(+ const Executor& e, const always_t&,+ typename enable_if<+ is_executor<Executor>::value+ && traits::static_require<+ const Executor&,+ blocking_adaptation::allowed_t<0>+ >::is_valid+ >::type* = 0)+ {+ return adapter<Executor>(0, e);+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T always_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <int I>+struct never_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef blocking_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR never_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, never_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, never_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, never_t>::value();+ }++ template <typename E, typename T = decltype(never_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = never_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR blocking_t<I> value()+ {+ return never_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const never_t&, const never_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const never_t&, const never_t&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const never_t&, const possibly_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const never_t&, const possibly_t<I>&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const never_t&, const always_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const never_t&, const always_t<I>&)+ {+ return true;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T never_t<I>::static_query_v;+#endif // defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++} // namespace blocking+} // namespace detail++typedef detail::blocking_t<> blocking_t;++#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr blocking_t blocking;+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+namespace { static const blocking_t& blocking = blocking_t::instance; }+#endif++} // namespace execution++#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+struct is_applicable_property<T, execution::blocking_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::blocking_t::possibly_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::blocking_t::always_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::blocking_t::never_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++template <typename T>+struct query_free_default<T, execution::blocking_t,+ typename enable_if<+ can_query<T, execution::blocking_t::possibly_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::blocking_t::possibly_t>::value));++ typedef execution::blocking_t result_type;+};++template <typename T>+struct query_free_default<T, execution::blocking_t,+ typename enable_if<+ !can_query<T, execution::blocking_t::possibly_t>::value+ && can_query<T, execution::blocking_t::always_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::blocking_t::always_t>::value));++ typedef execution::blocking_t result_type;+};++template <typename T>+struct query_free_default<T, execution::blocking_t,+ typename enable_if<+ !can_query<T, execution::blocking_t::possibly_t>::value+ && !can_query<T, execution::blocking_t::always_t>::value+ && can_query<T, execution::blocking_t::never_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::blocking_t::never_t>::value));++ typedef execution::blocking_t result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename T>+struct static_query<T, execution::blocking_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::blocking_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::blocking_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::blocking_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::blocking_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid+ && !traits::query_member<T, execution::blocking_t>::is_valid+ && traits::static_query<T, execution::blocking_t::possibly_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::blocking_t::possibly_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T, execution::blocking_t::possibly_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::blocking_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid+ && !traits::query_member<T, execution::blocking_t>::is_valid+ && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid+ && traits::static_query<T, execution::blocking_t::always_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::blocking_t::always_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T, execution::blocking_t::always_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::blocking_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid+ && !traits::query_member<T, execution::blocking_t>::is_valid+ && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid+ && !traits::static_query<T, execution::blocking_t::always_t>::is_valid+ && traits::static_query<T, execution::blocking_t::never_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::blocking_t::never_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T, execution::blocking_t::never_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::blocking_t::possibly_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::blocking_t::possibly_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::blocking_t::possibly_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::blocking_t::possibly_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::blocking_t::possibly_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::blocking_t::possibly_t>::is_valid+ && !traits::query_member<T, execution::blocking_t::possibly_t>::is_valid+ && !traits::query_free<T, execution::blocking_t::possibly_t>::is_valid+ && !can_query<T, execution::blocking_t::always_t>::value+ && !can_query<T, execution::blocking_t::never_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef execution::blocking_t::possibly_t result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return result_type();+ }+};++template <typename T>+struct static_query<T, execution::blocking_t::always_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::blocking_t::always_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::blocking_t::always_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::blocking_t::always_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::blocking_t::never_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::blocking_t::never_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::blocking_t::never_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::blocking_t::never_t>::value();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++template <typename T>+struct static_require<T, execution::blocking_t::possibly_t,+ typename enable_if<+ static_query<T, execution::blocking_t::possibly_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::blocking_t::possibly_t>::result_type,+ execution::blocking_t::possibly_t>::value));+};++template <typename T>+struct static_require<T, execution::blocking_t::always_t,+ typename enable_if<+ static_query<T, execution::blocking_t::always_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::blocking_t::always_t>::result_type,+ execution::blocking_t::always_t>::value));+};++template <typename T>+struct static_require<T, execution::blocking_t::never_t,+ typename enable_if<+ static_query<T, execution::blocking_t::never_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::blocking_t::never_t>::result_type,+ execution::blocking_t::never_t>::value));+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)++template <typename T>+struct require_free_default<T, execution::blocking_t::always_t,+ typename enable_if<+ is_same<T, typename decay<T>::type>::value+ && execution::is_executor<T>::value+ && traits::static_require<+ const T&,+ execution::detail::blocking_adaptation::allowed_t<0>+ >::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef execution::detail::blocking::adapter<T> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++template <typename Executor>+struct equality_comparable<+ execution::detail::blocking::adapter<Executor> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+};++#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++template <typename Executor, typename Function>+struct execute_member<+ execution::detail::blocking::adapter<Executor>, Function>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++template <typename Executor, int I>+struct query_static_constexpr_member<+ execution::detail::blocking::adapter<Executor>,+ execution::detail::blocking_t<I> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef execution::blocking_t::always_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return result_type();+ }+};++template <typename Executor, int I>+struct query_static_constexpr_member<+ execution::detail::blocking::adapter<Executor>,+ execution::detail::blocking::always_t<I> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef execution::blocking_t::always_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return result_type();+ }+};++template <typename Executor, int I>+struct query_static_constexpr_member<+ execution::detail::blocking::adapter<Executor>,+ execution::detail::blocking::possibly_t<I> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef execution::blocking_t::always_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return result_type();+ }+};++template <typename Executor, int I>+struct query_static_constexpr_member<+ execution::detail::blocking::adapter<Executor>,+ execution::detail::blocking::never_t<I> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef execution::blocking_t::always_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return result_type();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++template <typename Executor, typename Property>+struct query_member<+ execution::detail::blocking::adapter<Executor>, Property,+ typename enable_if<+ can_query<const Executor&, Property>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<Executor, Property>::value));+ typedef typename query_result<Executor, Property>::type result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++template <typename Executor, int I>+struct require_member<+ execution::detail::blocking::adapter<Executor>,+ execution::detail::blocking::possibly_t<I>,+ typename enable_if<+ can_require<+ const Executor&,+ execution::detail::blocking::possibly_t<I>+ >::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_require<const Executor&,+ execution::detail::blocking::possibly_t<I> >::value));+ typedef typename require_result<const Executor&,+ execution::detail::blocking::possibly_t<I> >::type result_type;+};++template <typename Executor, int I>+struct require_member<+ execution::detail::blocking::adapter<Executor>,+ execution::detail::blocking::never_t<I>,+ typename enable_if<+ can_require<+ const Executor&,+ execution::detail::blocking::never_t<I>+ >::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_require<const Executor&,+ execution::detail::blocking::never_t<I> >::value));+ typedef typename require_result<const Executor&,+ execution::detail::blocking::never_t<I> >::type result_type;+};++template <typename Executor, typename Property>+struct require_member<+ execution::detail::blocking::adapter<Executor>, Property,+ typename enable_if<+ can_require<const Executor&, Property>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_require<Executor, Property>::value));+ typedef execution::detail::blocking::adapter<typename decay<+ typename require_result<Executor, Property>::type+ >::type> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)++template <typename Executor, typename Property>+struct prefer_member<+ execution::detail::blocking::adapter<Executor>, Property,+ typename enable_if<+ can_prefer<const Executor&, Property>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_prefer<Executor, Property>::value));+ typedef execution::detail::blocking::adapter<typename decay<+ typename prefer_result<Executor, Property>::type+ >::type> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_BLOCKING_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/blocking_adaptation.hpp view
@@ -0,0 +1,1064 @@+//+// execution/blocking_adaptation.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_BLOCKING_ADAPTATION_HPP+#define ASIO_EXECUTION_BLOCKING_ADAPTATION_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/mutex.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution/execute.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/is_applicable_property.hpp"+#include "asio/prefer.hpp"+#include "asio/query.hpp"+#include "asio/require.hpp"+#include "asio/traits/prefer_member.hpp"+#include "asio/traits/query_free.hpp"+#include "asio/traits/query_member.hpp"+#include "asio/traits/query_static_constexpr_member.hpp"+#include "asio/traits/require_member.hpp"+#include "asio/traits/static_query.hpp"+#include "asio/traits/static_require.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// A property to describe whether automatic adaptation of an executor is+/// allowed in order to apply the blocking_adaptation_t::allowed_t property.+struct blocking_adaptation_t+{+ /// The blocking_adaptation_t property applies to executors, senders, and+ /// schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The top-level blocking_adaptation_t property cannot be required.+ static constexpr bool is_requirable = false;++ /// The top-level blocking_adaptation_t property cannot be preferred.+ static constexpr bool is_preferable = false;++ /// The type returned by queries against an @c any_executor.+ typedef blocking_adaptation_t polymorphic_query_result_type;++ /// A sub-property that indicates that automatic adaptation is not allowed.+ struct disallowed_t+ {+ /// The blocking_adaptation_t::disallowed_t property applies to executors,+ /// senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The blocking_adaptation_t::disallowed_t property can be required.+ static constexpr bool is_requirable = true;++ /// The blocking_adaptation_t::disallowed_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef blocking_adaptation_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr disallowed_t();++ /// Get the value associated with a property object.+ /**+ * @returns disallowed_t();+ */+ static constexpr blocking_adaptation_t value();+ };++ /// A sub-property that indicates that automatic adaptation is allowed.+ struct allowed_t+ {+ /// The blocking_adaptation_t::allowed_t property applies to executors,+ /// senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The blocking_adaptation_t::allowed_t property can be required.+ static constexpr bool is_requirable = true;++ /// The blocking_adaptation_t::allowed_t property can be preferred.+ static constexpr bool is_preferable = false;++ /// The type returned by queries against an @c any_executor.+ typedef blocking_adaptation_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr allowed_t();++ /// Get the value associated with a property object.+ /**+ * @returns allowed_t();+ */+ static constexpr blocking_adaptation_t value();+ };++ /// A special value used for accessing the blocking_adaptation_t::disallowed_t+ /// property.+ static constexpr disallowed_t disallowed;++ /// A special value used for accessing the blocking_adaptation_t::allowed_t+ /// property.+ static constexpr allowed_t allowed;++ /// Default constructor.+ constexpr blocking_adaptation_t();++ /// Construct from a sub-property value.+ constexpr blocking_adaptation_t(disallowed_t);++ /// Construct from a sub-property value.+ constexpr blocking_adaptation_t(allowed_t);++ /// Compare property values for equality.+ friend constexpr bool operator==(+ const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept;++ /// Compare property values for inequality.+ friend constexpr bool operator!=(+ const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept;+};++/// A special value used for accessing the blocking_adaptation_t property.+constexpr blocking_adaptation_t blocking_adaptation;++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {+namespace detail {+namespace blocking_adaptation {++template <int I> struct disallowed_t;+template <int I> struct allowed_t;++} // namespace blocking_adaptation++template <int I = 0>+struct blocking_adaptation_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);+ typedef blocking_adaptation_t polymorphic_query_result_type;++ typedef detail::blocking_adaptation::disallowed_t<I> disallowed_t;+ typedef detail::blocking_adaptation::allowed_t<I> allowed_t;++ ASIO_CONSTEXPR blocking_adaptation_t()+ : value_(-1)+ {+ }++ ASIO_CONSTEXPR blocking_adaptation_t(disallowed_t)+ : value_(0)+ {+ }++ ASIO_CONSTEXPR blocking_adaptation_t(allowed_t)+ : value_(1)+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<+ T, blocking_adaptation_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<+ T, blocking_adaptation_t+ >::is_noexcept))+ {+ return traits::query_static_constexpr_member<+ T, blocking_adaptation_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, disallowed_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<+ T, blocking_adaptation_t>::is_valid+ && !traits::query_member<T, blocking_adaptation_t>::is_valid+ && traits::static_query<T, disallowed_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, disallowed_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, allowed_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<+ T, blocking_adaptation_t>::is_valid+ && !traits::query_member<T, blocking_adaptation_t>::is_valid+ && !traits::static_query<T, disallowed_t>::is_valid+ && traits::static_query<T, allowed_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, allowed_t>::value();+ }++ template <typename E,+ typename T = decltype(blocking_adaptation_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = blocking_adaptation_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ friend ASIO_CONSTEXPR bool operator==(+ const blocking_adaptation_t& a, const blocking_adaptation_t& b)+ {+ return a.value_ == b.value_;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const blocking_adaptation_t& a, const blocking_adaptation_t& b)+ {+ return a.value_ != b.value_;+ }++ struct convertible_from_blocking_adaptation_t+ {+ ASIO_CONSTEXPR convertible_from_blocking_adaptation_t(+ blocking_adaptation_t)+ {+ }+ };++ template <typename Executor>+ friend ASIO_CONSTEXPR blocking_adaptation_t query(+ const Executor& ex, convertible_from_blocking_adaptation_t,+ typename enable_if<+ can_query<const Executor&, disallowed_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&,+ blocking_adaptation_t<>::disallowed_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, disallowed_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, disallowed_t());+ }++ template <typename Executor>+ friend ASIO_CONSTEXPR blocking_adaptation_t query(+ const Executor& ex, convertible_from_blocking_adaptation_t,+ typename enable_if<+ !can_query<const Executor&, disallowed_t>::value+ && can_query<const Executor&, allowed_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&,+ blocking_adaptation_t<>::allowed_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, allowed_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, allowed_t());+ }++ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(disallowed_t, disallowed);+ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(allowed_t, allowed);++#if !defined(ASIO_HAS_CONSTEXPR)+ static const blocking_adaptation_t instance;+#endif // !defined(ASIO_HAS_CONSTEXPR)++private:+ int value_;+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T blocking_adaptation_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_CONSTEXPR)+template <int I>+const blocking_adaptation_t<I> blocking_adaptation_t<I>::instance;+#endif++template <int I>+const typename blocking_adaptation_t<I>::disallowed_t+blocking_adaptation_t<I>::disallowed;++template <int I>+const typename blocking_adaptation_t<I>::allowed_t+blocking_adaptation_t<I>::allowed;++namespace blocking_adaptation {++template <int I = 0>+struct disallowed_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef blocking_adaptation_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR disallowed_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, disallowed_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, disallowed_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, disallowed_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR disallowed_t static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, disallowed_t>::is_valid+ && !traits::query_member<T, disallowed_t>::is_valid+ && !traits::query_free<T, disallowed_t>::is_valid+ && !can_query<T, allowed_t<I> >::value+ >::type* = 0) ASIO_NOEXCEPT+ {+ return disallowed_t();+ }++ template <typename E, typename T = decltype(disallowed_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = disallowed_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR blocking_adaptation_t<I> value()+ {+ return disallowed_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const disallowed_t&, const disallowed_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const disallowed_t&, const disallowed_t&)+ {+ return false;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T disallowed_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename Executor>+class adapter+{+public:+ adapter(int, const Executor& e) ASIO_NOEXCEPT+ : executor_(e)+ {+ }++ adapter(const adapter& other) ASIO_NOEXCEPT+ : executor_(other.executor_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ adapter(adapter&& other) ASIO_NOEXCEPT+ : executor_(ASIO_MOVE_CAST(Executor)(other.executor_))+ {+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ template <int I>+ static ASIO_CONSTEXPR allowed_t<I> query(+ blocking_adaptation_t<I>) ASIO_NOEXCEPT+ {+ return allowed_t<I>();+ }++ template <int I>+ static ASIO_CONSTEXPR allowed_t<I> query(+ allowed_t<I>) ASIO_NOEXCEPT+ {+ return allowed_t<I>();+ }++ template <int I>+ static ASIO_CONSTEXPR allowed_t<I> query(+ disallowed_t<I>) ASIO_NOEXCEPT+ {+ return allowed_t<I>();+ }++ template <typename Property>+ typename enable_if<+ can_query<const Executor&, Property>::value,+ typename query_result<const Executor&, Property>::type+ >::type query(const Property& p) const+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, Property>::value))+ {+ return asio::query(executor_, p);+ }++ template <int I>+ Executor require(disallowed_t<I>) const ASIO_NOEXCEPT+ {+ return executor_;+ }++ template <typename Property>+ typename enable_if<+ can_require<const Executor&, Property>::value,+ adapter<typename decay<+ typename require_result<const Executor&, Property>::type+ >::type>+ >::type require(const Property& p) const+ ASIO_NOEXCEPT_IF((+ is_nothrow_require<const Executor&, Property>::value))+ {+ return adapter<typename decay<+ typename require_result<const Executor&, Property>::type+ >::type>(0, asio::require(executor_, p));+ }++ template <typename Property>+ typename enable_if<+ can_prefer<const Executor&, Property>::value,+ adapter<typename decay<+ typename prefer_result<const Executor&, Property>::type+ >::type>+ >::type prefer(const Property& p) const+ ASIO_NOEXCEPT_IF((+ is_nothrow_prefer<const Executor&, Property>::value))+ {+ return adapter<typename decay<+ typename prefer_result<const Executor&, Property>::type+ >::type>(0, asio::prefer(executor_, p));+ }++ template <typename Function>+ typename enable_if<+ execution::can_execute<const Executor&, Function>::value+ >::type execute(ASIO_MOVE_ARG(Function) f) const+ {+ execution::execute(executor_, ASIO_MOVE_CAST(Function)(f));+ }++ friend bool operator==(const adapter& a, const adapter& b) ASIO_NOEXCEPT+ {+ return a.executor_ == b.executor_;+ }++ friend bool operator!=(const adapter& a, const adapter& b) ASIO_NOEXCEPT+ {+ return a.executor_ != b.executor_;+ }++private:+ Executor executor_;+};++template <int I = 0>+struct allowed_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);+ typedef blocking_adaptation_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR allowed_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, allowed_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, allowed_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, allowed_t>::value();+ }++ template <typename E, typename T = decltype(allowed_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = allowed_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR blocking_adaptation_t<I> value()+ {+ return allowed_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const allowed_t&, const allowed_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const allowed_t&, const allowed_t&)+ {+ return false;+ }++ template <typename Executor>+ friend adapter<Executor> require(+ const Executor& e, const allowed_t&,+ typename enable_if<+ is_executor<Executor>::value+ >::type* = 0)+ {+ return adapter<Executor>(0, e);+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T allowed_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename Function>+class blocking_execute_state+{+public:+ template <typename F>+ blocking_execute_state(ASIO_MOVE_ARG(F) f)+ : func_(ASIO_MOVE_CAST(F)(f)),+ is_complete_(false)+ {+ }++ template <typename Executor>+ void execute_and_wait(ASIO_MOVE_ARG(Executor) ex)+ {+ handler h = { this };+ execution::execute(ASIO_MOVE_CAST(Executor)(ex), h);+ asio::detail::mutex::scoped_lock lock(mutex_);+ while (!is_complete_)+ event_.wait(lock);+ }++ struct cleanup+ {+ ~cleanup()+ {+ asio::detail::mutex::scoped_lock lock(state_->mutex_);+ state_->is_complete_ = true;+ state_->event_.unlock_and_signal_one_for_destruction(lock);+ }++ blocking_execute_state* state_;+ };++ struct handler+ {+ void operator()()+ {+ cleanup c = { state_ };+ state_->func_();+ }++ blocking_execute_state* state_;+ };++ Function func_;+ asio::detail::mutex mutex_;+ asio::detail::event event_;+ bool is_complete_;+};++template <typename Executor, typename Function>+void blocking_execute(+ ASIO_MOVE_ARG(Executor) ex,+ ASIO_MOVE_ARG(Function) func)+{+ typedef typename decay<Function>::type func_t;+ blocking_execute_state<func_t> state(ASIO_MOVE_CAST(Function)(func));+ state.execute_and_wait(ex);+}++} // namespace blocking_adaptation+} // namespace detail++typedef detail::blocking_adaptation_t<> blocking_adaptation_t;++#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr blocking_adaptation_t blocking_adaptation;+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+namespace { static const blocking_adaptation_t&+ blocking_adaptation = blocking_adaptation_t::instance; }+#endif++} // namespace execution++#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+struct is_applicable_property<T, execution::blocking_adaptation_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::blocking_adaptation_t::disallowed_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::blocking_adaptation_t::allowed_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++template <typename T>+struct query_free_default<T, execution::blocking_adaptation_t,+ typename enable_if<+ can_query<T, execution::blocking_adaptation_t::disallowed_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T,+ execution::blocking_adaptation_t::disallowed_t>::value));++ typedef execution::blocking_adaptation_t result_type;+};++template <typename T>+struct query_free_default<T, execution::blocking_adaptation_t,+ typename enable_if<+ !can_query<T, execution::blocking_adaptation_t::disallowed_t>::value+ && can_query<T, execution::blocking_adaptation_t::allowed_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::blocking_adaptation_t::allowed_t>::value));++ typedef execution::blocking_adaptation_t result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename T>+struct static_query<T, execution::blocking_adaptation_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::blocking_adaptation_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t>::is_valid+ && !traits::query_member<T,+ execution::blocking_adaptation_t>::is_valid+ && traits::static_query<T,+ execution::blocking_adaptation_t::disallowed_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::blocking_adaptation_t::disallowed_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T,+ execution::blocking_adaptation_t::disallowed_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::blocking_adaptation_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t>::is_valid+ && !traits::query_member<T,+ execution::blocking_adaptation_t>::is_valid+ && !traits::static_query<T,+ execution::blocking_adaptation_t::disallowed_t>::is_valid+ && traits::static_query<T,+ execution::blocking_adaptation_t::allowed_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::blocking_adaptation_t::allowed_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T,+ execution::blocking_adaptation_t::allowed_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::blocking_adaptation_t::disallowed_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t::disallowed_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t::disallowed_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t::disallowed_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::blocking_adaptation_t::disallowed_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t::disallowed_t>::is_valid+ && !traits::query_member<T,+ execution::blocking_adaptation_t::disallowed_t>::is_valid+ && !traits::query_free<T,+ execution::blocking_adaptation_t::disallowed_t>::is_valid+ && !can_query<T, execution::blocking_adaptation_t::allowed_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef execution::blocking_adaptation_t::disallowed_t result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return result_type();+ }+};++template <typename T>+struct static_query<T, execution::blocking_adaptation_t::allowed_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t::allowed_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t::allowed_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::blocking_adaptation_t::allowed_t>::value();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++template <typename T>+struct static_require<T, execution::blocking_adaptation_t::disallowed_t,+ typename enable_if<+ static_query<T, execution::blocking_adaptation_t::disallowed_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::blocking_adaptation_t::disallowed_t>::result_type,+ execution::blocking_adaptation_t::disallowed_t>::value));+};++template <typename T>+struct static_require<T, execution::blocking_adaptation_t::allowed_t,+ typename enable_if<+ static_query<T, execution::blocking_adaptation_t::allowed_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::blocking_adaptation_t::allowed_t>::result_type,+ execution::blocking_adaptation_t::allowed_t>::value));+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)++template <typename T>+struct require_free_default<T, execution::blocking_adaptation_t::allowed_t,+ typename enable_if<+ is_same<T, typename decay<T>::type>::value+ && execution::is_executor<T>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef execution::detail::blocking_adaptation::adapter<T> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++template <typename Executor>+struct equality_comparable<+ execution::detail::blocking_adaptation::adapter<Executor> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+};++#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++template <typename Executor, typename Function>+struct execute_member<+ execution::detail::blocking_adaptation::adapter<Executor>, Function>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++template <typename Executor, int I>+struct query_static_constexpr_member<+ execution::detail::blocking_adaptation::adapter<Executor>,+ execution::detail::blocking_adaptation_t<I> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef execution::blocking_adaptation_t::allowed_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return result_type();+ }+};++template <typename Executor, int I>+struct query_static_constexpr_member<+ execution::detail::blocking_adaptation::adapter<Executor>,+ execution::detail::blocking_adaptation::allowed_t<I> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef execution::blocking_adaptation_t::allowed_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return result_type();+ }+};++template <typename Executor, int I>+struct query_static_constexpr_member<+ execution::detail::blocking_adaptation::adapter<Executor>,+ execution::detail::blocking_adaptation::disallowed_t<I> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef execution::blocking_adaptation_t::allowed_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return result_type();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++template <typename Executor, typename Property>+struct query_member<+ execution::detail::blocking_adaptation::adapter<Executor>, Property,+ typename enable_if<+ can_query<const Executor&, Property>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<Executor, Property>::value));+ typedef typename query_result<Executor, Property>::type result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++template <typename Executor, int I>+struct require_member<+ execution::detail::blocking_adaptation::adapter<Executor>,+ execution::detail::blocking_adaptation::disallowed_t<I> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef Executor result_type;+};++template <typename Executor, typename Property>+struct require_member<+ execution::detail::blocking_adaptation::adapter<Executor>, Property,+ typename enable_if<+ can_require<const Executor&, Property>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_require<Executor, Property>::value));+ typedef execution::detail::blocking_adaptation::adapter<typename decay<+ typename require_result<Executor, Property>::type+ >::type> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)++template <typename Executor, typename Property>+struct prefer_member<+ execution::detail::blocking_adaptation::adapter<Executor>, Property,+ typename enable_if<+ can_prefer<const Executor&, Property>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_prefer<Executor, Property>::value));+ typedef execution::detail::blocking_adaptation::adapter<typename decay<+ typename prefer_result<Executor, Property>::type+ >::type> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/bulk_execute.hpp view
@@ -0,0 +1,390 @@+//+// execution/bulk_execute.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_BULK_EXECUTE_HPP+#define ASIO_EXECUTION_BULK_EXECUTE_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/bulk_guarantee.hpp"+#include "asio/execution/detail/bulk_sender.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution/sender.hpp"+#include "asio/traits/bulk_execute_member.hpp"+#include "asio/traits/bulk_execute_free.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {+namespace execution {++/// A customisation point that creates a bulk sender.+/**+ * The name <tt>execution::bulk_execute</tt> denotes a customisation point+ * object. If <tt>is_convertible_v<N, size_t></tt> is true, then the expression+ * <tt>execution::bulk_execute(S, F, N)</tt> for some subexpressions+ * <tt>S</tt>, <tt>F</tt>, and <tt>N</tt> is expression-equivalent to:+ *+ * @li <tt>S.bulk_execute(F, N)</tt>, if that expression is valid. If the+ * function selected does not execute <tt>N</tt> invocations of the function+ * object <tt>F</tt> on the executor <tt>S</tt> in bulk with forward progress+ * guarantee <tt>asio::query(S, execution::bulk_guarantee)</tt>, and+ * the result of that function does not model <tt>sender<void></tt>, the+ * program is ill-formed with no diagnostic required.+ *+ * @li Otherwise, <tt>bulk_execute(S, F, N)</tt>, if that expression is valid,+ * with overload resolution performed in a context that includes the+ * declaration <tt>void bulk_execute();</tt> and that does not include a+ * declaration of <tt>execution::bulk_execute</tt>. If the function selected+ * by overload resolution does not execute <tt>N</tt> invocations of the+ * function object <tt>F</tt> on the executor <tt>S</tt> in bulk with forward+ * progress guarantee <tt>asio::query(E,+ * execution::bulk_guarantee)</tt>, and the result of that function does not+ * model <tt>sender<void></tt>, the program is ill-formed with no diagnostic+ * required.+ *+ * @li Otherwise, if the types <tt>F</tt> and+ * <tt>executor_index_t<remove_cvref_t<S>></tt> model <tt>invocable</tt> and+ * if <tt>asio::query(S, execution::bulk_guarantee)</tt> equals+ * <tt>execution::bulk_guarantee.unsequenced</tt>, then+ *+ * - Evaluates <tt>DECAY_COPY(std::forward<decltype(F)>(F))</tt> on the+ * calling thread to create a function object <tt>cf</tt>. [Note:+ * Additional copies of <tt>cf</tt> may subsequently be created. --end+ * note.]+ *+ * - For each value of <tt>i</tt> in <tt>N</tt>, <tt>cf(i)</tt> (or copy of+ * <tt>cf</tt>)) will be invoked at most once by an execution agent that is+ * unique for each value of <tt>i</tt>.+ *+ * - May block pending completion of one or more invocations of <tt>cf</tt>.+ *+ * - Synchronizes with (C++Std [intro.multithread]) the invocations of+ * <tt>cf</tt>.+ *+ * @li Otherwise, <tt>execution::bulk_execute(S, F, N)</tt> is ill-formed.+ */+inline constexpr unspecified bulk_execute = unspecified;++/// A type trait that determines whether a @c bulk_execute expression is+/// well-formed.+/**+ * Class template @c can_bulk_execute is a trait that is derived from @c+ * true_type if the expression <tt>execution::bulk_execute(std::declval<S>(),+ * std::declval<F>(), std::declval<N>)</tt> is well formed; otherwise @c+ * false_type.+ */+template <typename S, typename F, typename N>+struct can_bulk_execute :+ integral_constant<bool, automatically_determined>+{+};++} // namespace execution+} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_execution_bulk_execute_fn {++using asio::declval;+using asio::enable_if;+using asio::execution::bulk_guarantee_t;+using asio::execution::detail::bulk_sender;+using asio::execution::executor_index;+using asio::execution::is_sender;+using asio::is_convertible;+using asio::is_same;+using asio::remove_cvref;+using asio::result_of;+using asio::traits::bulk_execute_free;+using asio::traits::bulk_execute_member;+using asio::traits::static_require;++void bulk_execute();++enum overload_type+{+ call_member,+ call_free,+ adapter,+ ill_formed+};++template <typename S, typename Args, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename S, typename F, typename N>+struct call_traits<S, void(F, N),+ typename enable_if<+ (+ is_convertible<N, std::size_t>::value+ &&+ bulk_execute_member<S, F, N>::is_valid+ &&+ is_sender<+ typename bulk_execute_member<S, F, N>::result_type+ >::value+ )+ >::type> :+ bulk_execute_member<S, F, N>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename S, typename F, typename N>+struct call_traits<S, void(F, N),+ typename enable_if<+ (+ is_convertible<N, std::size_t>::value+ &&+ !bulk_execute_member<S, F, N>::is_valid+ &&+ bulk_execute_free<S, F, N>::is_valid+ &&+ is_sender<+ typename bulk_execute_free<S, F, N>::result_type+ >::value+ )+ >::type> :+ bulk_execute_free<S, F, N>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++template <typename S, typename F, typename N>+struct call_traits<S, void(F, N),+ typename enable_if<+ (+ is_convertible<N, std::size_t>::value+ &&+ !bulk_execute_member<S, F, N>::is_valid+ &&+ !bulk_execute_free<S, F, N>::is_valid+ &&+ is_sender<S>::value+ &&+ is_same<+ typename result_of<+ F(typename executor_index<typename remove_cvref<S>::type>::type)+ >::type,+ typename result_of<+ F(typename executor_index<typename remove_cvref<S>::type>::type)+ >::type+ >::value+ &&+ static_require<S, bulk_guarantee_t::unsequenced_t>::is_valid+ )+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef bulk_sender<S, F, N> result_type;+};++struct impl+{+#if defined(ASIO_HAS_MOVE)+ template <typename S, typename F, typename N>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(F, N)>::overload == call_member,+ typename call_traits<S, void(F, N)>::result_type+ >::type+ operator()(S&& s, F&& f, N&& n) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(F, N)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(S)(s).bulk_execute(+ ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));+ }++ template <typename S, typename F, typename N>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(F, N)>::overload == call_free,+ typename call_traits<S, void(F, N)>::result_type+ >::type+ operator()(S&& s, F&& f, N&& n) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(F, N)>::is_noexcept))+ {+ return bulk_execute(ASIO_MOVE_CAST(S)(s),+ ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));+ }++ template <typename S, typename F, typename N>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(F, N)>::overload == adapter,+ typename call_traits<S, void(F, N)>::result_type+ >::type+ operator()(S&& s, F&& f, N&& n) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(F, N)>::is_noexcept))+ {+ return typename call_traits<S, void(F, N)>::result_type(+ ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(F)(f),+ ASIO_MOVE_CAST(N)(n));+ }+#else // defined(ASIO_HAS_MOVE)+ template <typename S, typename F, typename N>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(const F&, const N&)>::overload == call_member,+ typename call_traits<S, void(const F&, const N&)>::result_type+ >::type+ operator()(S& s, const F& f, const N& n) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(const F&, const N&)>::is_noexcept))+ {+ return s.bulk_execute(ASIO_MOVE_CAST(F)(f),+ ASIO_MOVE_CAST(N)(n));+ }++ template <typename S, typename F, typename N>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(const F&, const N&)>::overload == call_member,+ typename call_traits<S, void(const F&, const N&)>::result_type+ >::type+ operator()(const S& s, const F& f, const N& n) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(const F&, const N&)>::is_noexcept))+ {+ return s.bulk_execute(ASIO_MOVE_CAST(F)(f),+ ASIO_MOVE_CAST(N)(n));+ }++ template <typename S, typename F, typename N>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(const F&, const N&)>::overload == call_free,+ typename call_traits<S, void(const F&, const N&)>::result_type+ >::type+ operator()(S& s, const F& f, const N& n) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(const F&, const N&)>::is_noexcept))+ {+ return bulk_execute(s, ASIO_MOVE_CAST(F)(f),+ ASIO_MOVE_CAST(N)(n));+ }++ template <typename S, typename F, typename N>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(const F&, const N&)>::overload == call_free,+ typename call_traits<S, void(const F&, const N&)>::result_type+ >::type+ operator()(const S& s, const F& f, const N& n) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(const F&, const N&)>::is_noexcept))+ {+ return bulk_execute(s, ASIO_MOVE_CAST(F)(f),+ ASIO_MOVE_CAST(N)(n));+ }++ template <typename S, typename F, typename N>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(const F&, const N&)>::overload == adapter,+ typename call_traits<S, void(const F&, const N&)>::result_type+ >::type+ operator()(S& s, const F& f, const N& n) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(const F&, const N&)>::is_noexcept))+ {+ return typename call_traits<S, void(const F&, const N&)>::result_type(+ s, ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));+ }++ template <typename S, typename F, typename N>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(const F&, const N&)>::overload == adapter,+ typename call_traits<S, void(const F&, const N&)>::result_type+ >::type+ operator()(const S& s, const F& f, const N& n) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(const F&, const N&)>::is_noexcept))+ {+ return typename call_traits<S, void(const F&, const N&)>::result_type(+ s, ASIO_MOVE_CAST(F)(f), ASIO_MOVE_CAST(N)(n));+ }+#endif // defined(ASIO_HAS_MOVE)+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_execution_bulk_execute_fn+namespace asio {+namespace execution {+namespace {++static ASIO_CONSTEXPR+ const asio_execution_bulk_execute_fn::impl& bulk_execute =+ asio_execution_bulk_execute_fn::static_instance<>::instance;++} // namespace++template <typename S, typename F, typename N>+struct can_bulk_execute :+ integral_constant<bool,+ asio_execution_bulk_execute_fn::call_traits<S, void(F, N)>::overload !=+ asio_execution_bulk_execute_fn::ill_formed>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename F, typename N>+constexpr bool can_bulk_execute_v = can_bulk_execute<S, F, N>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename F, typename N>+struct is_nothrow_bulk_execute :+ integral_constant<bool,+ asio_execution_bulk_execute_fn::call_traits<S, void(F, N)>::is_noexcept>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename F, typename N>+constexpr bool is_nothrow_bulk_execute_v+ = is_nothrow_bulk_execute<S, F, N>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename F, typename N>+struct bulk_execute_result+{+ typedef typename asio_execution_bulk_execute_fn::call_traits<+ S, void(F, N)>::result_type type;+};++} // namespace execution+} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_BULK_EXECUTE_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/bulk_guarantee.hpp view
@@ -0,0 +1,1018 @@+//+// execution/bulk_guarantee.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_BULK_GUARANTEE_HPP+#define ASIO_EXECUTION_BULK_GUARANTEE_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/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/is_applicable_property.hpp"+#include "asio/query.hpp"+#include "asio/traits/query_free.hpp"+#include "asio/traits/query_member.hpp"+#include "asio/traits/query_static_constexpr_member.hpp"+#include "asio/traits/static_query.hpp"+#include "asio/traits/static_require.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// A property to communicate the forward progress and ordering guarantees of+/// execution agents associated with the bulk execution.+struct bulk_guarantee_t+{+ /// The bulk_guarantee_t property applies to executors, senders, and+ /// schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The top-level bulk_guarantee_t property cannot be required.+ static constexpr bool is_requirable = false;++ /// The top-level bulk_guarantee_t property cannot be preferred.+ static constexpr bool is_preferable = false;++ /// The type returned by queries against an @c any_executor.+ typedef bulk_guarantee_t polymorphic_query_result_type;++ /// A sub-property that indicates that execution agents within the same bulk+ /// execution may be parallelised and vectorised.+ struct unsequenced_t+ {+ /// The bulk_guarantee_t::unsequenced_t property applies to executors,+ /// senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The bulk_guarantee_t::unsequenced_t property can be required.+ static constexpr bool is_requirable = true;++ /// The bulk_guarantee_t::unsequenced_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef bulk_guarantee_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr unsequenced_t();++ /// Get the value associated with a property object.+ /**+ * @returns unsequenced_t();+ */+ static constexpr bulk_guarantee_t value();+ };++ /// A sub-property that indicates that execution agents within the same bulk+ /// execution may not be parallelised and vectorised.+ struct sequenced_t+ {+ /// The bulk_guarantee_t::sequenced_t property applies to executors,+ /// senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The bulk_guarantee_t::sequenced_t property can be required.+ static constexpr bool is_requirable = true;++ /// The bulk_guarantee_t::sequenced_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef bulk_guarantee_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr sequenced_t();++ /// Get the value associated with a property object.+ /**+ * @returns sequenced_t();+ */+ static constexpr bulk_guarantee_t value();+ };++ /// A sub-property that indicates that execution agents within the same bulk+ /// execution may be parallelised.+ struct parallel_t+ {+ /// The bulk_guarantee_t::parallel_t property applies to executors,+ /// senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The bulk_guarantee_t::parallel_t property can be required.+ static constexpr bool is_requirable = true;++ /// The bulk_guarantee_t::parallel_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef bulk_guarantee_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr parallel_t();++ /// Get the value associated with a property object.+ /**+ * @returns parallel_t();+ */+ static constexpr bulk_guarantee_t value();+ };++ /// A special value used for accessing the bulk_guarantee_t::unsequenced_t+ /// property.+ static constexpr unsequenced_t unsequenced;++ /// A special value used for accessing the bulk_guarantee_t::sequenced_t+ /// property.+ static constexpr sequenced_t sequenced;++ /// A special value used for accessing the bulk_guarantee_t::parallel_t+ /// property.+ static constexpr parallel_t parallel;++ /// Default constructor.+ constexpr bulk_guarantee_t();++ /// Construct from a sub-property value.+ constexpr bulk_guarantee_t(unsequenced_t);++ /// Construct from a sub-property value.+ constexpr bulk_guarantee_t(sequenced_t);++ /// Construct from a sub-property value.+ constexpr bulk_guarantee_t(parallel_t);++ /// Compare property values for equality.+ friend constexpr bool operator==(+ const bulk_guarantee_t& a, const bulk_guarantee_t& b) noexcept;++ /// Compare property values for inequality.+ friend constexpr bool operator!=(+ const bulk_guarantee_t& a, const bulk_guarantee_t& b) noexcept;+};++/// A special value used for accessing the bulk_guarantee_t property.+constexpr bulk_guarantee_t bulk_guarantee;++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {+namespace detail {+namespace bulk_guarantee {++template <int I> struct unsequenced_t;+template <int I> struct sequenced_t;+template <int I> struct parallel_t;++} // namespace bulk_guarantee++template <int I = 0>+struct bulk_guarantee_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);+ typedef bulk_guarantee_t polymorphic_query_result_type;++ typedef detail::bulk_guarantee::unsequenced_t<I> unsequenced_t;+ typedef detail::bulk_guarantee::sequenced_t<I> sequenced_t;+ typedef detail::bulk_guarantee::parallel_t<I> parallel_t;++ ASIO_CONSTEXPR bulk_guarantee_t()+ : value_(-1)+ {+ }++ ASIO_CONSTEXPR bulk_guarantee_t(unsequenced_t)+ : value_(0)+ {+ }++ ASIO_CONSTEXPR bulk_guarantee_t(sequenced_t)+ : value_(1)+ {+ }++ ASIO_CONSTEXPR bulk_guarantee_t(parallel_t)+ : value_(2)+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<+ T, bulk_guarantee_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, bulk_guarantee_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, unsequenced_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_valid+ && !traits::query_member<T, bulk_guarantee_t>::is_valid+ && traits::static_query<T, unsequenced_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, unsequenced_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, sequenced_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_valid+ && !traits::query_member<T, bulk_guarantee_t>::is_valid+ && !traits::static_query<T, unsequenced_t>::is_valid+ && traits::static_query<T, sequenced_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, sequenced_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, parallel_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_valid+ && !traits::query_member<T, bulk_guarantee_t>::is_valid+ && !traits::static_query<T, unsequenced_t>::is_valid+ && !traits::static_query<T, sequenced_t>::is_valid+ && traits::static_query<T, parallel_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, parallel_t>::value();+ }++ template <typename E,+ typename T = decltype(bulk_guarantee_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = bulk_guarantee_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ friend ASIO_CONSTEXPR bool operator==(+ const bulk_guarantee_t& a, const bulk_guarantee_t& b)+ {+ return a.value_ == b.value_;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const bulk_guarantee_t& a, const bulk_guarantee_t& b)+ {+ return a.value_ != b.value_;+ }++ struct convertible_from_bulk_guarantee_t+ {+ ASIO_CONSTEXPR convertible_from_bulk_guarantee_t(bulk_guarantee_t) {}+ };++ template <typename Executor>+ friend ASIO_CONSTEXPR bulk_guarantee_t query(+ const Executor& ex, convertible_from_bulk_guarantee_t,+ typename enable_if<+ can_query<const Executor&, unsequenced_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&,+ bulk_guarantee_t<>::unsequenced_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, unsequenced_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, unsequenced_t());+ }++ template <typename Executor>+ friend ASIO_CONSTEXPR bulk_guarantee_t query(+ const Executor& ex, convertible_from_bulk_guarantee_t,+ typename enable_if<+ !can_query<const Executor&, unsequenced_t>::value+ && can_query<const Executor&, sequenced_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&,+ bulk_guarantee_t<>::sequenced_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, sequenced_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, sequenced_t());+ }++ template <typename Executor>+ friend ASIO_CONSTEXPR bulk_guarantee_t query(+ const Executor& ex, convertible_from_bulk_guarantee_t,+ typename enable_if<+ !can_query<const Executor&, unsequenced_t>::value+ && !can_query<const Executor&, sequenced_t>::value+ && can_query<const Executor&, parallel_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, bulk_guarantee_t<>::parallel_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, parallel_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, parallel_t());+ }++ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(unsequenced_t, unsequenced);+ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(sequenced_t, sequenced);+ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(parallel_t, parallel);++#if !defined(ASIO_HAS_CONSTEXPR)+ static const bulk_guarantee_t instance;+#endif // !defined(ASIO_HAS_CONSTEXPR)++private:+ int value_;+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T bulk_guarantee_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_CONSTEXPR)+template <int I>+const bulk_guarantee_t<I> bulk_guarantee_t<I>::instance;+#endif++template <int I>+const typename bulk_guarantee_t<I>::unsequenced_t+bulk_guarantee_t<I>::unsequenced;++template <int I>+const typename bulk_guarantee_t<I>::sequenced_t+bulk_guarantee_t<I>::sequenced;++template <int I>+const typename bulk_guarantee_t<I>::parallel_t+bulk_guarantee_t<I>::parallel;++namespace bulk_guarantee {++template <int I = 0>+struct unsequenced_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef bulk_guarantee_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR unsequenced_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, unsequenced_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, unsequenced_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, unsequenced_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR unsequenced_t static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, unsequenced_t>::is_valid+ && !traits::query_member<T, unsequenced_t>::is_valid+ && !traits::query_free<T, unsequenced_t>::is_valid+ && !can_query<T, sequenced_t<I> >::value+ && !can_query<T, parallel_t<I> >::value+ >::type* = 0) ASIO_NOEXCEPT+ {+ return unsequenced_t();+ }++ template <typename E, typename T = decltype(unsequenced_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = unsequenced_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR bulk_guarantee_t<I> value()+ {+ return unsequenced_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const unsequenced_t&, const unsequenced_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const unsequenced_t&, const unsequenced_t&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const unsequenced_t&, const sequenced_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const unsequenced_t&, const sequenced_t<I>&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const unsequenced_t&, const parallel_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const unsequenced_t&, const parallel_t<I>&)+ {+ return true;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T unsequenced_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <int I = 0>+struct sequenced_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef bulk_guarantee_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR sequenced_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, sequenced_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, sequenced_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, sequenced_t>::value();+ }++ template <typename E, typename T = decltype(sequenced_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = sequenced_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR bulk_guarantee_t<I> value()+ {+ return sequenced_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const sequenced_t&, const sequenced_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const sequenced_t&, const sequenced_t&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const sequenced_t&, const unsequenced_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const sequenced_t&, const unsequenced_t<I>&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const sequenced_t&, const parallel_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const sequenced_t&, const parallel_t<I>&)+ {+ return true;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T sequenced_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <int I>+struct parallel_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef bulk_guarantee_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR parallel_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, parallel_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, parallel_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, parallel_t>::value();+ }++ template <typename E, typename T = decltype(parallel_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = parallel_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR bulk_guarantee_t<I> value()+ {+ return parallel_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const parallel_t&, const parallel_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const parallel_t&, const parallel_t&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const parallel_t&, const unsequenced_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const parallel_t&, const unsequenced_t<I>&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator==(+ const parallel_t&, const sequenced_t<I>&)+ {+ return false;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const parallel_t&, const sequenced_t<I>&)+ {+ return true;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T parallel_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++} // namespace bulk_guarantee+} // namespace detail++typedef detail::bulk_guarantee_t<> bulk_guarantee_t;++#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr bulk_guarantee_t bulk_guarantee;+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+namespace { static const bulk_guarantee_t&+ bulk_guarantee = bulk_guarantee_t::instance; }+#endif++} // namespace execution++#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+struct is_applicable_property<T, execution::bulk_guarantee_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::bulk_guarantee_t::unsequenced_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::bulk_guarantee_t::sequenced_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::bulk_guarantee_t::parallel_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++template <typename T>+struct query_free_default<T, execution::bulk_guarantee_t,+ typename enable_if<+ can_query<T, execution::bulk_guarantee_t::unsequenced_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::bulk_guarantee_t::unsequenced_t>::value));++ typedef execution::bulk_guarantee_t result_type;+};++template <typename T>+struct query_free_default<T, execution::bulk_guarantee_t,+ typename enable_if<+ !can_query<T, execution::bulk_guarantee_t::unsequenced_t>::value+ && can_query<T, execution::bulk_guarantee_t::sequenced_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::bulk_guarantee_t::sequenced_t>::value));++ typedef execution::bulk_guarantee_t result_type;+};++template <typename T>+struct query_free_default<T, execution::bulk_guarantee_t,+ typename enable_if<+ !can_query<T, execution::bulk_guarantee_t::unsequenced_t>::value+ && !can_query<T, execution::bulk_guarantee_t::sequenced_t>::value+ && can_query<T, execution::bulk_guarantee_t::parallel_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::bulk_guarantee_t::parallel_t>::value));++ typedef execution::bulk_guarantee_t result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename T>+struct static_query<T, execution::bulk_guarantee_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::bulk_guarantee_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t>::is_valid+ && !traits::query_member<T,+ execution::bulk_guarantee_t>::is_valid+ && traits::static_query<T,+ execution::bulk_guarantee_t::unsequenced_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::bulk_guarantee_t::unsequenced_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T,+ execution::bulk_guarantee_t::unsequenced_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::bulk_guarantee_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t>::is_valid+ && !traits::query_member<T,+ execution::bulk_guarantee_t>::is_valid+ && !traits::static_query<T,+ execution::bulk_guarantee_t::unsequenced_t>::is_valid+ && traits::static_query<T,+ execution::bulk_guarantee_t::sequenced_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::bulk_guarantee_t::sequenced_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T,+ execution::bulk_guarantee_t::sequenced_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::bulk_guarantee_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t>::is_valid+ && !traits::query_member<T,+ execution::bulk_guarantee_t>::is_valid+ && !traits::static_query<T,+ execution::bulk_guarantee_t::unsequenced_t>::is_valid+ && !traits::static_query<T,+ execution::bulk_guarantee_t::sequenced_t>::is_valid+ && traits::static_query<T,+ execution::bulk_guarantee_t::parallel_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::bulk_guarantee_t::parallel_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T,+ execution::bulk_guarantee_t::parallel_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::bulk_guarantee_t::unsequenced_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t::unsequenced_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t::unsequenced_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t::unsequenced_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::bulk_guarantee_t::unsequenced_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t::unsequenced_t>::is_valid+ && !traits::query_member<T,+ execution::bulk_guarantee_t::unsequenced_t>::is_valid+ && !traits::query_free<T,+ execution::bulk_guarantee_t::unsequenced_t>::is_valid+ && !can_query<T, execution::bulk_guarantee_t::sequenced_t>::value+ && !can_query<T, execution::bulk_guarantee_t::parallel_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef execution::bulk_guarantee_t::unsequenced_t result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return result_type();+ }+};++template <typename T>+struct static_query<T, execution::bulk_guarantee_t::sequenced_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t::sequenced_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t::sequenced_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t::sequenced_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::bulk_guarantee_t::parallel_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t::parallel_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t::parallel_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::bulk_guarantee_t::parallel_t>::value();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++template <typename T>+struct static_require<T, execution::bulk_guarantee_t::unsequenced_t,+ typename enable_if<+ static_query<T, execution::bulk_guarantee_t::unsequenced_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::bulk_guarantee_t::unsequenced_t>::result_type,+ execution::bulk_guarantee_t::unsequenced_t>::value));+};++template <typename T>+struct static_require<T, execution::bulk_guarantee_t::sequenced_t,+ typename enable_if<+ static_query<T, execution::bulk_guarantee_t::sequenced_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::bulk_guarantee_t::sequenced_t>::result_type,+ execution::bulk_guarantee_t::sequenced_t>::value));+};++template <typename T>+struct static_require<T, execution::bulk_guarantee_t::parallel_t,+ typename enable_if<+ static_query<T, execution::bulk_guarantee_t::parallel_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::bulk_guarantee_t::parallel_t>::result_type,+ execution::bulk_guarantee_t::parallel_t>::value));+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_BULK_GUARANTEE_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/connect.hpp view
@@ -0,0 +1,486 @@+//+// execution/connect.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_CONNECT_HPP+#define ASIO_EXECUTION_CONNECT_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/detail/as_invocable.hpp"+#include "asio/execution/detail/as_operation.hpp"+#include "asio/execution/detail/as_receiver.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution/operation_state.hpp"+#include "asio/execution/receiver.hpp"+#include "asio/execution/sender.hpp"+#include "asio/traits/connect_member.hpp"+#include "asio/traits/connect_free.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {+namespace execution {++/// A customisation point that connects a sender to a receiver.+/**+ * The name <tt>execution::connect</tt> denotes a customisation point object.+ * For some subexpressions <tt>s</tt> and <tt>r</tt>, let <tt>S</tt> be a type+ * such that <tt>decltype((s))</tt> is <tt>S</tt> and let <tt>R</tt> be a type+ * such that <tt>decltype((r))</tt> is <tt>R</tt>. The expression+ * <tt>execution::connect(s, r)</tt> is expression-equivalent to:+ *+ * @li <tt>s.connect(r)</tt>, if that expression is valid, if its type+ * satisfies <tt>operation_state</tt>, and if <tt>S</tt> satisfies+ * <tt>sender</tt>.+ *+ * @li Otherwise, <tt>connect(s, r)</tt>, if that expression is valid, if its+ * type satisfies <tt>operation_state</tt>, and if <tt>S</tt> satisfies+ * <tt>sender</tt>, with overload resolution performed in a context that+ * includes the declaration <tt>void connect();</tt> and that does not include+ * a declaration of <tt>execution::connect</tt>.+ *+ * @li Otherwise, <tt>as_operation{s, r}</tt>, if <tt>r</tt> is not an instance+ * of <tt>as_receiver<F, S></tt> for some type <tt>F</tt>, and if+ * <tt>receiver_of<R> && executor_of<remove_cvref_t<S>,+ * as_invocable<remove_cvref_t<R>, S>></tt> is <tt>true</tt>, where+ * <tt>as_operation</tt> is an implementation-defined class equivalent to+ * @code template <class S, class R>+ * struct as_operation+ * {+ * remove_cvref_t<S> e_;+ * remove_cvref_t<R> r_;+ * void start() noexcept try {+ * execution::execute(std::move(e_),+ * as_invocable<remove_cvref_t<R>, S>{r_});+ * } catch(...) {+ * execution::set_error(std::move(r_), current_exception());+ * }+ * }; @endcode+ * and <tt>as_invocable</tt> is a class template equivalent to the following:+ * @code template<class R>+ * struct as_invocable+ * {+ * R* r_;+ * explicit as_invocable(R& r) noexcept+ * : r_(std::addressof(r)) {}+ * as_invocable(as_invocable && other) noexcept+ * : r_(std::exchange(other.r_, nullptr)) {}+ * ~as_invocable() {+ * if(r_)+ * execution::set_done(std::move(*r_));+ * }+ * void operator()() & noexcept try {+ * execution::set_value(std::move(*r_));+ * r_ = nullptr;+ * } catch(...) {+ * execution::set_error(std::move(*r_), current_exception());+ * r_ = nullptr;+ * }+ * };+ * @endcode+ *+ * @li Otherwise, <tt>execution::connect(s, r)</tt> is ill-formed.+ */+inline constexpr unspecified connect = unspecified;++/// A type trait that determines whether a @c connect expression is+/// well-formed.+/**+ * Class template @c can_connect is a trait that is derived from+ * @c true_type if the expression <tt>execution::connect(std::declval<S>(),+ * std::declval<R>())</tt> is well formed; otherwise @c false_type.+ */+template <typename S, typename R>+struct can_connect :+ integral_constant<bool, automatically_determined>+{+};++/// A type trait to determine the result of a @c connect expression.+template <typename S, typename R>+struct connect_result+{+ /// The type of the connect expression.+ /**+ * The type of the expression <tt>execution::connect(std::declval<S>(),+ * std::declval<R>())</tt>.+ */+ typedef automatically_determined type;+};++/// A type alis to determine the result of a @c connect expression.+template <typename S, typename R>+using connect_result_t = typename connect_result<S, R>::type;++} // namespace execution+} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_execution_connect_fn {++using asio::conditional;+using asio::declval;+using asio::enable_if;+using asio::execution::detail::as_invocable;+using asio::execution::detail::as_operation;+using asio::execution::detail::is_as_receiver;+using asio::execution::is_executor_of;+using asio::execution::is_operation_state;+using asio::execution::is_receiver;+using asio::execution::is_sender;+using asio::false_type;+using asio::remove_cvref;+using asio::traits::connect_free;+using asio::traits::connect_member;++void connect();++enum overload_type+{+ call_member,+ call_free,+ adapter,+ ill_formed+};++template <typename S, typename R, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename S, typename R>+struct call_traits<S, void(R),+ typename enable_if<+ (+ connect_member<S, R>::is_valid+ &&+ is_operation_state<typename connect_member<S, R>::result_type>::value+ &&+ is_sender<typename remove_cvref<S>::type>::value+ )+ >::type> :+ connect_member<S, R>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename S, typename R>+struct call_traits<S, void(R),+ typename enable_if<+ (+ !connect_member<S, R>::is_valid+ &&+ connect_free<S, R>::is_valid+ &&+ is_operation_state<typename connect_free<S, R>::result_type>::value+ &&+ is_sender<typename remove_cvref<S>::type>::value+ )+ >::type> :+ connect_free<S, R>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++template <typename S, typename R>+struct call_traits<S, void(R),+ typename enable_if<+ (+ !connect_member<S, R>::is_valid+ &&+ !connect_free<S, R>::is_valid+ &&+ is_receiver<R>::value+ &&+ conditional<+ !is_as_receiver<+ typename remove_cvref<R>::type+ >::value,+ is_executor_of<+ typename remove_cvref<S>::type,+ as_invocable<typename remove_cvref<R>::type, S>+ >,+ false_type+ >::type::value+ )+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef as_operation<S, R> result_type;+};++struct impl+{+#if defined(ASIO_HAS_MOVE)+ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(R)>::overload == call_member,+ typename call_traits<S, void(R)>::result_type+ >::type+ operator()(S&& s, R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(R)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(S)(s).connect(ASIO_MOVE_CAST(R)(r));+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(R)>::overload == call_free,+ typename call_traits<S, void(R)>::result_type+ >::type+ operator()(S&& s, R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(R)>::is_noexcept))+ {+ return connect(ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r));+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(R)>::overload == adapter,+ typename call_traits<S, void(R)>::result_type+ >::type+ operator()(S&& s, R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(R)>::is_noexcept))+ {+ return typename call_traits<S, void(R)>::result_type(+ ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r));+ }+#else // defined(ASIO_HAS_MOVE)+ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(R&)>::overload == call_member,+ typename call_traits<S&, void(R&)>::result_type+ >::type+ operator()(S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(R&)>::is_noexcept))+ {+ return s.connect(r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(R&)>::overload == call_member,+ typename call_traits<const S&, void(R&)>::result_type+ >::type+ operator()(const S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(R&)>::is_noexcept))+ {+ return s.connect(r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(R&)>::overload == call_free,+ typename call_traits<S&, void(R&)>::result_type+ >::type+ operator()(S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(R&)>::is_noexcept))+ {+ return connect(s, r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(R&)>::overload == call_free,+ typename call_traits<const S&, void(R&)>::result_type+ >::type+ operator()(const S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(R&)>::is_noexcept))+ {+ return connect(s, r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(R&)>::overload == adapter,+ typename call_traits<S&, void(R&)>::result_type+ >::type+ operator()(S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(R&)>::is_noexcept))+ {+ return typename call_traits<S&, void(R&)>::result_type(s, r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(R&)>::overload == adapter,+ typename call_traits<const S&, void(R&)>::result_type+ >::type+ operator()(const S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(R&)>::is_noexcept))+ {+ return typename call_traits<const S&, void(R&)>::result_type(s, r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(const R&)>::overload == call_member,+ typename call_traits<S&, void(const R&)>::result_type+ >::type+ operator()(S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(const R&)>::is_noexcept))+ {+ return s.connect(r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(const R&)>::overload == call_member,+ typename call_traits<const S&, void(const R&)>::result_type+ >::type+ operator()(const S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(const R&)>::is_noexcept))+ {+ return s.connect(r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(const R&)>::overload == call_free,+ typename call_traits<S&, void(const R&)>::result_type+ >::type+ operator()(S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(const R&)>::is_noexcept))+ {+ return connect(s, r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(const R&)>::overload == call_free,+ typename call_traits<const S&, void(const R&)>::result_type+ >::type+ operator()(const S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(const R&)>::is_noexcept))+ {+ return connect(s, r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(const R&)>::overload == adapter,+ typename call_traits<S&, void(const R&)>::result_type+ >::type+ operator()(S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(const R&)>::is_noexcept))+ {+ return typename call_traits<S&, void(const R&)>::result_type(s, r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(const R&)>::overload == adapter,+ typename call_traits<const S&, void(const R&)>::result_type+ >::type+ operator()(const S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(const R&)>::is_noexcept))+ {+ return typename call_traits<const S&, void(const R&)>::result_type(s, r);+ }+#endif // defined(ASIO_HAS_MOVE)+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_execution_connect_fn+namespace asio {+namespace execution {+namespace {++static ASIO_CONSTEXPR const asio_execution_connect_fn::impl&+ connect = asio_execution_connect_fn::static_instance<>::instance;++} // namespace++template <typename S, typename R>+struct can_connect :+ integral_constant<bool,+ asio_execution_connect_fn::call_traits<S, void(R)>::overload !=+ asio_execution_connect_fn::ill_formed>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename R>+constexpr bool can_connect_v = can_connect<S, R>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename R>+struct is_nothrow_connect :+ integral_constant<bool,+ asio_execution_connect_fn::call_traits<S, void(R)>::is_noexcept>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename R>+constexpr bool is_nothrow_connect_v+ = is_nothrow_connect<S, R>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename R>+struct connect_result+{+ typedef typename asio_execution_connect_fn::call_traits<+ S, void(R)>::result_type type;+};++#if defined(ASIO_HAS_ALIAS_TEMPLATES)++template <typename S, typename R>+using connect_result_t = typename connect_result<S, R>::type;++#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)++} // namespace execution+} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_CONNECT_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/context.hpp view
@@ -0,0 +1,185 @@+//+// execution/context.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_CONTEXT2_HPP+#define ASIO_EXECUTION_CONTEXT2_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/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/is_applicable_property.hpp"+#include "asio/traits/query_static_constexpr_member.hpp"+#include "asio/traits/static_query.hpp"++#if defined(ASIO_HAS_STD_ANY)+# include <any>+#endif // defined(ASIO_HAS_STD_ANY)++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// A property that is used to obtain the execution context that is associated+/// with an executor.+struct context_t+{+ /// The context_t property applies to executors, senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The context_t property cannot be required.+ static constexpr bool is_requirable = false;++ /// The context_t property cannot be preferred.+ static constexpr bool is_preferable = false;++ /// The type returned by queries against an @c any_executor.+ typedef std::any polymorphic_query_result_type;+};++/// A special value used for accessing the context_t property.+constexpr context_t context;++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {+namespace detail {++template <int I = 0>+struct context_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);++#if defined(ASIO_HAS_STD_ANY)+ typedef std::any polymorphic_query_result_type;+#endif // defined(ASIO_HAS_STD_ANY)++ ASIO_CONSTEXPR context_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, context_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, context_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, context_t>::value();+ }++ template <typename E, typename T = decltype(context_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = context_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_CONSTEXPR)+ static const context_t instance;+#endif // !defined(ASIO_HAS_CONSTEXPR)+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T context_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_CONSTEXPR)+template <int I>+const context_t<I> context_t<I>::instance;+#endif++} // namespace detail++typedef detail::context_t<> context_t;++#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr context_t context;+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+namespace { static const context_t& context = context_t::instance; }+#endif++} // namespace execution++#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+struct is_applicable_property<T, execution::context_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename T>+struct static_query<T, execution::context_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::context_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::context_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::context_t>::value();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_CONTEXT2_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/context_as.hpp view
@@ -0,0 +1,201 @@+//+// execution/context_as.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_CONTEXT_AS_HPP+#define ASIO_EXECUTION_CONTEXT_AS_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/context.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/is_applicable_property.hpp"+#include "asio/query.hpp"+#include "asio/traits/query_static_constexpr_member.hpp"+#include "asio/traits/static_query.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// A property that is used to obtain the execution context that is associated+/// with an executor.+template <typename U>+struct context_as_t+{+ /// The context_as_t property applies to executors, senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The context_t property cannot be required.+ static constexpr bool is_requirable = false;++ /// The context_t property cannot be preferred.+ static constexpr bool is_preferable = false;++ /// The type returned by queries against an @c any_executor.+ typedef T polymorphic_query_result_type;+};++/// A special value used for accessing the context_as_t property.+template <typename U>+constexpr context_as_t context_as;++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {++template <typename T>+struct context_as_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename U>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<U>::value+ || is_sender<U>::value || is_scheduler<U>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);++ typedef T polymorphic_query_result_type;++ ASIO_CONSTEXPR context_as_t()+ {+ }++ ASIO_CONSTEXPR context_as_t(context_t)+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename E>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<E, context_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<E, context_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<E, context_t>::value();+ }++ template <typename E, typename U = decltype(context_as_t::static_query<E>())>+ static ASIO_CONSTEXPR const U static_query_v+ = context_as_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ template <typename Executor, typename U>+ friend ASIO_CONSTEXPR U query(+ const Executor& ex, const context_as_t<U>&,+ typename enable_if<+ is_same<T, U>::value+ && can_query<const Executor&, const context_t&>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, const context_t&>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, const context_t&>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, context);+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <typename T> template <typename E, typename U>+const U context_as_t<T>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if (defined(ASIO_HAS_VARIABLE_TEMPLATES) \+ && defined(ASIO_HAS_CONSTEXPR)) \+ || defined(GENERATING_DOCUMENTATION)+template <typename T>+constexpr context_as_t<T> context_as{};+#endif // (defined(ASIO_HAS_VARIABLE_TEMPLATES)+ // && defined(ASIO_HAS_CONSTEXPR))+ // || defined(GENERATING_DOCUMENTATION)++} // namespace execution++#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename U>+struct is_applicable_property<T, execution::context_as_t<U> >+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename T, typename U>+struct static_query<T, execution::context_as_t<U>,+ typename enable_if<+ static_query<T, execution::context_t>::is_valid+ >::type> : static_query<T, execution::context_t>+{+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++template <typename T, typename U>+struct query_free<T, execution::context_as_t<U>,+ typename enable_if<+ can_query<const T&, const execution::context_t&>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<const T&, const execution::context_t&>::value));++ typedef U result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_CONTEXT_AS_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/detail/as_invocable.hpp view
@@ -0,0 +1,152 @@+//+// execution/detail/as_invocable.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_DETAIL_AS_INVOCABLE_HPP+#define ASIO_EXECUTION_DETAIL_AS_INVOCABLE_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/atomic_count.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution/receiver_invocation_error.hpp"+#include "asio/execution/set_done.hpp"+#include "asio/execution/set_error.hpp"+#include "asio/execution/set_value.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {+namespace detail {++#if defined(ASIO_HAS_MOVE)++template <typename Receiver, typename>+struct as_invocable+{+ Receiver* receiver_;++ explicit as_invocable(Receiver& r) ASIO_NOEXCEPT+ : receiver_(asio::detail::addressof(r))+ {+ }++ as_invocable(as_invocable&& other) ASIO_NOEXCEPT+ : receiver_(other.receiver_)+ {+ other.receiver_ = 0;+ }++ ~as_invocable()+ {+ if (receiver_)+ execution::set_done(ASIO_MOVE_OR_LVALUE(Receiver)(*receiver_));+ }++ void operator()() ASIO_LVALUE_REF_QUAL ASIO_NOEXCEPT+ {+#if !defined(ASIO_NO_EXCEPTIONS)+ try+ {+#endif // !defined(ASIO_NO_EXCEPTIONS)+ execution::set_value(ASIO_MOVE_CAST(Receiver)(*receiver_));+ receiver_ = 0;+#if !defined(ASIO_NO_EXCEPTIONS)+ }+ catch (...)+ {+#if defined(ASIO_HAS_STD_EXCEPTION_PTR)+ execution::set_error(ASIO_MOVE_CAST(Receiver)(*receiver_),+ std::make_exception_ptr(receiver_invocation_error()));+ receiver_ = 0;+#else // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ std::terminate();+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ }+#endif // !defined(ASIO_NO_EXCEPTIONS)+ }+};++#else // defined(ASIO_HAS_MOVE)++template <typename Receiver, typename>+struct as_invocable+{+ Receiver* receiver_;+ asio::detail::shared_ptr<asio::detail::atomic_count> ref_count_;++ explicit as_invocable(Receiver& r,+ const asio::detail::shared_ptr<+ asio::detail::atomic_count>& c) ASIO_NOEXCEPT+ : receiver_(asio::detail::addressof(r)),+ ref_count_(c)+ {+ }++ as_invocable(const as_invocable& other) ASIO_NOEXCEPT+ : receiver_(other.receiver_),+ ref_count_(other.ref_count_)+ {+ ++(*ref_count_);+ }++ ~as_invocable()+ {+ if (--(*ref_count_) == 0)+ execution::set_done(*receiver_);+ }++ void operator()() ASIO_LVALUE_REF_QUAL ASIO_NOEXCEPT+ {+#if !defined(ASIO_NO_EXCEPTIONS)+ try+ {+#endif // !defined(ASIO_NO_EXCEPTIONS)+ execution::set_value(*receiver_);+ ++(*ref_count_);+ }+#if !defined(ASIO_NO_EXCEPTIONS)+ catch (...)+ {+#if defined(ASIO_HAS_STD_EXCEPTION_PTR)+ execution::set_error(*receiver_,+ std::make_exception_ptr(receiver_invocation_error()));+ ++(*ref_count_);+#else // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ std::terminate();+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ }+#endif // !defined(ASIO_NO_EXCEPTIONS)+ }+};++#endif // defined(ASIO_HAS_MOVE)++template <typename T>+struct is_as_invocable : false_type+{+};++template <typename Function, typename T>+struct is_as_invocable<as_invocable<Function, T> > : true_type+{+};++} // namespace detail+} // namespace execution+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_DETAIL_AS_INVOCABLE_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/detail/as_operation.hpp view
@@ -0,0 +1,105 @@+//+// execution/detail/as_operation.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_DETAIL_AS_OPERATION_HPP+#define ASIO_EXECUTION_DETAIL_AS_OPERATION_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/memory.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution/detail/as_invocable.hpp"+#include "asio/execution/execute.hpp"+#include "asio/execution/set_error.hpp"+#include "asio/traits/start_member.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {+namespace detail {++template <typename Executor, typename Receiver>+struct as_operation+{+ typename remove_cvref<Executor>::type ex_;+ typename remove_cvref<Receiver>::type receiver_;+#if !defined(ASIO_HAS_MOVE)+ asio::detail::shared_ptr<asio::detail::atomic_count> ref_count_;+#endif // !defined(ASIO_HAS_MOVE)++ template <typename E, typename R>+ explicit as_operation(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(R) r)+ : ex_(ASIO_MOVE_CAST(E)(e)),+ receiver_(ASIO_MOVE_CAST(R)(r))+#if !defined(ASIO_HAS_MOVE)+ , ref_count_(new asio::detail::atomic_count(1))+#endif // !defined(ASIO_HAS_MOVE)+ {+ }++ void start() ASIO_NOEXCEPT+ {+#if !defined(ASIO_NO_EXCEPTIONS)+ try+ {+#endif // !defined(ASIO_NO_EXCEPTIONS)+ execution::execute(+ ASIO_MOVE_CAST(typename remove_cvref<Executor>::type)(ex_),+ as_invocable<typename remove_cvref<Receiver>::type,+ Executor>(receiver_+#if !defined(ASIO_HAS_MOVE)+ , ref_count_+#endif // !defined(ASIO_HAS_MOVE)+ ));+#if !defined(ASIO_NO_EXCEPTIONS)+ }+ catch (...)+ {+#if defined(ASIO_HAS_STD_EXCEPTION_PTR)+ execution::set_error(+ ASIO_MOVE_OR_LVALUE(+ typename remove_cvref<Receiver>::type)(+ receiver_),+ std::current_exception());+#else // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ std::terminate();+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ }+#endif // !defined(ASIO_NO_EXCEPTIONS)+ }+};++} // namespace detail+} // namespace execution+namespace traits {++#if !defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)++template <typename Executor, typename Receiver>+struct start_member<+ asio::execution::detail::as_operation<Executor, Receiver> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_DETAIL_AS_OPERATION_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/detail/as_receiver.hpp view
@@ -0,0 +1,128 @@+//+// execution/detail/as_receiver.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_DETAIL_AS_RECEIVER_HPP+#define ASIO_EXECUTION_DETAIL_AS_RECEIVER_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/traits/set_done_member.hpp"+#include "asio/traits/set_error_member.hpp"+#include "asio/traits/set_value_member.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {+namespace detail {++template <typename Function, typename>+struct as_receiver+{+ Function f_;++ template <typename F>+ explicit as_receiver(ASIO_MOVE_ARG(F) f, int)+ : f_(ASIO_MOVE_CAST(F)(f))+ {+ }++#if defined(ASIO_MSVC) && defined(ASIO_HAS_MOVE)+ as_receiver(as_receiver&& other)+ : f_(ASIO_MOVE_CAST(Function)(other.f_))+ {+ }+#endif // defined(ASIO_MSVC) && defined(ASIO_HAS_MOVE)++ void set_value()+ ASIO_NOEXCEPT_IF(noexcept(declval<Function&>()()))+ {+ f_();+ }++ template <typename E>+ void set_error(E) ASIO_NOEXCEPT+ {+ std::terminate();+ }++ void set_done() ASIO_NOEXCEPT+ {+ }+};++template <typename T>+struct is_as_receiver : false_type+{+};++template <typename Function, typename T>+struct is_as_receiver<as_receiver<Function, T> > : true_type+{+};++} // namespace detail+} // namespace execution+namespace traits {++#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)++template <typename Function, typename T>+struct set_value_member<+ asio::execution::detail::as_receiver<Function, T>, void()>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+#if defined(ASIO_HAS_NOEXCEPT)+ ASIO_STATIC_CONSTEXPR(bool,+ is_noexcept = noexcept(declval<Function&>()()));+#else // defined(ASIO_HAS_NOEXCEPT)+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+#endif // defined(ASIO_HAS_NOEXCEPT)+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)++template <typename Function, typename T, typename E>+struct set_error_member<+ asio::execution::detail::as_receiver<Function, T>, E>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)++template <typename Function, typename T>+struct set_done_member<+ asio::execution::detail::as_receiver<Function, T> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_DETAIL_AS_RECEIVER_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/detail/bulk_sender.hpp view
@@ -0,0 +1,261 @@+//+// execution/detail/bulk_sender.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_DETAIL_BULK_SENDER_HPP+#define ASIO_EXECUTION_DETAIL_BULK_SENDER_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/connect.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution/set_done.hpp"+#include "asio/execution/set_error.hpp"+#include "asio/traits/connect_member.hpp"+#include "asio/traits/set_done_member.hpp"+#include "asio/traits/set_error_member.hpp"+#include "asio/traits/set_value_member.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {+namespace detail {++template <typename Receiver, typename Function, typename Number, typename Index>+struct bulk_receiver+{+ typename remove_cvref<Receiver>::type receiver_;+ typename decay<Function>::type f_;+ typename decay<Number>::type n_;++ template <typename R, typename F, typename N>+ explicit bulk_receiver(ASIO_MOVE_ARG(R) r,+ ASIO_MOVE_ARG(F) f, ASIO_MOVE_ARG(N) n)+ : receiver_(ASIO_MOVE_CAST(R)(r)),+ f_(ASIO_MOVE_CAST(F)(f)),+ n_(ASIO_MOVE_CAST(N)(n))+ {+ }++ void set_value()+ {+ for (Index i = 0; i < n_; ++i)+ f_(i);++ execution::set_value(+ ASIO_MOVE_OR_LVALUE(+ typename remove_cvref<Receiver>::type)(receiver_));+ }++ template <typename Error>+ void set_error(ASIO_MOVE_ARG(Error) e) ASIO_NOEXCEPT+ {+ execution::set_error(+ ASIO_MOVE_OR_LVALUE(+ typename remove_cvref<Receiver>::type)(receiver_),+ ASIO_MOVE_CAST(Error)(e));+ }++ void set_done() ASIO_NOEXCEPT+ {+ execution::set_done(+ ASIO_MOVE_OR_LVALUE(+ typename remove_cvref<Receiver>::type)(receiver_));+ }+};++template <typename Sender, typename Receiver,+ typename Function, typename Number>+struct bulk_receiver_traits+{+ typedef bulk_receiver<+ Receiver, Function, Number,+ typename execution::executor_index<+ typename remove_cvref<Sender>::type+ >::type+ > type;++#if defined(ASIO_HAS_MOVE)+ typedef type arg_type;+#else // defined(ASIO_HAS_MOVE)+ typedef const type& arg_type;+#endif // defined(ASIO_HAS_MOVE)+};++template <typename Sender, typename Function, typename Number>+struct bulk_sender : sender_base+{+ typename remove_cvref<Sender>::type sender_;+ typename decay<Function>::type f_;+ typename decay<Number>::type n_;++ template <typename S, typename F, typename N>+ explicit bulk_sender(ASIO_MOVE_ARG(S) s,+ ASIO_MOVE_ARG(F) f, ASIO_MOVE_ARG(N) n)+ : sender_(ASIO_MOVE_CAST(S)(s)),+ f_(ASIO_MOVE_CAST(F)(f)),+ n_(ASIO_MOVE_CAST(N)(n))+ {+ }++ template <typename Receiver>+ typename connect_result<+ ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref<Sender>::type),+ typename bulk_receiver_traits<+ Sender, Receiver, Function, Number+ >::arg_type+ >::type connect(ASIO_MOVE_ARG(Receiver) r,+ typename enable_if<+ can_connect<+ typename remove_cvref<Sender>::type,+ typename bulk_receiver_traits<+ Sender, Receiver, Function, Number+ >::arg_type+ >::value+ >::type* = 0) ASIO_RVALUE_REF_QUAL ASIO_NOEXCEPT+ {+ return execution::connect(+ ASIO_MOVE_OR_LVALUE(typename remove_cvref<Sender>::type)(sender_),+ typename bulk_receiver_traits<Sender, Receiver, Function, Number>::type(+ ASIO_MOVE_CAST(Receiver)(r),+ ASIO_MOVE_CAST(typename decay<Function>::type)(f_),+ ASIO_MOVE_CAST(typename decay<Number>::type)(n_)));+ }++ template <typename Receiver>+ typename connect_result<+ const typename remove_cvref<Sender>::type&,+ typename bulk_receiver_traits<+ Sender, Receiver, Function, Number+ >::arg_type+ >::type connect(ASIO_MOVE_ARG(Receiver) r,+ typename enable_if<+ can_connect<+ const typename remove_cvref<Sender>::type&,+ typename bulk_receiver_traits<+ Sender, Receiver, Function, Number+ >::arg_type+ >::value+ >::type* = 0) const ASIO_LVALUE_REF_QUAL ASIO_NOEXCEPT+ {+ return execution::connect(sender_,+ typename bulk_receiver_traits<Sender, Receiver, Function, Number>::type(+ ASIO_MOVE_CAST(Receiver)(r), f_, n_));+ }+};++} // namespace detail+} // namespace execution+namespace traits {++#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)++template <typename Receiver, typename Function, typename Number, typename Index>+struct set_value_member<+ execution::detail::bulk_receiver<Receiver, Function, Number, Index>,+ void()>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)++template <typename Receiver, typename Function,+ typename Number, typename Index, typename Error>+struct set_error_member<+ execution::detail::bulk_receiver<Receiver, Function, Number, Index>,+ Error>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)++template <typename Receiver, typename Function, typename Number, typename Index>+struct set_done_member<+ execution::detail::bulk_receiver<Receiver, Function, Number, Index> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)++template <typename Sender, typename Function,+ typename Number, typename Receiver>+struct connect_member<+ execution::detail::bulk_sender<Sender, Function, Number>,+ Receiver,+ typename enable_if<+ execution::can_connect<+ ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref<Sender>::type),+ typename execution::detail::bulk_receiver_traits<+ Sender, Receiver, Function, Number+ >::arg_type+ >::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef typename execution::connect_result<+ ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref<Sender>::type),+ typename execution::detail::bulk_receiver_traits<+ Sender, Receiver, Function, Number+ >::arg_type+ >::type result_type;+};++template <typename Sender, typename Function,+ typename Number, typename Receiver>+struct connect_member<+ const execution::detail::bulk_sender<Sender, Function, Number>,+ Receiver,+ typename enable_if<+ execution::can_connect<+ const typename remove_cvref<Sender>::type&,+ typename execution::detail::bulk_receiver_traits<+ Sender, Receiver, Function, Number+ >::arg_type+ >::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef typename execution::connect_result<+ const typename remove_cvref<Sender>::type&,+ typename execution::detail::bulk_receiver_traits<+ Sender, Receiver, Function, Number+ >::arg_type+ >::type result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_DETAIL_BULK_SENDER_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/detail/submit_receiver.hpp view
@@ -0,0 +1,233 @@+//+// execution/detail/submit_receiver.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP+#define ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_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/variadic_templates.hpp"+#include "asio/execution/connect.hpp"+#include "asio/execution/receiver.hpp"+#include "asio/execution/set_done.hpp"+#include "asio/execution/set_error.hpp"+#include "asio/execution/set_value.hpp"+#include "asio/traits/set_done_member.hpp"+#include "asio/traits/set_error_member.hpp"+#include "asio/traits/set_value_member.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {+namespace detail {++template <typename Sender, typename Receiver>+struct submit_receiver;++template <typename Sender, typename Receiver>+struct submit_receiver_wrapper+{+ submit_receiver<Sender, Receiver>* p_;++ explicit submit_receiver_wrapper(submit_receiver<Sender, Receiver>* p)+ : p_(p)+ {+ }++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename... Args>+ typename enable_if<is_receiver_of<Receiver, Args...>::value>::type+ set_value(ASIO_MOVE_ARG(Args)... args) ASIO_RVALUE_REF_QUAL+ ASIO_NOEXCEPT_IF((is_nothrow_receiver_of<Receiver, Args...>::value))+ {+ execution::set_value(+ ASIO_MOVE_OR_LVALUE(+ typename remove_cvref<Receiver>::type)(p_->r_),+ ASIO_MOVE_CAST(Args)(args)...);+ delete p_;+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ void set_value() ASIO_RVALUE_REF_QUAL+ ASIO_NOEXCEPT_IF((is_nothrow_receiver_of<Receiver>::value))+ {+ execution::set_value(+ ASIO_MOVE_OR_LVALUE(+ typename remove_cvref<Receiver>::type)(p_->r_));+ delete p_;+ }++#define ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF(n) \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ typename enable_if<is_receiver_of<Receiver, \+ ASIO_VARIADIC_TARGS(n)>::value>::type \+ set_value(ASIO_VARIADIC_MOVE_PARAMS(n)) ASIO_RVALUE_REF_QUAL \+ ASIO_NOEXCEPT_IF((is_nothrow_receiver_of< \+ Receiver, ASIO_VARIADIC_TARGS(n)>::value)) \+ { \+ execution::set_value( \+ ASIO_MOVE_OR_LVALUE( \+ typename remove_cvref<Receiver>::type)(p_->r_), \+ ASIO_VARIADIC_MOVE_ARGS(n)); \+ delete p_; \+ } \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF)+#undef ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename E>+ void set_error(ASIO_MOVE_ARG(E) e)+ ASIO_RVALUE_REF_QUAL ASIO_NOEXCEPT+ {+ execution::set_error(+ ASIO_MOVE_OR_LVALUE(+ typename remove_cvref<Receiver>::type)(p_->r_),+ ASIO_MOVE_CAST(E)(e));+ delete p_;+ }++ void set_done() ASIO_RVALUE_REF_QUAL ASIO_NOEXCEPT+ {+ execution::set_done(+ ASIO_MOVE_OR_LVALUE(+ typename remove_cvref<Receiver>::type)(p_->r_));+ delete p_;+ }+};++template <typename Sender, typename Receiver>+struct submit_receiver+{+ typename remove_cvref<Receiver>::type r_;+#if defined(ASIO_HAS_MOVE)+ typename connect_result<Sender,+ submit_receiver_wrapper<Sender, Receiver> >::type state_;+#else // defined(ASIO_HAS_MOVE)+ typename connect_result<Sender,+ const submit_receiver_wrapper<Sender, Receiver>& >::type state_;+#endif // defined(ASIO_HAS_MOVE)++#if defined(ASIO_HAS_MOVE)+ template <typename S, typename R>+ explicit submit_receiver(ASIO_MOVE_ARG(S) s, ASIO_MOVE_ARG(R) r)+ : r_(ASIO_MOVE_CAST(R)(r)),+ state_(execution::connect(ASIO_MOVE_CAST(S)(s),+ submit_receiver_wrapper<Sender, Receiver>(this)))+ {+ }+#else // defined(ASIO_HAS_MOVE)+ explicit submit_receiver(Sender s, Receiver r)+ : r_(r),+ state_(execution::connect(s,+ submit_receiver_wrapper<Sender, Receiver>(this)))+ {+ }+#endif // defined(ASIO_HAS_MOVE)+};++} // namespace detail+} // namespace execution+namespace traits {++#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename Sender, typename Receiver, typename... Args>+struct set_value_member<+ asio::execution::detail::submit_receiver_wrapper<+ Sender, Receiver>,+ void(Args...)>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (asio::execution::is_nothrow_receiver_of<Receiver, Args...>::value));+ typedef void result_type;+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename Sender, typename Receiver>+struct set_value_member<+ asio::execution::detail::submit_receiver_wrapper<+ Sender, Receiver>,+ void()>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ asio::execution::is_nothrow_receiver_of<Receiver>::value);+ typedef void result_type;+};++#define ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF(n) \+ template <typename Sender, typename Receiver, \+ ASIO_VARIADIC_TPARAMS(n)> \+ struct set_value_member< \+ asio::execution::detail::submit_receiver_wrapper< \+ Sender, Receiver>, \+ void(ASIO_VARIADIC_TARGS(n))> \+ { \+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true); \+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = \+ (asio::execution::is_nothrow_receiver_of<Receiver, \+ ASIO_VARIADIC_TARGS(n)>::value)); \+ typedef void result_type; \+ }; \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF)+#undef ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)++template <typename Sender, typename Receiver, typename E>+struct set_error_member<+ asio::execution::detail::submit_receiver_wrapper<+ Sender, Receiver>, E>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)++template <typename Sender, typename Receiver>+struct set_done_member<+ asio::execution::detail::submit_receiver_wrapper<+ Sender, Receiver> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/detail/void_receiver.hpp view
@@ -0,0 +1,90 @@+//+// execution/detail/void_receiver.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_DETAIL_VOID_RECEIVER_HPP+#define ASIO_EXECUTION_DETAIL_VOID_RECEIVER_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/traits/set_done_member.hpp"+#include "asio/traits/set_error_member.hpp"+#include "asio/traits/set_value_member.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {+namespace detail {++struct void_receiver+{+ void set_value() ASIO_NOEXCEPT+ {+ }++ template <typename E>+ void set_error(ASIO_MOVE_ARG(E)) ASIO_NOEXCEPT+ {+ }++ void set_done() ASIO_NOEXCEPT+ {+ }+};++} // namespace detail+} // namespace execution+namespace traits {++#if !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)++template <>+struct set_value_member<asio::execution::detail::void_receiver, void()>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)++template <typename E>+struct set_error_member<asio::execution::detail::void_receiver, E>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)++template <>+struct set_done_member<asio::execution::detail::void_receiver>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_DETAIL_VOID_RECEIVER_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/execute.hpp view
@@ -0,0 +1,264 @@+//+// execution/execute.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_EXECUTE_HPP+#define ASIO_EXECUTION_EXECUTE_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/detail/as_invocable.hpp"+#include "asio/execution/detail/as_receiver.hpp"+#include "asio/traits/execute_member.hpp"+#include "asio/traits/execute_free.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {+namespace execution {++/// A customisation point that executes a function on an executor.+/**+ * The name <tt>execution::execute</tt> denotes a customisation point object.+ *+ * For some subexpressions <tt>e</tt> and <tt>f</tt>, let <tt>E</tt> be a type+ * such that <tt>decltype((e))</tt> is <tt>E</tt> and let <tt>F</tt> be a type+ * such that <tt>decltype((f))</tt> is <tt>F</tt>. The expression+ * <tt>execution::execute(e, f)</tt> is ill-formed if <tt>F</tt> does not model+ * <tt>invocable</tt>, or if <tt>E</tt> does not model either <tt>executor</tt>+ * or <tt>sender</tt>. Otherwise, it is expression-equivalent to:+ *+ * @li <tt>e.execute(f)</tt>, if that expression is valid. If the function+ * selected does not execute the function object <tt>f</tt> on the executor+ * <tt>e</tt>, the program is ill-formed with no diagnostic required.+ *+ * @li Otherwise, <tt>execute(e, f)</tt>, if that expression is valid, with+ * overload resolution performed in a context that includes the declaration+ * <tt>void execute();</tt> and that does not include a declaration of+ * <tt>execution::execute</tt>. If the function selected by overload+ * resolution does not execute the function object <tt>f</tt> on the executor+ * <tt>e</tt>, the program is ill-formed with no diagnostic required.+ */+inline constexpr unspecified execute = unspecified;++/// A type trait that determines whether a @c execute expression is well-formed.+/**+ * Class template @c can_execute is a trait that is derived from+ * @c true_type if the expression <tt>execution::execute(std::declval<T>(),+ * std::declval<F>())</tt> is well formed; otherwise @c false_type.+ */+template <typename T, typename F>+struct can_execute :+ integral_constant<bool, automatically_determined>+{+};++} // namespace execution+} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio {+namespace execution {++template <typename T, typename R>+struct is_sender_to;++namespace detail {++template <typename S, typename R>+void submit_helper(ASIO_MOVE_ARG(S) s, ASIO_MOVE_ARG(R) r);++} // namespace detail+} // namespace execution+} // namespace asio+namespace asio_execution_execute_fn {++using asio::conditional;+using asio::decay;+using asio::declval;+using asio::enable_if;+using asio::execution::detail::as_receiver;+using asio::execution::detail::is_as_invocable;+using asio::execution::is_sender_to;+using asio::false_type;+using asio::result_of;+using asio::traits::execute_free;+using asio::traits::execute_member;+using asio::true_type;++void execute();++enum overload_type+{+ call_member,+ call_free,+ adapter,+ ill_formed+};++template <typename T, typename F, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+};++template <typename T, typename F>+struct call_traits<T, void(F),+ typename enable_if<+ (+ execute_member<T, F>::is_valid+ )+ >::type> :+ execute_member<T, F>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename T, typename F>+struct call_traits<T, void(F),+ typename enable_if<+ (+ !execute_member<T, F>::is_valid+ &&+ execute_free<T, F>::is_valid+ )+ >::type> :+ execute_free<T, F>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++template <typename T, typename F>+struct call_traits<T, void(F),+ typename enable_if<+ (+ !execute_member<T, F>::is_valid+ &&+ !execute_free<T, F>::is_valid+ &&+ conditional<true, true_type,+ typename result_of<typename decay<F>::type&()>::type+ >::type::value+ &&+ conditional<+ !is_as_invocable<+ typename decay<F>::type+ >::value,+ is_sender_to<+ T,+ as_receiver<typename decay<F>::type, T>+ >,+ false_type+ >::type::value+ )+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++struct impl+{+ template <typename T, typename F>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(F)>::overload == call_member,+ typename call_traits<T, void(F)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(F) f) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(F)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(T)(t).execute(ASIO_MOVE_CAST(F)(f));+ }++ template <typename T, typename F>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(F)>::overload == call_free,+ typename call_traits<T, void(F)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(F) f) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(F)>::is_noexcept))+ {+ return execute(ASIO_MOVE_CAST(T)(t), ASIO_MOVE_CAST(F)(f));+ }++ template <typename T, typename F>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(F)>::overload == adapter,+ typename call_traits<T, void(F)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(F) f) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(F)>::is_noexcept))+ {+ return asio::execution::detail::submit_helper(+ ASIO_MOVE_CAST(T)(t),+ as_receiver<typename decay<F>::type, T>(+ ASIO_MOVE_CAST(F)(f), 0));+ }+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_execution_execute_fn+namespace asio {+namespace execution {+namespace {++static ASIO_CONSTEXPR const asio_execution_execute_fn::impl&+ execute = asio_execution_execute_fn::static_instance<>::instance;++} // namespace++template <typename T, typename F>+struct can_execute :+ integral_constant<bool,+ asio_execution_execute_fn::call_traits<T, void(F)>::overload !=+ asio_execution_execute_fn::ill_formed>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename F>+constexpr bool can_execute_v = can_execute<T, F>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++} // namespace execution+} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_EXECUTE_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/executor.hpp view
@@ -0,0 +1,238 @@+//+// execution/executor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_EXECUTOR_HPP+#define ASIO_EXECUTION_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/execution/execute.hpp"+#include "asio/execution/invocable_archetype.hpp"+#include "asio/traits/equality_comparable.hpp"++#if defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) \+ && defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) \+ && defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)+# define ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT 1+#endif // defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)+ // && defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)+ // && defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {+namespace detail {++template <typename T, typename F>+struct is_executor_of_impl_base :+ integral_constant<bool,+ conditional<true, true_type,+ typename result_of<typename decay<F>::type&()>::type+ >::type::value+ && is_constructible<typename decay<F>::type, F>::value+ && is_move_constructible<typename decay<F>::type>::value+#if defined(ASIO_HAS_NOEXCEPT)+ && is_nothrow_copy_constructible<T>::value+ && is_nothrow_destructible<T>::value+#else // defined(ASIO_HAS_NOEXCEPT)+ && is_copy_constructible<T>::value+ && is_destructible<T>::value+#endif // defined(ASIO_HAS_NOEXCEPT)+ && traits::equality_comparable<T>::is_valid+ && traits::equality_comparable<T>::is_noexcept+ >+{+};++template <typename T, typename F>+struct is_executor_of_impl :+ conditional<+ can_execute<T, F>::value,+ is_executor_of_impl_base<T, F>,+ false_type+ >::type+{+};++template <typename T, typename = void>+struct executor_shape+{+ typedef std::size_t type;+};++template <typename T>+struct executor_shape<T,+ typename void_type<+ typename T::shape_type+ >::type>+{+ typedef typename T::shape_type type;+};++template <typename T, typename Default, typename = void>+struct executor_index+{+ typedef Default type;+};++template <typename T, typename Default>+struct executor_index<T, Default,+ typename void_type<+ typename T::index_type+ >::type>+{+ typedef typename T::index_type type;+};++} // namespace detail++/// The is_executor trait detects whether a type T satisfies the+/// execution::executor concept.+/**+ * Class template @c is_executor is a UnaryTypeTrait that is derived from @c+ * true_type if the type @c T meets the concept definition for an executor,+ * otherwise @c false_type.+ */+template <typename T>+struct is_executor :+#if defined(GENERATING_DOCUMENTATION)+ integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ detail::is_executor_of_impl<T, invocable_archetype>+#endif // defined(GENERATING_DOCUMENTATION)+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+ASIO_CONSTEXPR const bool is_executor_v = is_executor<T>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_CONCEPTS)++template <typename T>+ASIO_CONCEPT executor = is_executor<T>::value;++#define ASIO_EXECUTION_EXECUTOR ::asio::execution::executor++#else // defined(ASIO_HAS_CONCEPTS)++#define ASIO_EXECUTION_EXECUTOR typename++#endif // defined(ASIO_HAS_CONCEPTS)++/// The is_executor_of trait detects whether a type T satisfies the+/// execution::executor_of concept for some set of value arguments.+/**+ * Class template @c is_executor_of is a type trait that is derived from @c+ * true_type if the type @c T meets the concept definition for an executor+ * that is invocable with a function object of type @c F, otherwise @c+ * false_type.+ */+template <typename T, typename F>+struct is_executor_of :+#if defined(GENERATING_DOCUMENTATION)+ integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ integral_constant<bool,+ is_executor<T>::value && detail::is_executor_of_impl<T, F>::value+ >+#endif // defined(GENERATING_DOCUMENTATION)+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename F>+ASIO_CONSTEXPR const bool is_executor_of_v =+ is_executor_of<T, F>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_CONCEPTS)++template <typename T, typename F>+ASIO_CONCEPT executor_of = is_executor_of<T, F>::value;++#define ASIO_EXECUTION_EXECUTOR_OF(f) \+ ::asio::execution::executor_of<f>++#else // defined(ASIO_HAS_CONCEPTS)++#define ASIO_EXECUTION_EXECUTOR_OF typename++#endif // defined(ASIO_HAS_CONCEPTS)++/// The executor_shape trait detects the type used by an executor to represent+/// the shape of a bulk operation.+/**+ * Class template @c executor_shape is a type trait with a nested type alias+ * @c type whose type is @c T::shape_type if @c T::shape_type is valid,+ * otherwise @c std::size_t.+ */+template <typename T>+struct executor_shape+#if !defined(GENERATING_DOCUMENTATION)+ : detail::executor_shape<T>+#endif // !defined(GENERATING_DOCUMENTATION)+{+#if defined(GENERATING_DOCUMENTATION)+ /// @c T::shape_type if @c T::shape_type is valid, otherwise @c std::size_t.+ typedef automatically_determined type;+#endif // defined(GENERATING_DOCUMENTATION)+};++#if defined(ASIO_HAS_ALIAS_TEMPLATES)++template <typename T>+using executor_shape_t = typename executor_shape<T>::type;++#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)++/// The executor_index trait detects the type used by an executor to represent+/// an index within a bulk operation.+/**+ * Class template @c executor_index is a type trait with a nested type alias+ * @c type whose type is @c T::index_type if @c T::index_type is valid,+ * otherwise @c executor_shape_t<T>.+ */+template <typename T>+struct executor_index+#if !defined(GENERATING_DOCUMENTATION)+ : detail::executor_index<T, typename executor_shape<T>::type>+#endif // !defined(GENERATING_DOCUMENTATION)+{+#if defined(GENERATING_DOCUMENTATION)+ /// @c T::index_type if @c T::index_type is valid, otherwise+ /// @c executor_shape_t<T>.+ typedef automatically_determined type;+#endif // defined(GENERATING_DOCUMENTATION)+};++#if defined(ASIO_HAS_ALIAS_TEMPLATES)++template <typename T>+using executor_index_t = typename executor_index<T>::type;++#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)++} // namespace execution+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/impl/bad_executor.ipp view
@@ -0,0 +1,40 @@+//+// exection/impl/bad_executor.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_IMPL_BAD_EXECUTOR_IPP+#define ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/execution/bad_executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {++bad_executor::bad_executor() ASIO_NOEXCEPT+{+}++const char* bad_executor::what() const ASIO_NOEXCEPT_OR_NOTHROW+{+ return "bad executor";+}++} // namespace execution+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP
+ link/modules/asio-standalone/asio/include/asio/execution/impl/receiver_invocation_error.ipp view
@@ -0,0 +1,36 @@+//+// exection/impl/receiver_invocation_error.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_IMPL_RECEIVER_INVOCATION_ERROR_IPP+#define ASIO_EXECUTION_IMPL_RECEIVER_INVOCATION_ERROR_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/execution/receiver_invocation_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {++receiver_invocation_error::receiver_invocation_error()+ : std::runtime_error("receiver invocation error")+{+}++} // namespace execution+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_IMPL_RECEIVER_INVOCATION_ERROR_IPP
+ link/modules/asio-standalone/asio/include/asio/execution/invocable_archetype.hpp view
@@ -0,0 +1,71 @@+//+// execution/invocable_archetype.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_INVOCABLE_ARCHETYPE_HPP+#define ASIO_EXECUTION_INVOCABLE_ARCHETYPE_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/variadic_templates.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {++/// An archetypal function object used for determining adherence to the+/// execution::executor concept.+struct invocable_archetype+{+#if !defined(GENERATING_DOCUMENTATION)+ // Necessary for compatibility with a C++03 implementation of result_of.+ typedef void result_type;+#endif // !defined(GENERATING_DOCUMENTATION)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \+ || defined(GENERATING_DOCUMENTATION)++ /// Function call operator.+ template <typename... Args>+ void operator()(ASIO_MOVE_ARG(Args)...)+ {+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)++ void operator()()+ {+ }++#define ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF(n) \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ void operator()(ASIO_VARIADIC_UNNAMED_MOVE_PARAMS(n)) \+ { \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF)+#undef ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)+};++} // namespace execution+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP+
+ link/modules/asio-standalone/asio/include/asio/execution/mapping.hpp view
@@ -0,0 +1,917 @@+//+// execution/mapping.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_MAPPING_HPP+#define ASIO_EXECUTION_MAPPING_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/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/is_applicable_property.hpp"+#include "asio/query.hpp"+#include "asio/traits/query_free.hpp"+#include "asio/traits/query_member.hpp"+#include "asio/traits/query_static_constexpr_member.hpp"+#include "asio/traits/static_query.hpp"+#include "asio/traits/static_require.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// A property to describe what guarantees an executor makes about the mapping+/// of execution agents on to threads of execution.+struct mapping_t+{+ /// The mapping_t property applies to executors, senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The top-level mapping_t property cannot be required.+ static constexpr bool is_requirable = false;++ /// The top-level mapping_t property cannot be preferred.+ static constexpr bool is_preferable = false;++ /// The type returned by queries against an @c any_executor.+ typedef mapping_t polymorphic_query_result_type;++ /// A sub-property that indicates that execution agents are mapped on to+ /// threads of execution.+ struct thread_t+ {+ /// The mapping_t::thread_t property applies to executors, senders, and+ /// schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The mapping_t::thread_t property can be required.+ static constexpr bool is_requirable = true;++ /// The mapping_t::thread_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef mapping_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr thread_t();++ /// Get the value associated with a property object.+ /**+ * @returns thread_t();+ */+ static constexpr mapping_t value();+ };++ /// A sub-property that indicates that execution agents are mapped on to+ /// new threads of execution.+ struct new_thread_t+ {+ /// The mapping_t::new_thread_t property applies to executors, senders, and+ /// schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The mapping_t::new_thread_t property can be required.+ static constexpr bool is_requirable = true;++ /// The mapping_t::new_thread_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef mapping_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr new_thread_t();++ /// Get the value associated with a property object.+ /**+ * @returns new_thread_t();+ */+ static constexpr mapping_t value();+ };++ /// A sub-property that indicates that the mapping of execution agents is+ /// implementation-defined.+ struct other_t+ {+ /// The mapping_t::other_t property applies to executors, senders, and+ /// schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The mapping_t::other_t property can be required.+ static constexpr bool is_requirable = true;++ /// The mapping_t::other_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef mapping_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr other_t();++ /// Get the value associated with a property object.+ /**+ * @returns other_t();+ */+ static constexpr mapping_t value();+ };++ /// A special value used for accessing the mapping_t::thread_t property.+ static constexpr thread_t thread;++ /// A special value used for accessing the mapping_t::new_thread_t property.+ static constexpr new_thread_t new_thread;++ /// A special value used for accessing the mapping_t::other_t property.+ static constexpr other_t other;++ /// Default constructor.+ constexpr mapping_t();++ /// Construct from a sub-property value.+ constexpr mapping_t(thread_t);++ /// Construct from a sub-property value.+ constexpr mapping_t(new_thread_t);++ /// Construct from a sub-property value.+ constexpr mapping_t(other_t);++ /// Compare property values for equality.+ friend constexpr bool operator==(+ const mapping_t& a, const mapping_t& b) noexcept;++ /// Compare property values for inequality.+ friend constexpr bool operator!=(+ const mapping_t& a, const mapping_t& b) noexcept;+};++/// A special value used for accessing the mapping_t property.+constexpr mapping_t mapping;++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {+namespace detail {+namespace mapping {++template <int I> struct thread_t;+template <int I> struct new_thread_t;+template <int I> struct other_t;++} // namespace mapping++template <int I = 0>+struct mapping_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);+ typedef mapping_t polymorphic_query_result_type;++ typedef detail::mapping::thread_t<I> thread_t;+ typedef detail::mapping::new_thread_t<I> new_thread_t;+ typedef detail::mapping::other_t<I> other_t;++ ASIO_CONSTEXPR mapping_t()+ : value_(-1)+ {+ }++ ASIO_CONSTEXPR mapping_t(thread_t)+ : value_(0)+ {+ }++ ASIO_CONSTEXPR mapping_t(new_thread_t)+ : value_(1)+ {+ }++ ASIO_CONSTEXPR mapping_t(other_t)+ : value_(2)+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, mapping_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, mapping_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, mapping_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, thread_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, mapping_t>::is_valid+ && !traits::query_member<T, mapping_t>::is_valid+ && traits::static_query<T, thread_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, thread_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, new_thread_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, mapping_t>::is_valid+ && !traits::query_member<T, mapping_t>::is_valid+ && !traits::static_query<T, thread_t>::is_valid+ && traits::static_query<T, new_thread_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, new_thread_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, other_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, mapping_t>::is_valid+ && !traits::query_member<T, mapping_t>::is_valid+ && !traits::static_query<T, thread_t>::is_valid+ && !traits::static_query<T, new_thread_t>::is_valid+ && traits::static_query<T, other_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, other_t>::value();+ }++ template <typename E, typename T = decltype(mapping_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = mapping_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ friend ASIO_CONSTEXPR bool operator==(+ const mapping_t& a, const mapping_t& b)+ {+ return a.value_ == b.value_;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const mapping_t& a, const mapping_t& b)+ {+ return a.value_ != b.value_;+ }++ struct convertible_from_mapping_t+ {+ ASIO_CONSTEXPR convertible_from_mapping_t(mapping_t) {}+ };++ template <typename Executor>+ friend ASIO_CONSTEXPR mapping_t query(+ const Executor& ex, convertible_from_mapping_t,+ typename enable_if<+ can_query<const Executor&, thread_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, mapping_t<>::thread_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, thread_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, thread_t());+ }++ template <typename Executor>+ friend ASIO_CONSTEXPR mapping_t query(+ const Executor& ex, convertible_from_mapping_t,+ typename enable_if<+ !can_query<const Executor&, thread_t>::value+ && can_query<const Executor&, new_thread_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, mapping_t<>::new_thread_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, new_thread_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, new_thread_t());+ }++ template <typename Executor>+ friend ASIO_CONSTEXPR mapping_t query(+ const Executor& ex, convertible_from_mapping_t,+ typename enable_if<+ !can_query<const Executor&, thread_t>::value+ && !can_query<const Executor&, new_thread_t>::value+ && can_query<const Executor&, other_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, mapping_t<>::other_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, other_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, other_t());+ }++ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(thread_t, thread);+ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(new_thread_t, new_thread);+ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(other_t, other);++#if !defined(ASIO_HAS_CONSTEXPR)+ static const mapping_t instance;+#endif // !defined(ASIO_HAS_CONSTEXPR)++private:+ int value_;+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T mapping_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_CONSTEXPR)+template <int I>+const mapping_t<I> mapping_t<I>::instance;+#endif++template <int I>+const typename mapping_t<I>::thread_t mapping_t<I>::thread;++template <int I>+const typename mapping_t<I>::new_thread_t mapping_t<I>::new_thread;++template <int I>+const typename mapping_t<I>::other_t mapping_t<I>::other;++namespace mapping {++template <int I = 0>+struct thread_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef mapping_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR thread_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, thread_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, thread_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, thread_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR thread_t static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, thread_t>::is_valid+ && !traits::query_member<T, thread_t>::is_valid+ && !traits::query_free<T, thread_t>::is_valid+ && !can_query<T, new_thread_t<I> >::value+ && !can_query<T, other_t<I> >::value+ >::type* = 0) ASIO_NOEXCEPT+ {+ return thread_t();+ }++ template <typename E, typename T = decltype(thread_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = thread_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR mapping_t<I> value()+ {+ return thread_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const thread_t&, const thread_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const thread_t&, const thread_t&)+ {+ return false;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T thread_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <int I = 0>+struct new_thread_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef mapping_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR new_thread_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, new_thread_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, new_thread_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, new_thread_t>::value();+ }++ template <typename E, typename T = decltype(new_thread_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = new_thread_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR mapping_t<I> value()+ {+ return new_thread_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const new_thread_t&, const new_thread_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const new_thread_t&, const new_thread_t&)+ {+ return false;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T new_thread_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <int I>+struct other_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef mapping_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR other_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, other_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, other_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, other_t>::value();+ }++ template <typename E, typename T = decltype(other_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = other_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR mapping_t<I> value()+ {+ return other_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const other_t&, const other_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const other_t&, const other_t&)+ {+ return false;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T other_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++} // namespace mapping+} // namespace detail++typedef detail::mapping_t<> mapping_t;++#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr mapping_t mapping;+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+namespace { static const mapping_t& mapping = mapping_t::instance; }+#endif++} // namespace execution++#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+struct is_applicable_property<T, execution::mapping_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::mapping_t::thread_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::mapping_t::new_thread_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::mapping_t::other_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++template <typename T>+struct query_free_default<T, execution::mapping_t,+ typename enable_if<+ can_query<T, execution::mapping_t::thread_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::mapping_t::thread_t>::value));++ typedef execution::mapping_t result_type;+};++template <typename T>+struct query_free_default<T, execution::mapping_t,+ typename enable_if<+ !can_query<T, execution::mapping_t::thread_t>::value+ && can_query<T, execution::mapping_t::new_thread_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::mapping_t::new_thread_t>::value));++ typedef execution::mapping_t result_type;+};++template <typename T>+struct query_free_default<T, execution::mapping_t,+ typename enable_if<+ !can_query<T, execution::mapping_t::thread_t>::value+ && !can_query<T, execution::mapping_t::new_thread_t>::value+ && can_query<T, execution::mapping_t::other_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::mapping_t::other_t>::value));++ typedef execution::mapping_t result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename T>+struct static_query<T, execution::mapping_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::mapping_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::mapping_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::mapping_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::mapping_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T, execution::mapping_t>::is_valid+ && !traits::query_member<T, execution::mapping_t>::is_valid+ && traits::static_query<T, execution::mapping_t::thread_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::mapping_t::thread_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T, execution::mapping_t::thread_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::mapping_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T, execution::mapping_t>::is_valid+ && !traits::query_member<T, execution::mapping_t>::is_valid+ && !traits::static_query<T, execution::mapping_t::thread_t>::is_valid+ && traits::static_query<T, execution::mapping_t::new_thread_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::mapping_t::new_thread_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T, execution::mapping_t::new_thread_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::mapping_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T, execution::mapping_t>::is_valid+ && !traits::query_member<T, execution::mapping_t>::is_valid+ && !traits::static_query<T, execution::mapping_t::thread_t>::is_valid+ && !traits::static_query<T, execution::mapping_t::new_thread_t>::is_valid+ && traits::static_query<T, execution::mapping_t::other_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::mapping_t::other_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T, execution::mapping_t::other_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::mapping_t::thread_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::mapping_t::thread_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::mapping_t::thread_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::mapping_t::thread_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::mapping_t::thread_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::mapping_t::thread_t>::is_valid+ && !traits::query_member<T, execution::mapping_t::thread_t>::is_valid+ && !traits::query_free<T, execution::mapping_t::thread_t>::is_valid+ && !can_query<T, execution::mapping_t::new_thread_t>::value+ && !can_query<T, execution::mapping_t::other_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef execution::mapping_t::thread_t result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return result_type();+ }+};++template <typename T>+struct static_query<T, execution::mapping_t::new_thread_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::mapping_t::new_thread_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::mapping_t::new_thread_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::mapping_t::new_thread_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::mapping_t::other_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::mapping_t::other_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::mapping_t::other_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::mapping_t::other_t>::value();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++template <typename T>+struct static_require<T, execution::mapping_t::thread_t,+ typename enable_if<+ static_query<T, execution::mapping_t::thread_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::mapping_t::thread_t>::result_type,+ execution::mapping_t::thread_t>::value));+};++template <typename T>+struct static_require<T, execution::mapping_t::new_thread_t,+ typename enable_if<+ static_query<T, execution::mapping_t::new_thread_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::mapping_t::new_thread_t>::result_type,+ execution::mapping_t::new_thread_t>::value));+};++template <typename T>+struct static_require<T, execution::mapping_t::other_t,+ typename enable_if<+ static_query<T, execution::mapping_t::other_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::mapping_t::other_t>::result_type,+ execution::mapping_t::other_t>::value));+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_MAPPING_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/occupancy.hpp view
@@ -0,0 +1,178 @@+//+// execution/occupancy.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_OCCUPANCY_HPP+#define ASIO_EXECUTION_OCCUPANCY_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/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/is_applicable_property.hpp"+#include "asio/traits/query_static_constexpr_member.hpp"+#include "asio/traits/static_query.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// A property that gives an estimate of the number of execution agents that+/// should occupy the associated execution context.+struct occupancy_t+{+ /// The occupancy_t property applies to executors, senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The occupancy_t property cannot be required.+ static constexpr bool is_requirable = false;++ /// The occupancy_t property cannot be preferred.+ static constexpr bool is_preferable = false;++ /// The type returned by queries against an @c any_executor.+ typedef std::size_t polymorphic_query_result_type;+};++/// A special value used for accessing the occupancy_t property.+constexpr occupancy_t occupancy;++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {+namespace detail {++template <int I = 0>+struct occupancy_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);+ typedef std::size_t polymorphic_query_result_type;++ ASIO_CONSTEXPR occupancy_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, occupancy_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, occupancy_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, occupancy_t>::value();+ }++ template <typename E, typename T = decltype(occupancy_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = occupancy_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_CONSTEXPR)+ static const occupancy_t instance;+#endif // !defined(ASIO_HAS_CONSTEXPR)+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T occupancy_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_CONSTEXPR)+template <int I>+const occupancy_t<I> occupancy_t<I>::instance;+#endif++} // namespace detail++typedef detail::occupancy_t<> occupancy_t;++#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr occupancy_t occupancy;+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+namespace { static const occupancy_t& occupancy = occupancy_t::instance; }+#endif++} // namespace execution++#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+struct is_applicable_property<T, execution::occupancy_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename T>+struct static_query<T, execution::occupancy_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::occupancy_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::occupancy_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::occupancy_t>::value();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_OCCUPANCY_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/operation_state.hpp view
@@ -0,0 +1,94 @@+//+// execution/operation_state.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_OPERATION_STATE_HPP+#define ASIO_EXECUTION_OPERATION_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/detail/type_traits.hpp"+#include "asio/execution/start.hpp"++#if defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT) \+ && defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)+# define ASIO_HAS_DEDUCED_EXECUTION_IS_OPERATION_STATE_TRAIT 1+#endif // defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT)+ // && defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {+namespace detail {++template <typename T>+struct is_operation_state_base :+ integral_constant<bool,+ is_destructible<T>::value+ && is_object<T>::value+ >+{+};++} // namespace detail++/// The is_operation_state trait detects whether a type T satisfies the+/// execution::operation_state concept.+/**+ * Class template @c is_operation_state is a type trait that is derived from+ * @c true_type if the type @c T meets the concept definition for an+ * @c operation_state, otherwise @c false_type.+ */+template <typename T>+struct is_operation_state :+#if defined(GENERATING_DOCUMENTATION)+ integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ conditional<+ can_start<typename add_lvalue_reference<T>::type>::value+ && is_nothrow_start<typename add_lvalue_reference<T>::type>::value,+ detail::is_operation_state_base<T>,+ false_type+ >::type+#endif // defined(GENERATING_DOCUMENTATION)+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+ASIO_CONSTEXPR const bool is_operation_state_v =+ is_operation_state<T>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_CONCEPTS)++template <typename T>+ASIO_CONCEPT operation_state = is_operation_state<T>::value;++#define ASIO_EXECUTION_OPERATION_STATE \+ ::asio::execution::operation_state++#else // defined(ASIO_HAS_CONCEPTS)++#define ASIO_EXECUTION_OPERATION_STATE typename++#endif // defined(ASIO_HAS_CONCEPTS)++} // namespace execution+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_OPERATION_STATE_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/outstanding_work.hpp view
@@ -0,0 +1,721 @@+//+// execution/outstanding_work.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_OUTSTANDING_WORK_HPP+#define ASIO_EXECUTION_OUTSTANDING_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/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/is_applicable_property.hpp"+#include "asio/query.hpp"+#include "asio/traits/query_free.hpp"+#include "asio/traits/query_member.hpp"+#include "asio/traits/query_static_constexpr_member.hpp"+#include "asio/traits/static_query.hpp"+#include "asio/traits/static_require.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// A property to describe whether task submission is likely in the future.+struct outstanding_work_t+{+ /// The outstanding_work_t property applies to executors, senders, and+ /// schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The top-level outstanding_work_t property cannot be required.+ static constexpr bool is_requirable = false;++ /// The top-level outstanding_work_t property cannot be preferred.+ static constexpr bool is_preferable = false;++ /// The type returned by queries against an @c any_executor.+ typedef outstanding_work_t polymorphic_query_result_type;++ /// A sub-property that indicates that the executor does not represent likely+ /// future submission of a function object.+ struct untracked_t+ {+ /// The outstanding_work_t::untracked_t property applies to executors,+ /// senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The outstanding_work_t::untracked_t property can be required.+ static constexpr bool is_requirable = true;++ /// The outstanding_work_t::untracked_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef outstanding_work_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr untracked_t();++ /// Get the value associated with a property object.+ /**+ * @returns untracked_t();+ */+ static constexpr outstanding_work_t value();+ };++ /// A sub-property that indicates that the executor represents likely+ /// future submission of a function object.+ struct tracked_t+ {+ /// The outstanding_work_t::untracked_t property applies to executors,+ /// senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The outstanding_work_t::tracked_t property can be required.+ static constexpr bool is_requirable = true;++ /// The outstanding_work_t::tracked_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef outstanding_work_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr tracked_t();++ /// Get the value associated with a property object.+ /**+ * @returns tracked_t();+ */+ static constexpr outstanding_work_t value();+ };++ /// A special value used for accessing the outstanding_work_t::untracked_t+ /// property.+ static constexpr untracked_t untracked;++ /// A special value used for accessing the outstanding_work_t::tracked_t+ /// property.+ static constexpr tracked_t tracked;++ /// Default constructor.+ constexpr outstanding_work_t();++ /// Construct from a sub-property value.+ constexpr outstanding_work_t(untracked_t);++ /// Construct from a sub-property value.+ constexpr outstanding_work_t(tracked_t);++ /// Compare property values for equality.+ friend constexpr bool operator==(+ const outstanding_work_t& a, const outstanding_work_t& b) noexcept;++ /// Compare property values for inequality.+ friend constexpr bool operator!=(+ const outstanding_work_t& a, const outstanding_work_t& b) noexcept;+};++/// A special value used for accessing the outstanding_work_t property.+constexpr outstanding_work_t outstanding_work;++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {+namespace detail {+namespace outstanding_work {++template <int I> struct untracked_t;+template <int I> struct tracked_t;++} // namespace outstanding_work++template <int I = 0>+struct outstanding_work_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);+ typedef outstanding_work_t polymorphic_query_result_type;++ typedef detail::outstanding_work::untracked_t<I> untracked_t;+ typedef detail::outstanding_work::tracked_t<I> tracked_t;++ ASIO_CONSTEXPR outstanding_work_t()+ : value_(-1)+ {+ }++ ASIO_CONSTEXPR outstanding_work_t(untracked_t)+ : value_(0)+ {+ }++ ASIO_CONSTEXPR outstanding_work_t(tracked_t)+ : value_(1)+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<+ T, outstanding_work_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<+ T, outstanding_work_t+ >::is_noexcept))+ {+ return traits::query_static_constexpr_member<+ T, outstanding_work_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, untracked_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<+ T, outstanding_work_t>::is_valid+ && !traits::query_member<T, outstanding_work_t>::is_valid+ && traits::static_query<T, untracked_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, untracked_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, tracked_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<+ T, outstanding_work_t>::is_valid+ && !traits::query_member<T, outstanding_work_t>::is_valid+ && !traits::static_query<T, untracked_t>::is_valid+ && traits::static_query<T, tracked_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, tracked_t>::value();+ }++ template <typename E,+ typename T = decltype(outstanding_work_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = outstanding_work_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ friend ASIO_CONSTEXPR bool operator==(+ const outstanding_work_t& a, const outstanding_work_t& b)+ {+ return a.value_ == b.value_;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const outstanding_work_t& a, const outstanding_work_t& b)+ {+ return a.value_ != b.value_;+ }++ struct convertible_from_outstanding_work_t+ {+ ASIO_CONSTEXPR convertible_from_outstanding_work_t(outstanding_work_t)+ {+ }+ };++ template <typename Executor>+ friend ASIO_CONSTEXPR outstanding_work_t query(+ const Executor& ex, convertible_from_outstanding_work_t,+ typename enable_if<+ can_query<const Executor&, untracked_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&,+ outstanding_work_t<>::untracked_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, untracked_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, untracked_t());+ }++ template <typename Executor>+ friend ASIO_CONSTEXPR outstanding_work_t query(+ const Executor& ex, convertible_from_outstanding_work_t,+ typename enable_if<+ !can_query<const Executor&, untracked_t>::value+ && can_query<const Executor&, tracked_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&,+ outstanding_work_t<>::tracked_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, tracked_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, tracked_t());+ }++ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(untracked_t, untracked);+ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(tracked_t, tracked);++#if !defined(ASIO_HAS_CONSTEXPR)+ static const outstanding_work_t instance;+#endif // !defined(ASIO_HAS_CONSTEXPR)++private:+ int value_;+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T outstanding_work_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_CONSTEXPR)+template <int I>+const outstanding_work_t<I> outstanding_work_t<I>::instance;+#endif++template <int I>+const typename outstanding_work_t<I>::untracked_t+outstanding_work_t<I>::untracked;++template <int I>+const typename outstanding_work_t<I>::tracked_t+outstanding_work_t<I>::tracked;++namespace outstanding_work {++template <int I = 0>+struct untracked_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef outstanding_work_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR untracked_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, untracked_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, untracked_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, untracked_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR untracked_t static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, untracked_t>::is_valid+ && !traits::query_member<T, untracked_t>::is_valid+ && !traits::query_free<T, untracked_t>::is_valid+ && !can_query<T, tracked_t<I> >::value+ >::type* = 0) ASIO_NOEXCEPT+ {+ return untracked_t();+ }++ template <typename E, typename T = decltype(untracked_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = untracked_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR outstanding_work_t<I> value()+ {+ return untracked_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const untracked_t&, const untracked_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const untracked_t&, const untracked_t&)+ {+ return false;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T untracked_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <int I = 0>+struct tracked_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef outstanding_work_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR tracked_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, tracked_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, tracked_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, tracked_t>::value();+ }++ template <typename E, typename T = decltype(tracked_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = tracked_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR outstanding_work_t<I> value()+ {+ return tracked_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const tracked_t&, const tracked_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const tracked_t&, const tracked_t&)+ {+ return false;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T tracked_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++} // namespace outstanding_work+} // namespace detail++typedef detail::outstanding_work_t<> outstanding_work_t;++#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr outstanding_work_t outstanding_work;+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+namespace { static const outstanding_work_t&+ outstanding_work = outstanding_work_t::instance; }+#endif++} // namespace execution++#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+struct is_applicable_property<T, execution::outstanding_work_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::outstanding_work_t::untracked_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::outstanding_work_t::tracked_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++template <typename T>+struct query_free_default<T, execution::outstanding_work_t,+ typename enable_if<+ can_query<T, execution::outstanding_work_t::untracked_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::outstanding_work_t::untracked_t>::value));++ typedef execution::outstanding_work_t result_type;+};++template <typename T>+struct query_free_default<T, execution::outstanding_work_t,+ typename enable_if<+ !can_query<T, execution::outstanding_work_t::untracked_t>::value+ && can_query<T, execution::outstanding_work_t::tracked_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::outstanding_work_t::tracked_t>::value));++ typedef execution::outstanding_work_t result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename T>+struct static_query<T, execution::outstanding_work_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::outstanding_work_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::outstanding_work_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::outstanding_work_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::outstanding_work_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::outstanding_work_t>::is_valid+ && !traits::query_member<T,+ execution::outstanding_work_t>::is_valid+ && traits::static_query<T,+ execution::outstanding_work_t::untracked_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::outstanding_work_t::untracked_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T,+ execution::outstanding_work_t::untracked_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::outstanding_work_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::outstanding_work_t>::is_valid+ && !traits::query_member<T,+ execution::outstanding_work_t>::is_valid+ && !traits::static_query<T,+ execution::outstanding_work_t::untracked_t>::is_valid+ && traits::static_query<T,+ execution::outstanding_work_t::tracked_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::outstanding_work_t::tracked_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T,+ execution::outstanding_work_t::tracked_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::outstanding_work_t::untracked_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::outstanding_work_t::untracked_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::outstanding_work_t::untracked_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::outstanding_work_t::untracked_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::outstanding_work_t::untracked_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::outstanding_work_t::untracked_t>::is_valid+ && !traits::query_member<T,+ execution::outstanding_work_t::untracked_t>::is_valid+ && !traits::query_free<T,+ execution::outstanding_work_t::untracked_t>::is_valid+ && !can_query<T, execution::outstanding_work_t::tracked_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef execution::outstanding_work_t::untracked_t result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return result_type();+ }+};++template <typename T>+struct static_query<T, execution::outstanding_work_t::tracked_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::outstanding_work_t::tracked_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::outstanding_work_t::tracked_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::outstanding_work_t::tracked_t>::value();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++template <typename T>+struct static_require<T, execution::outstanding_work_t::untracked_t,+ typename enable_if<+ static_query<T, execution::outstanding_work_t::untracked_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::outstanding_work_t::untracked_t>::result_type,+ execution::outstanding_work_t::untracked_t>::value));+};++template <typename T>+struct static_require<T, execution::outstanding_work_t::tracked_t,+ typename enable_if<+ static_query<T, execution::outstanding_work_t::tracked_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::outstanding_work_t::tracked_t>::result_type,+ execution::outstanding_work_t::tracked_t>::value));+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_OUTSTANDING_WORK_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/prefer_only.hpp view
@@ -0,0 +1,327 @@+//+// execution/prefer_only.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_PREFER_ONLY_HPP+#define ASIO_EXECUTION_PREFER_ONLY_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/is_applicable_property.hpp"+#include "asio/prefer.hpp"+#include "asio/query.hpp"+#include "asio/traits/static_query.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// A property adapter that is used with the polymorphic executor wrapper+/// to mark properties as preferable, but not requirable.+template <typename Property>+struct prefer_only+{+ /// The prefer_only adapter applies to the same types as the nested property.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_applicable_property<T, Property>::value;++ /// The context_t property cannot be required.+ static constexpr bool is_requirable = false;++ /// The context_t property can be preferred, it the underlying property can+ /// be preferred.+ /**+ * @c true if @c Property::is_preferable is @c true, otherwise @c false.+ */+ static constexpr bool is_preferable = automatically_determined;++ /// The type returned by queries against an @c any_executor.+ typedef typename Property::polymorphic_query_result_type+ polymorphic_query_result_type;+};++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {+namespace detail {++template <typename InnerProperty, typename = void>+struct prefer_only_is_preferable+{+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);+};++template <typename InnerProperty>+struct prefer_only_is_preferable<InnerProperty,+ typename enable_if<+ InnerProperty::is_preferable+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+};++template <typename InnerProperty, typename = void>+struct prefer_only_polymorphic_query_result_type+{+};++template <typename InnerProperty>+struct prefer_only_polymorphic_query_result_type<InnerProperty,+ typename void_type<+ typename InnerProperty::polymorphic_query_result_type+ >::type>+{+ typedef typename InnerProperty::polymorphic_query_result_type+ polymorphic_query_result_type;+};++template <typename InnerProperty, typename = void>+struct prefer_only_property+{+ InnerProperty property;++ prefer_only_property(const InnerProperty& p)+ : property(p)+ {+ }+};++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++template <typename InnerProperty>+struct prefer_only_property<InnerProperty,+ typename void_type<+ decltype(asio::declval<const InnerProperty>().value())+ >::type>+{+ InnerProperty property;++ prefer_only_property(const InnerProperty& p)+ : property(p)+ {+ }++ ASIO_CONSTEXPR auto value() const+ ASIO_NOEXCEPT_IF((+ noexcept(asio::declval<const InnerProperty>().value())))+ -> decltype(asio::declval<const InnerProperty>().value())+ {+ return property.value();+ }+};++#else // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++struct prefer_only_memfns_base+{+ void value();+};++template <typename T>+struct prefer_only_memfns_derived+ : T, prefer_only_memfns_base+{+};++template <typename T, T>+struct prefer_only_memfns_check+{+};++template <typename>+char (&prefer_only_value_memfn_helper(...))[2];++template <typename T>+char prefer_only_value_memfn_helper(+ prefer_only_memfns_check<+ void (prefer_only_memfns_base::*)(),+ &prefer_only_memfns_derived<T>::value>*);++template <typename InnerProperty>+struct prefer_only_property<InnerProperty,+ typename enable_if<+ sizeof(prefer_only_value_memfn_helper<InnerProperty>(0)) != 1+ && !is_same<typename InnerProperty::polymorphic_query_result_type,+ void>::value+ >::type>+{+ InnerProperty property;++ prefer_only_property(const InnerProperty& p)+ : property(p)+ {+ }++ ASIO_CONSTEXPR typename InnerProperty::polymorphic_query_result_type+ value() const+ {+ return property.value();+ }+};++#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++} // namespace detail++template <typename InnerProperty>+struct prefer_only :+ detail::prefer_only_is_preferable<InnerProperty>,+ detail::prefer_only_polymorphic_query_result_type<InnerProperty>,+ detail::prefer_only_property<InnerProperty>+{+ ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);++ ASIO_CONSTEXPR prefer_only(const InnerProperty& p)+ : detail::prefer_only_property<InnerProperty>(p)+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, InnerProperty>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::static_query<T, InnerProperty>::is_noexcept))+ {+ return traits::static_query<T, InnerProperty>::value();+ }++ template <typename E, typename T = decltype(prefer_only::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = prefer_only::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ template <typename Executor, typename Property>+ friend ASIO_CONSTEXPR+ typename prefer_result<const Executor&, const InnerProperty&>::type+ prefer(const Executor& ex, const prefer_only<Property>& p,+ typename enable_if<+ is_same<Property, InnerProperty>::value+ && can_prefer<const Executor&, const InnerProperty&>::value+ >::type* = 0)+#if !defined(ASIO_MSVC) \+ && !defined(__clang__) // Clang crashes if noexcept is used here.+ ASIO_NOEXCEPT_IF((+ is_nothrow_prefer<const Executor&, const InnerProperty&>::value))+#endif // !defined(ASIO_MSVC)+ // && !defined(__clang__)+ {+ return asio::prefer(ex, p.property);+ }++ template <typename Executor, typename Property>+ friend ASIO_CONSTEXPR+ typename query_result<const Executor&, const InnerProperty&>::type+ query(const Executor& ex, const prefer_only<Property>& p,+ typename enable_if<+ is_same<Property, InnerProperty>::value+ && can_query<const Executor&, const InnerProperty&>::value+ >::type* = 0)+#if !defined(ASIO_MSVC) \+ && !defined(__clang__) // Clang crashes if noexcept is used here.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, const InnerProperty&>::value))+#endif // !defined(ASIO_MSVC)+ // && !defined(__clang__)+ {+ return asio::query(ex, p.property);+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <typename InnerProperty> template <typename E, typename T>+const T prefer_only<InnerProperty>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++} // namespace execution++template <typename T, typename InnerProperty>+struct is_applicable_property<T, execution::prefer_only<InnerProperty> >+ : is_applicable_property<T, InnerProperty>+{+};++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename T, typename InnerProperty>+struct static_query<T, execution::prefer_only<InnerProperty> > :+ static_query<T, const InnerProperty&>+{+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)++template <typename T, typename InnerProperty>+struct prefer_free_default<T, execution::prefer_only<InnerProperty>,+ typename enable_if<+ can_prefer<const T&, const InnerProperty&>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_prefer<const T&, const InnerProperty&>::value));++ typedef typename prefer_result<const T&,+ const InnerProperty&>::type result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++template <typename T, typename InnerProperty>+struct query_free<T, execution::prefer_only<InnerProperty>,+ typename enable_if<+ can_query<const T&, const InnerProperty&>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<const T&, const InnerProperty&>::value));++ typedef typename query_result<const T&,+ const InnerProperty&>::type result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_PREFER_ONLY_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/receiver.hpp view
@@ -0,0 +1,280 @@+//+// execution/receiver.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_RECEIVER_HPP+#define ASIO_EXECUTION_RECEIVER_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/variadic_templates.hpp"+#include "asio/execution/set_done.hpp"+#include "asio/execution/set_error.hpp"+#include "asio/execution/set_value.hpp"++#if defined(ASIO_HAS_STD_EXCEPTION_PTR)+# include <exception>+#else // defined(ASIO_HAS_STD_EXCEPTION_PTR)+# include "asio/error_code.hpp"+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)++#if defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT) \+ && defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) \+ && defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT) \+ && defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) \+ && defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT) \+ && defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) \+ && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_FREE_TRAIT) \+ && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_MEMBER_TRAIT)+# define ASIO_HAS_DEDUCED_EXECUTION_IS_RECEIVER_TRAIT 1+#endif // defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT)+ // && defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)+ // && defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT)+ // && defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)+ // && defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT)+ // && defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)+ // && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_FREE_TRAIT)+ // && defined(ASIO_HAS_DEDUCED_RECEIVER_OF_MEMBER_TRAIT)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {+namespace detail {++template <typename T, typename E>+struct is_receiver_base :+ integral_constant<bool,+ is_move_constructible<typename remove_cvref<T>::type>::value+ && is_constructible<typename remove_cvref<T>::type, T>::value+ >+{+};++} // namespace detail++#if defined(ASIO_HAS_STD_EXCEPTION_PTR)+# define ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT = std::exception_ptr+#else // defined(ASIO_HAS_STD_EXCEPTION_PTR)+# define ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT \+ = ::asio::error_code+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)++/// The is_receiver trait detects whether a type T satisfies the+/// execution::receiver concept.+/**+ * Class template @c is_receiver is a type trait that is derived from @c+ * true_type if the type @c T meets the concept definition for a receiver for+ * error type @c E, otherwise @c false_type.+ */+template <typename T, typename E ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT>+struct is_receiver :+#if defined(GENERATING_DOCUMENTATION)+ integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ conditional<+ can_set_done<typename remove_cvref<T>::type>::value+ && is_nothrow_set_done<typename remove_cvref<T>::type>::value+ && can_set_error<typename remove_cvref<T>::type, E>::value+ && is_nothrow_set_error<typename remove_cvref<T>::type, E>::value,+ detail::is_receiver_base<T, E>,+ false_type+ >::type+#endif // defined(GENERATING_DOCUMENTATION)+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename E ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT>+ASIO_CONSTEXPR const bool is_receiver_v = is_receiver<T, E>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_CONCEPTS)++template <typename T, typename E ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT>+ASIO_CONCEPT receiver = is_receiver<T, E>::value;++#define ASIO_EXECUTION_RECEIVER ::asio::execution::receiver++#else // defined(ASIO_HAS_CONCEPTS)++#define ASIO_EXECUTION_RECEIVER typename++#endif // defined(ASIO_HAS_CONCEPTS)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \+ || defined(GENERATING_DOCUMENTATION)++/// The is_receiver_of trait detects whether a type T satisfies the+/// execution::receiver_of concept for some set of value arguments.+/**+ * Class template @c is_receiver_of is a type trait that is derived from @c+ * true_type if the type @c T meets the concept definition for a receiver for+ * value arguments @c Vs, otherwise @c false_type.+ */+template <typename T, typename... Vs>+struct is_receiver_of :+#if defined(GENERATING_DOCUMENTATION)+ integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ conditional<+ is_receiver<T>::value,+ can_set_value<typename remove_cvref<T>::type, Vs...>,+ false_type+ >::type+#endif // defined(GENERATING_DOCUMENTATION)+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename... Vs>+ASIO_CONSTEXPR const bool is_receiver_of_v =+ is_receiver_of<T, Vs...>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_CONCEPTS)++template <typename T, typename... Vs>+ASIO_CONCEPT receiver_of = is_receiver_of<T, Vs...>::value;++#define ASIO_EXECUTION_RECEIVER_OF_0 \+ ::asio::execution::receiver_of++#define ASIO_EXECUTION_RECEIVER_OF_1(v) \+ ::asio::execution::receiver_of<v>++#else // defined(ASIO_HAS_CONCEPTS)++#define ASIO_EXECUTION_RECEIVER_OF_0 typename+#define ASIO_EXECUTION_RECEIVER_OF_1(v) typename++#endif // defined(ASIO_HAS_CONCEPTS)++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)++template <typename T, typename = void,+ typename = void, typename = void, typename = void, typename = void,+ typename = void, typename = void, typename = void, typename = void>+struct is_receiver_of;++template <typename T>+struct is_receiver_of<T> :+ conditional<+ is_receiver<T>::value,+ can_set_value<typename remove_cvref<T>::type>,+ false_type+ >::type+{+};++#define ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF(n) \+ template <typename T, ASIO_VARIADIC_TPARAMS(n)> \+ struct is_receiver_of<T, ASIO_VARIADIC_TARGS(n)> : \+ conditional< \+ conditional<true, is_receiver<T>, void>::type::value, \+ can_set_value< \+ typename remove_cvref<T>::type, \+ ASIO_VARIADIC_TARGS(n)>, \+ false_type \+ >::type \+ { \+ }; \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF)+#undef ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF++#define ASIO_EXECUTION_RECEIVER_OF_0 typename+#define ASIO_EXECUTION_RECEIVER_OF_1(v) typename++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \+ || defined(GENERATING_DOCUMENTATION)++/// The is_nothrow_receiver_of trait detects whether a type T satisfies the+/// execution::receiver_of concept for some set of value arguments, with a+/// noexcept @c set_value operation.+/**+ * Class template @c is_nothrow_receiver_of is a type trait that is derived+ * from @c true_type if the type @c T meets the concept definition for a+ * receiver for value arguments @c Vs, and the expression+ * <tt>execution::set_value(declval<T>(), declval<Ts>()...)</tt> is noexcept,+ * otherwise @c false_type.+ */+template <typename T, typename... Vs>+struct is_nothrow_receiver_of :+#if defined(GENERATING_DOCUMENTATION)+ integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ integral_constant<bool,+ is_receiver_of<T, Vs...>::value+ && is_nothrow_set_value<typename remove_cvref<T>::type, Vs...>::value+ >+#endif // defined(GENERATING_DOCUMENTATION)+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename... Vs>+ASIO_CONSTEXPR const bool is_nothrow_receiver_of_v =+ is_nothrow_receiver_of<T, Vs...>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)++template <typename T, typename = void,+ typename = void, typename = void, typename = void, typename = void,+ typename = void, typename = void, typename = void, typename = void>+struct is_nothrow_receiver_of;++template <typename T>+struct is_nothrow_receiver_of<T> :+ integral_constant<bool,+ is_receiver_of<T>::value+ && is_nothrow_set_value<typename remove_cvref<T>::type>::value+ >+{+};++#define ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF(n) \+ template <typename T, ASIO_VARIADIC_TPARAMS(n)> \+ struct is_nothrow_receiver_of<T, ASIO_VARIADIC_TARGS(n)> : \+ integral_constant<bool, \+ is_receiver_of<T, ASIO_VARIADIC_TARGS(n)>::value \+ && is_nothrow_set_value<typename remove_cvref<T>::type, \+ ASIO_VARIADIC_TARGS(n)>::value \+ > \+ { \+ }; \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF)+#undef ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)++} // namespace execution+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_RECEIVER_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/receiver_invocation_error.hpp view
@@ -0,0 +1,48 @@+//+// execution/receiver_invocation_error.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_RECEIVER_INVOCATION_ERROR_HPP+#define ASIO_EXECUTION_RECEIVER_INVOCATION_ERROR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <stdexcept>++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {++/// Exception reported via @c set_error when an exception escapes from+/// @c set_value.+class receiver_invocation_error+ : public std::runtime_error+#if defined(ASIO_HAS_STD_NESTED_EXCEPTION)+ , public std::nested_exception+#endif // defined(ASIO_HAS_STD_NESTED_EXCEPTION)+{+public:+ /// Constructor.+ ASIO_DECL receiver_invocation_error();+};++} // namespace execution+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/execution/impl/receiver_invocation_error.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_EXECUTION_RECEIVER_INVOCATION_ERROR_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/relationship.hpp view
@@ -0,0 +1,720 @@+//+// execution/relationship.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_RELATIONSHIP_HPP+#define ASIO_EXECUTION_RELATIONSHIP_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/scheduler.hpp"+#include "asio/execution/sender.hpp"+#include "asio/is_applicable_property.hpp"+#include "asio/query.hpp"+#include "asio/traits/query_free.hpp"+#include "asio/traits/query_member.hpp"+#include "asio/traits/query_static_constexpr_member.hpp"+#include "asio/traits/static_query.hpp"+#include "asio/traits/static_require.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(GENERATING_DOCUMENTATION)++namespace execution {++/// A property to describe whether submitted tasks represent continuations of+/// the calling context.+struct relationship_t+{+ /// The relationship_t property applies to executors, senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The top-level relationship_t property cannot be required.+ static constexpr bool is_requirable = false;++ /// The top-level relationship_t property cannot be preferred.+ static constexpr bool is_preferable = false;++ /// The type returned by queries against an @c any_executor.+ typedef relationship_t polymorphic_query_result_type;++ /// A sub-property that indicates that the executor does not represent a+ /// continuation of the calling context.+ struct fork_t+ {+ /// The relationship_t::fork_t property applies to executors, senders, and+ /// schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The relationship_t::fork_t property can be required.+ static constexpr bool is_requirable = true;++ /// The relationship_t::fork_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef relationship_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr fork_t();++ /// Get the value associated with a property object.+ /**+ * @returns fork_t();+ */+ static constexpr relationship_t value();+ };++ /// A sub-property that indicates that the executor represents a continuation+ /// of the calling context.+ struct continuation_t+ {+ /// The relationship_t::continuation_t property applies to executors,+ /// senders, and schedulers.+ template <typename T>+ static constexpr bool is_applicable_property_v =+ is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;++ /// The relationship_t::continuation_t property can be required.+ static constexpr bool is_requirable = true;++ /// The relationship_t::continuation_t property can be preferred.+ static constexpr bool is_preferable = true;++ /// The type returned by queries against an @c any_executor.+ typedef relationship_t polymorphic_query_result_type;++ /// Default constructor.+ constexpr continuation_t();++ /// Get the value associated with a property object.+ /**+ * @returns continuation_t();+ */+ static constexpr relationship_t value();+ };++ /// A special value used for accessing the relationship_t::fork_t property.+ static constexpr fork_t fork;++ /// A special value used for accessing the relationship_t::continuation_t+ /// property.+ static constexpr continuation_t continuation;++ /// Default constructor.+ constexpr relationship_t();++ /// Construct from a sub-property value.+ constexpr relationship_t(fork_t);++ /// Construct from a sub-property value.+ constexpr relationship_t(continuation_t);++ /// Compare property values for equality.+ friend constexpr bool operator==(+ const relationship_t& a, const relationship_t& b) noexcept;++ /// Compare property values for inequality.+ friend constexpr bool operator!=(+ const relationship_t& a, const relationship_t& b) noexcept;+};++/// A special value used for accessing the relationship_t property.+constexpr relationship_t relationship;++} // namespace execution++#else // defined(GENERATING_DOCUMENTATION)++namespace execution {+namespace detail {+namespace relationship {++template <int I> struct fork_t;+template <int I> struct continuation_t;++} // namespace relationship++template <int I = 0>+struct relationship_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);+ typedef relationship_t polymorphic_query_result_type;++ typedef detail::relationship::fork_t<I> fork_t;+ typedef detail::relationship::continuation_t<I> continuation_t;++ ASIO_CONSTEXPR relationship_t()+ : value_(-1)+ {+ }++ ASIO_CONSTEXPR relationship_t(fork_t)+ : value_(0)+ {+ }++ ASIO_CONSTEXPR relationship_t(continuation_t)+ : value_(1)+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<+ T, relationship_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<+ T, relationship_t+ >::is_noexcept))+ {+ return traits::query_static_constexpr_member<+ T, relationship_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, fork_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<+ T, relationship_t>::is_valid+ && !traits::query_member<T, relationship_t>::is_valid+ && traits::static_query<T, fork_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, fork_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::static_query<T, continuation_t>::result_type+ static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<+ T, relationship_t>::is_valid+ && !traits::query_member<T, relationship_t>::is_valid+ && !traits::static_query<T, fork_t>::is_valid+ && traits::static_query<T, continuation_t>::is_valid+ >::type* = 0) ASIO_NOEXCEPT+ {+ return traits::static_query<T, continuation_t>::value();+ }++ template <typename E,+ typename T = decltype(relationship_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = relationship_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ friend ASIO_CONSTEXPR bool operator==(+ const relationship_t& a, const relationship_t& b)+ {+ return a.value_ == b.value_;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const relationship_t& a, const relationship_t& b)+ {+ return a.value_ != b.value_;+ }++ struct convertible_from_relationship_t+ {+ ASIO_CONSTEXPR convertible_from_relationship_t(relationship_t)+ {+ }+ };++ template <typename Executor>+ friend ASIO_CONSTEXPR relationship_t query(+ const Executor& ex, convertible_from_relationship_t,+ typename enable_if<+ can_query<const Executor&, fork_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, relationship_t<>::fork_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, fork_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, fork_t());+ }++ template <typename Executor>+ friend ASIO_CONSTEXPR relationship_t query(+ const Executor& ex, convertible_from_relationship_t,+ typename enable_if<+ !can_query<const Executor&, fork_t>::value+ && can_query<const Executor&, continuation_t>::value+ >::type* = 0)+#if !defined(__clang__) // Clang crashes if noexcept is used here.+#if defined(ASIO_MSVC) // Visual C++ wants the type to be qualified.+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&,+ relationship_t<>::continuation_t>::value))+#else // defined(ASIO_MSVC)+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, continuation_t>::value))+#endif // defined(ASIO_MSVC)+#endif // !defined(__clang__)+ {+ return asio::query(ex, continuation_t());+ }++ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(fork_t, fork);+ ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(continuation_t, continuation);++#if !defined(ASIO_HAS_CONSTEXPR)+ static const relationship_t instance;+#endif // !defined(ASIO_HAS_CONSTEXPR)++private:+ int value_;+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T relationship_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_CONSTEXPR)+template <int I>+const relationship_t<I> relationship_t<I>::instance;+#endif++template <int I>+const typename relationship_t<I>::fork_t+relationship_t<I>::fork;++template <int I>+const typename relationship_t<I>::continuation_t+relationship_t<I>::continuation;++namespace relationship {++template <int I = 0>+struct fork_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef relationship_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR fork_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, fork_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, fork_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, fork_t>::value();+ }++ template <typename T>+ static ASIO_CONSTEXPR fork_t static_query(+ typename enable_if<+ !traits::query_static_constexpr_member<T, fork_t>::is_valid+ && !traits::query_member<T, fork_t>::is_valid+ && !traits::query_free<T, fork_t>::is_valid+ && !can_query<T, continuation_t<I> >::value+ >::type* = 0) ASIO_NOEXCEPT+ {+ return fork_t();+ }++ template <typename E, typename T = decltype(fork_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = fork_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR relationship_t<I> value()+ {+ return fork_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const fork_t&, const fork_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const fork_t&, const fork_t&)+ {+ return false;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T fork_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <int I = 0>+struct continuation_t+{+#if defined(ASIO_HAS_VARIABLE_TEMPLATES)+ template <typename T>+ ASIO_STATIC_CONSTEXPR(bool,+ is_applicable_property_v = is_executor<T>::value+ || is_sender<T>::value || is_scheduler<T>::value);+#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++ ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);+ ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);+ typedef relationship_t<I> polymorphic_query_result_type;++ ASIO_CONSTEXPR continuation_t()+ {+ }++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+ template <typename T>+ static ASIO_CONSTEXPR+ typename traits::query_static_constexpr_member<T, continuation_t>::result_type+ static_query()+ ASIO_NOEXCEPT_IF((+ traits::query_static_constexpr_member<T, continuation_t>::is_noexcept))+ {+ return traits::query_static_constexpr_member<T, continuation_t>::value();+ }++ template <typename E,+ typename T = decltype(continuation_t::static_query<E>())>+ static ASIO_CONSTEXPR const T static_query_v+ = continuation_t::static_query<E>();+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++ static ASIO_CONSTEXPR relationship_t<I> value()+ {+ return continuation_t();+ }++ friend ASIO_CONSTEXPR bool operator==(+ const continuation_t&, const continuation_t&)+ {+ return true;+ }++ friend ASIO_CONSTEXPR bool operator!=(+ const continuation_t&, const continuation_t&)+ {+ return false;+ }+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)+template <int I> template <typename E, typename T>+const T continuation_t<I>::static_query_v;+#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // && defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++} // namespace relationship+} // namespace detail++typedef detail::relationship_t<> relationship_t;++#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr relationship_t relationship;+#else // defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+namespace { static const relationship_t&+ relationship = relationship_t::instance; }+#endif++} // namespace execution++#if !defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+struct is_applicable_property<T, execution::relationship_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::relationship_t::fork_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++template <typename T>+struct is_applicable_property<T, execution::relationship_t::continuation_t>+ : integral_constant<bool,+ execution::is_executor<T>::value+ || execution::is_sender<T>::value+ || execution::is_scheduler<T>::value>+{+};++#endif // !defined(ASIO_HAS_VARIABLE_TEMPLATES)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++template <typename T>+struct query_free_default<T, execution::relationship_t,+ typename enable_if<+ can_query<T, execution::relationship_t::fork_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::relationship_t::fork_t>::value));++ typedef execution::relationship_t result_type;+};++template <typename T>+struct query_free_default<T, execution::relationship_t,+ typename enable_if<+ !can_query<T, execution::relationship_t::fork_t>::value+ && can_query<T, execution::relationship_t::continuation_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<T, execution::relationship_t::continuation_t>::value));++ typedef execution::relationship_t result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \+ || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++template <typename T>+struct static_query<T, execution::relationship_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::relationship_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::relationship_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::relationship_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::relationship_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::relationship_t>::is_valid+ && !traits::query_member<T,+ execution::relationship_t>::is_valid+ && traits::static_query<T,+ execution::relationship_t::fork_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::relationship_t::fork_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T,+ execution::relationship_t::fork_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::relationship_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::relationship_t>::is_valid+ && !traits::query_member<T,+ execution::relationship_t>::is_valid+ && !traits::static_query<T,+ execution::relationship_t::fork_t>::is_valid+ && traits::static_query<T,+ execution::relationship_t::continuation_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::static_query<T,+ execution::relationship_t::continuation_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::static_query<T,+ execution::relationship_t::continuation_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::relationship_t::fork_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::relationship_t::fork_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::relationship_t::fork_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::relationship_t::fork_t>::value();+ }+};++template <typename T>+struct static_query<T, execution::relationship_t::fork_t,+ typename enable_if<+ !traits::query_static_constexpr_member<T,+ execution::relationship_t::fork_t>::is_valid+ && !traits::query_member<T,+ execution::relationship_t::fork_t>::is_valid+ && !traits::query_free<T,+ execution::relationship_t::fork_t>::is_valid+ && !can_query<T, execution::relationship_t::continuation_t>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef execution::relationship_t::fork_t result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return result_type();+ }+};++template <typename T>+struct static_query<T, execution::relationship_t::continuation_t,+ typename enable_if<+ traits::query_static_constexpr_member<T,+ execution::relationship_t::continuation_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++ typedef typename traits::query_static_constexpr_member<T,+ execution::relationship_t::continuation_t>::result_type result_type;++ static ASIO_CONSTEXPR result_type value()+ {+ return traits::query_static_constexpr_member<T,+ execution::relationship_t::continuation_t>::value();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)+ // || !defined(ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)++#if !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++template <typename T>+struct static_require<T, execution::relationship_t::fork_t,+ typename enable_if<+ static_query<T, execution::relationship_t::fork_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::relationship_t::fork_t>::result_type,+ execution::relationship_t::fork_t>::value));+};++template <typename T>+struct static_require<T, execution::relationship_t::continuation_t,+ typename enable_if<+ static_query<T, execution::relationship_t::continuation_t>::is_valid+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid =+ (is_same<typename static_query<T,+ execution::relationship_t::continuation_t>::result_type,+ execution::relationship_t::continuation_t>::value));+};++#endif // !defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++} // namespace traits++#endif // defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_RELATIONSHIP_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/schedule.hpp view
@@ -0,0 +1,290 @@+//+// execution/schedule.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_SCHEDULE_HPP+#define ASIO_EXECUTION_SCHEDULE_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/traits/schedule_member.hpp"+#include "asio/traits/schedule_free.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {+namespace execution {++/// A customisation point that is used to obtain a sender from a scheduler.+/**+ * The name <tt>execution::schedule</tt> denotes a customisation point object.+ * For some subexpression <tt>s</tt>, let <tt>S</tt> be a type such that+ * <tt>decltype((s))</tt> is <tt>S</tt>. The expression+ * <tt>execution::schedule(s)</tt> is expression-equivalent to:+ *+ * @li <tt>s.schedule()</tt>, if that expression is valid and its type models+ * <tt>sender</tt>.+ *+ * @li Otherwise, <tt>schedule(s)</tt>, if that expression is valid and its+ * type models <tt>sender</tt> with overload resolution performed in a context+ * that includes the declaration <tt>void schedule();</tt> and that does not+ * include a declaration of <tt>execution::schedule</tt>.+ *+ * @li Otherwise, <tt>S</tt> if <tt>S</tt> satisfies <tt>executor</tt>.+ *+ * @li Otherwise, <tt>execution::schedule(s)</tt> is ill-formed.+ */+inline constexpr unspecified schedule = unspecified;++/// A type trait that determines whether a @c schedule expression is+/// well-formed.+/**+ * Class template @c can_schedule is a trait that is derived from @c true_type+ * if the expression <tt>execution::schedule(std::declval<S>())</tt> is well+ * formed; otherwise @c false_type.+ */+template <typename S>+struct can_schedule :+ integral_constant<bool, automatically_determined>+{+};++} // namespace execution+} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_execution_schedule_fn {++using asio::decay;+using asio::declval;+using asio::enable_if;+using asio::execution::is_executor;+using asio::traits::schedule_free;+using asio::traits::schedule_member;++void schedule();++enum overload_type+{+ identity,+ call_member,+ call_free,+ ill_formed+};++template <typename S, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename S>+struct call_traits<S,+ typename enable_if<+ (+ schedule_member<S>::is_valid+ )+ >::type> :+ schedule_member<S>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename S>+struct call_traits<S,+ typename enable_if<+ (+ !schedule_member<S>::is_valid+ &&+ schedule_free<S>::is_valid+ )+ >::type> :+ schedule_free<S>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++template <typename S>+struct call_traits<S,+ typename enable_if<+ (+ !schedule_member<S>::is_valid+ &&+ !schedule_free<S>::is_valid+ &&+ is_executor<typename decay<S>::type>::value+ )+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++#if defined(ASIO_HAS_MOVE)+ typedef ASIO_MOVE_ARG(S) result_type;+#else // defined(ASIO_HAS_MOVE)+ typedef ASIO_MOVE_ARG(typename decay<S>::type) result_type;+#endif // defined(ASIO_HAS_MOVE)+};++struct impl+{+ template <typename S>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S>::overload == identity,+ typename call_traits<S>::result_type+ >::type+ operator()(ASIO_MOVE_ARG(S) s) const+ ASIO_NOEXCEPT_IF((+ call_traits<S>::is_noexcept))+ {+ return ASIO_MOVE_CAST(S)(s);+ }++#if defined(ASIO_HAS_MOVE)+ template <typename S>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S>::overload == call_member,+ typename call_traits<S>::result_type+ >::type+ operator()(S&& s) const+ ASIO_NOEXCEPT_IF((+ call_traits<S>::is_noexcept))+ {+ return ASIO_MOVE_CAST(S)(s).schedule();+ }++ template <typename S>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S>::overload == call_free,+ typename call_traits<S>::result_type+ >::type+ operator()(S&& s) const+ ASIO_NOEXCEPT_IF((+ call_traits<S>::is_noexcept))+ {+ return schedule(ASIO_MOVE_CAST(S)(s));+ }+#else // defined(ASIO_HAS_MOVE)+ template <typename S>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&>::overload == call_member,+ typename call_traits<S&>::result_type+ >::type+ operator()(S& s) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&>::is_noexcept))+ {+ return s.schedule();+ }++ template <typename S>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&>::overload == call_member,+ typename call_traits<const S&>::result_type+ >::type+ operator()(const S& s) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&>::is_noexcept))+ {+ return s.schedule();+ }++ template <typename S>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&>::overload == call_free,+ typename call_traits<S&>::result_type+ >::type+ operator()(S& s) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&>::is_noexcept))+ {+ return schedule(s);+ }++ template <typename S>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&>::overload == call_free,+ typename call_traits<const S&>::result_type+ >::type+ operator()(const S& s) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&>::is_noexcept))+ {+ return schedule(s);+ }+#endif // defined(ASIO_HAS_MOVE)+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_execution_schedule_fn+namespace asio {+namespace execution {+namespace {++static ASIO_CONSTEXPR const asio_execution_schedule_fn::impl&+ schedule = asio_execution_schedule_fn::static_instance<>::instance;++} // namespace++template <typename S>+struct can_schedule :+ integral_constant<bool,+ asio_execution_schedule_fn::call_traits<S>::overload !=+ asio_execution_schedule_fn::ill_formed>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S>+constexpr bool can_schedule_v = can_schedule<S>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S>+struct is_nothrow_schedule :+ integral_constant<bool,+ asio_execution_schedule_fn::call_traits<S>::is_noexcept>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S>+constexpr bool is_nothrow_schedule_v+ = is_nothrow_schedule<S>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++} // namespace execution+} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_SCHEDULE_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/scheduler.hpp view
@@ -0,0 +1,86 @@+//+// execution/scheduler.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_SCHEDULER_HPP+#define ASIO_EXECUTION_SCHEDULER_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/schedule.hpp"+#include "asio/traits/equality_comparable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace execution {+namespace detail {++template <typename T>+struct is_scheduler_base :+ integral_constant<bool,+ is_copy_constructible<typename remove_cvref<T>::type>::value+ && traits::equality_comparable<typename remove_cvref<T>::type>::is_valid+ >+{+};++} // namespace detail++/// The is_scheduler trait detects whether a type T satisfies the+/// execution::scheduler concept.+/**+ * Class template @c is_scheduler is a type trait that is derived from @c+ * true_type if the type @c T meets the concept definition for a scheduler for+ * error type @c E, otherwise @c false_type.+ */+template <typename T>+struct is_scheduler :+#if defined(GENERATING_DOCUMENTATION)+ integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ conditional<+ can_schedule<T>::value,+ detail::is_scheduler_base<T>,+ false_type+ >::type+#endif // defined(GENERATING_DOCUMENTATION)+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+ASIO_CONSTEXPR const bool is_scheduler_v = is_scheduler<T>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_CONCEPTS)++template <typename T>+ASIO_CONCEPT scheduler = is_scheduler<T>::value;++#define ASIO_EXECUTION_SCHEDULER ::asio::execution::scheduler++#else // defined(ASIO_HAS_CONCEPTS)++#define ASIO_EXECUTION_SCHEDULER typename++#endif // defined(ASIO_HAS_CONCEPTS)++} // namespace execution+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_SCHEDULER_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/sender.hpp view
@@ -0,0 +1,311 @@+//+// execution/sender.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_SENDER_HPP+#define ASIO_EXECUTION_SENDER_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/detail/as_invocable.hpp"+#include "asio/execution/detail/void_receiver.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution/receiver.hpp"++#include "asio/detail/push_options.hpp"++#if defined(ASIO_HAS_ALIAS_TEMPLATES) \+ && defined(ASIO_HAS_VARIADIC_TEMPLATES) \+ && defined(ASIO_HAS_DECLTYPE) \+ && !defined(ASIO_MSVC) || (_MSC_VER >= 1910)+# define ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT 1+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)+ // && defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // && defined(ASIO_HAS_DECLTYPE)+ // && !defined(ASIO_MSVC) || (_MSC_VER >= 1910)++namespace asio {+namespace execution {+namespace detail {++namespace sender_base_ns { struct sender_base {}; }++template <typename S, typename = void>+struct sender_traits_base+{+ typedef void asio_execution_sender_traits_base_is_unspecialised;+};++template <typename S>+struct sender_traits_base<S,+ typename enable_if<+ is_base_of<sender_base_ns::sender_base, S>::value+ >::type>+{+};++template <typename S, typename = void, typename = void, typename = void>+struct has_sender_types : false_type+{+};++#if defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT)++template <+ template <+ template <typename...> class Tuple,+ template <typename...> class Variant+ > class>+struct has_value_types+{+ typedef void type;+};++template <+ template <+ template <typename...> class Variant+ > class>+struct has_error_types+{+ typedef void type;+};++template <typename S>+struct has_sender_types<S,+ typename has_value_types<S::template value_types>::type,+ typename has_error_types<S::template error_types>::type,+ typename conditional<S::sends_done, void, void>::type> : true_type+{+};++template <typename S>+struct sender_traits_base<S,+ typename enable_if<+ has_sender_types<S>::value+ >::type>+{+ template <+ template <typename...> class Tuple,+ template <typename...> class Variant>+ using value_types = typename S::template value_types<Tuple, Variant>;++ template <template <typename...> class Variant>+ using error_types = typename S::template error_types<Variant>;++ ASIO_STATIC_CONSTEXPR(bool, sends_done = S::sends_done);+};++#endif // defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT)++template <typename S>+struct sender_traits_base<S,+ typename enable_if<+ !has_sender_types<S>::value+ && detail::is_executor_of_impl<S,+ as_invocable<void_receiver, S> >::value+ >::type>+{+#if defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) \+ && defined(ASIO_HAS_STD_EXCEPTION_PTR)++ template <+ template <typename...> class Tuple,+ template <typename...> class Variant>+ using value_types = Variant<Tuple<>>;++ template <template <typename...> class Variant>+ using error_types = Variant<std::exception_ptr>;++ ASIO_STATIC_CONSTEXPR(bool, sends_done = true);++#endif // defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT)+ // && defined(ASIO_HAS_STD_EXCEPTION_PTR)+};++} // namespace detail++/// Base class used for tagging senders.+#if defined(GENERATING_DOCUMENTATION)+typedef unspecified sender_base;+#else // defined(GENERATING_DOCUMENTATION)+typedef detail::sender_base_ns::sender_base sender_base;+#endif // defined(GENERATING_DOCUMENTATION)++/// Traits for senders.+template <typename S>+struct sender_traits+#if !defined(GENERATING_DOCUMENTATION)+ : detail::sender_traits_base<S>+#endif // !defined(GENERATING_DOCUMENTATION)+{+};++namespace detail {++template <typename S, typename = void>+struct has_sender_traits : true_type+{+};++template <typename S>+struct has_sender_traits<S,+ typename enable_if<+ is_same<+ typename asio::execution::sender_traits<+ S>::asio_execution_sender_traits_base_is_unspecialised,+ void+ >::value+ >::type> : false_type+{+};++} // namespace detail++/// The is_sender trait detects whether a type T satisfies the+/// execution::sender concept.++/**+ * Class template @c is_sender is a type trait that is derived from @c+ * true_type if the type @c T meets the concept definition for a sender,+ * otherwise @c false_type.+ */+template <typename T>+struct is_sender :+#if defined(GENERATING_DOCUMENTATION)+ integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ conditional<+ detail::has_sender_traits<typename remove_cvref<T>::type>::value,+ is_move_constructible<typename remove_cvref<T>::type>,+ false_type+ >::type+#endif // defined(GENERATING_DOCUMENTATION)+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+ASIO_CONSTEXPR const bool is_sender_v = is_sender<T>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_CONCEPTS)++template <typename T>+ASIO_CONCEPT sender = is_sender<T>::value;++#define ASIO_EXECUTION_SENDER ::asio::execution::sender++#else // defined(ASIO_HAS_CONCEPTS)++#define ASIO_EXECUTION_SENDER typename++#endif // defined(ASIO_HAS_CONCEPTS)++template <typename S, typename R>+struct can_connect;++/// The is_sender_to trait detects whether a type T satisfies the+/// execution::sender_to concept for some receiver.+/**+ * Class template @c is_sender_to is a type trait that is derived from @c+ * true_type if the type @c T meets the concept definition for a sender+ * for some receiver type R, otherwise @c false.+ */+template <typename T, typename R>+struct is_sender_to :+#if defined(GENERATING_DOCUMENTATION)+ integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ integral_constant<bool,+ is_sender<T>::value+ && is_receiver<R>::value+ && can_connect<T, R>::value+ >+#endif // defined(GENERATING_DOCUMENTATION)+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename R>+ASIO_CONSTEXPR const bool is_sender_to_v =+ is_sender_to<T, R>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_CONCEPTS)++template <typename T, typename R>+ASIO_CONCEPT sender_to = is_sender_to<T, R>::value;++#define ASIO_EXECUTION_SENDER_TO(r) \+ ::asio::execution::sender_to<r>++#else // defined(ASIO_HAS_CONCEPTS)++#define ASIO_EXECUTION_SENDER_TO(r) typename++#endif // defined(ASIO_HAS_CONCEPTS)++/// The is_typed_sender trait detects whether a type T satisfies the+/// execution::typed_sender concept.+/**+ * Class template @c is_typed_sender is a type trait that is derived from @c+ * true_type if the type @c T meets the concept definition for a typed sender,+ * otherwise @c false.+ */+template <typename T>+struct is_typed_sender :+#if defined(GENERATING_DOCUMENTATION)+ integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ integral_constant<bool,+ is_sender<T>::value+ && detail::has_sender_types<+ sender_traits<typename remove_cvref<T>::type> >::value+ >+#endif // defined(GENERATING_DOCUMENTATION)+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T>+ASIO_CONSTEXPR const bool is_typed_sender_v = is_typed_sender<T>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_CONCEPTS)++template <typename T>+ASIO_CONCEPT typed_sender = is_typed_sender<T>::value;++#define ASIO_EXECUTION_TYPED_SENDER \+ ::asio::execution::typed_sender++#else // defined(ASIO_HAS_CONCEPTS)++#define ASIO_EXECUTION_TYPED_SENDER typename++#endif // defined(ASIO_HAS_CONCEPTS)++} // namespace execution+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/execution/connect.hpp"++#endif // ASIO_EXECUTION_SENDER_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/set_done.hpp view
@@ -0,0 +1,253 @@+//+// execution/set_done.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_SET_DONE_HPP+#define ASIO_EXECUTION_SET_DONE_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/traits/set_done_member.hpp"+#include "asio/traits/set_done_free.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {+namespace execution {++/// A customisation point that delivers a done notification to a receiver.+/**+ * The name <tt>execution::set_done</tt> denotes a customisation point object.+ * The expression <tt>execution::set_done(R)</tt> for some subexpression+ * <tt>R</tt> is expression-equivalent to:+ *+ * @li <tt>R.set_done()</tt>, if that expression is valid. If the function+ * selected does not signal the receiver <tt>R</tt>'s done channel, the+ * program is ill-formed with no diagnostic required.+ *+ * @li Otherwise, <tt>set_done(R)</tt>, if that expression is valid, with+ * overload resolution performed in a context that includes the declaration+ * <tt>void set_done();</tt> and that does not include a declaration of+ * <tt>execution::set_done</tt>. If the function selected by overload+ * resolution does not signal the receiver <tt>R</tt>'s done channel, the+ * program is ill-formed with no diagnostic required.+ *+ * @li Otherwise, <tt>execution::set_done(R)</tt> is ill-formed.+ */+inline constexpr unspecified set_done = unspecified;++/// A type trait that determines whether a @c set_done expression is+/// well-formed.+/**+ * Class template @c can_set_done is a trait that is derived from+ * @c true_type if the expression <tt>execution::set_done(std::declval<R>(),+ * std::declval<E>())</tt> is well formed; otherwise @c false_type.+ */+template <typename R>+struct can_set_done :+ integral_constant<bool, automatically_determined>+{+};++} // namespace execution+} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_execution_set_done_fn {++using asio::decay;+using asio::declval;+using asio::enable_if;+using asio::traits::set_done_free;+using asio::traits::set_done_member;++void set_done();++enum overload_type+{+ call_member,+ call_free,+ ill_formed+};++template <typename R, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename R>+struct call_traits<R,+ typename enable_if<+ (+ set_done_member<R>::is_valid+ )+ >::type> :+ set_done_member<R>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename R>+struct call_traits<R,+ typename enable_if<+ (+ !set_done_member<R>::is_valid+ &&+ set_done_free<R>::is_valid+ )+ >::type> :+ set_done_free<R>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++struct impl+{+#if defined(ASIO_HAS_MOVE)+ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R>::overload == call_member,+ typename call_traits<R>::result_type+ >::type+ operator()(R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R>::is_noexcept))+ {+ return ASIO_MOVE_CAST(R)(r).set_done();+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R>::overload == call_free,+ typename call_traits<R>::result_type+ >::type+ operator()(R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R>::is_noexcept))+ {+ return set_done(ASIO_MOVE_CAST(R)(r));+ }+#else // defined(ASIO_HAS_MOVE)+ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R&>::overload == call_member,+ typename call_traits<R&>::result_type+ >::type+ operator()(R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R&>::is_noexcept))+ {+ return r.set_done();+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const R&>::overload == call_member,+ typename call_traits<const R&>::result_type+ >::type+ operator()(const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const R&>::is_noexcept))+ {+ return r.set_done();+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R&>::overload == call_free,+ typename call_traits<R&>::result_type+ >::type+ operator()(R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R&>::is_noexcept))+ {+ return set_done(r);+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const R&>::overload == call_free,+ typename call_traits<const R&>::result_type+ >::type+ operator()(const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const R&>::is_noexcept))+ {+ return set_done(r);+ }+#endif // defined(ASIO_HAS_MOVE)+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_execution_set_done_fn+namespace asio {+namespace execution {+namespace {++static ASIO_CONSTEXPR const asio_execution_set_done_fn::impl&+ set_done = asio_execution_set_done_fn::static_instance<>::instance;++} // namespace++template <typename R>+struct can_set_done :+ integral_constant<bool,+ asio_execution_set_done_fn::call_traits<R>::overload !=+ asio_execution_set_done_fn::ill_formed>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R>+constexpr bool can_set_done_v = can_set_done<R>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R>+struct is_nothrow_set_done :+ integral_constant<bool,+ asio_execution_set_done_fn::call_traits<R>::is_noexcept>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R>+constexpr bool is_nothrow_set_done_v+ = is_nothrow_set_done<R>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++} // namespace execution+} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_SET_DONE_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/set_error.hpp view
@@ -0,0 +1,253 @@+//+// execution/set_error.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_SET_ERROR_HPP+#define ASIO_EXECUTION_SET_ERROR_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/traits/set_error_member.hpp"+#include "asio/traits/set_error_free.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {+namespace execution {++/// A customisation point that delivers an error notification to a receiver.+/**+ * The name <tt>execution::set_error</tt> denotes a customisation point object.+ * The expression <tt>execution::set_error(R, E)</tt> for some subexpressions+ * <tt>R</tt> and <tt>E</tt> are expression-equivalent to:+ *+ * @li <tt>R.set_error(E)</tt>, if that expression is valid. If the function+ * selected does not send the error <tt>E</tt> to the receiver <tt>R</tt>'s+ * error channel, the program is ill-formed with no diagnostic required.+ *+ * @li Otherwise, <tt>set_error(R, E)</tt>, if that expression is valid, with+ * overload resolution performed in a context that includes the declaration+ * <tt>void set_error();</tt> and that does not include a declaration of+ * <tt>execution::set_error</tt>. If the function selected by overload+ * resolution does not send the error <tt>E</tt> to the receiver <tt>R</tt>'s+ * error channel, the program is ill-formed with no diagnostic required.+ *+ * @li Otherwise, <tt>execution::set_error(R, E)</tt> is ill-formed.+ */+inline constexpr unspecified set_error = unspecified;++/// A type trait that determines whether a @c set_error expression is+/// well-formed.+/**+ * Class template @c can_set_error is a trait that is derived from+ * @c true_type if the expression <tt>execution::set_error(std::declval<R>(),+ * std::declval<E>())</tt> is well formed; otherwise @c false_type.+ */+template <typename R, typename E>+struct can_set_error :+ integral_constant<bool, automatically_determined>+{+};++} // namespace execution+} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_execution_set_error_fn {++using asio::decay;+using asio::declval;+using asio::enable_if;+using asio::traits::set_error_free;+using asio::traits::set_error_member;++void set_error();++enum overload_type+{+ call_member,+ call_free,+ ill_formed+};++template <typename R, typename E, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename R, typename E>+struct call_traits<R, void(E),+ typename enable_if<+ (+ set_error_member<R, E>::is_valid+ )+ >::type> :+ set_error_member<R, E>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename R, typename E>+struct call_traits<R, void(E),+ typename enable_if<+ (+ !set_error_member<R, E>::is_valid+ &&+ set_error_free<R, E>::is_valid+ )+ >::type> :+ set_error_free<R, E>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++struct impl+{+#if defined(ASIO_HAS_MOVE)+ template <typename R, typename E>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R, void(E)>::overload == call_member,+ typename call_traits<R, void(E)>::result_type+ >::type+ operator()(R&& r, E&& e) const+ ASIO_NOEXCEPT_IF((+ call_traits<R, void(E)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(R)(r).set_error(ASIO_MOVE_CAST(E)(e));+ }++ template <typename R, typename E>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R, void(E)>::overload == call_free,+ typename call_traits<R, void(E)>::result_type+ >::type+ operator()(R&& r, E&& e) const+ ASIO_NOEXCEPT_IF((+ call_traits<R, void(E)>::is_noexcept))+ {+ return set_error(ASIO_MOVE_CAST(R)(r), ASIO_MOVE_CAST(E)(e));+ }+#else // defined(ASIO_HAS_MOVE)+ template <typename R, typename E>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R&, void(const E&)>::overload == call_member,+ typename call_traits<R&, void(const E&)>::result_type+ >::type+ operator()(R& r, const E& e) const+ ASIO_NOEXCEPT_IF((+ call_traits<R&, void(const E&)>::is_noexcept))+ {+ return r.set_error(e);+ }++ template <typename R, typename E>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const R&, void(const E&)>::overload == call_member,+ typename call_traits<const R&, void(const E&)>::result_type+ >::type+ operator()(const R& r, const E& e) const+ ASIO_NOEXCEPT_IF((+ call_traits<const R&, void(const E&)>::is_noexcept))+ {+ return r.set_error(e);+ }++ template <typename R, typename E>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R&, void(const E&)>::overload == call_free,+ typename call_traits<R&, void(const E&)>::result_type+ >::type+ operator()(R& r, const E& e) const+ ASIO_NOEXCEPT_IF((+ call_traits<R&, void(const E&)>::is_noexcept))+ {+ return set_error(r, e);+ }++ template <typename R, typename E>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const R&, void(const E&)>::overload == call_free,+ typename call_traits<const R&, void(const E&)>::result_type+ >::type+ operator()(const R& r, const E& e) const+ ASIO_NOEXCEPT_IF((+ call_traits<const R&, void(const E&)>::is_noexcept))+ {+ return set_error(r, e);+ }+#endif // defined(ASIO_HAS_MOVE)+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_execution_set_error_fn+namespace asio {+namespace execution {+namespace {++static ASIO_CONSTEXPR const asio_execution_set_error_fn::impl&+ set_error = asio_execution_set_error_fn::static_instance<>::instance;++} // namespace++template <typename R, typename E>+struct can_set_error :+ integral_constant<bool,+ asio_execution_set_error_fn::call_traits<R, void(E)>::overload !=+ asio_execution_set_error_fn::ill_formed>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R, typename E>+constexpr bool can_set_error_v = can_set_error<R, E>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R, typename E>+struct is_nothrow_set_error :+ integral_constant<bool,+ asio_execution_set_error_fn::call_traits<R, void(E)>::is_noexcept>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R, typename E>+constexpr bool is_nothrow_set_error_v+ = is_nothrow_set_error<R, E>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++} // namespace execution+} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_SET_ERROR_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/set_value.hpp view
@@ -0,0 +1,486 @@+//+// execution/set_value.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_SET_VALUE_HPP+#define ASIO_EXECUTION_SET_VALUE_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/variadic_templates.hpp"+#include "asio/traits/set_value_member.hpp"+#include "asio/traits/set_value_free.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {+namespace execution {++/// A customisation point that delivers a value to a receiver.+/**+ * The name <tt>execution::set_value</tt> denotes a customisation point object.+ * The expression <tt>execution::set_value(R, Vs...)</tt> for some+ * subexpressions <tt>R</tt> and <tt>Vs...</tt> is expression-equivalent to:+ *+ * @li <tt>R.set_value(Vs...)</tt>, if that expression is valid. If the+ * function selected does not send the value(s) <tt>Vs...</tt> to the receiver+ * <tt>R</tt>'s value channel, the program is ill-formed with no diagnostic+ * required.+ *+ * @li Otherwise, <tt>set_value(R, Vs...)</tt>, if that expression is valid,+ * with overload resolution performed in a context that includes the+ * declaration <tt>void set_value();</tt> and that does not include a+ * declaration of <tt>execution::set_value</tt>. If the function selected by+ * overload resolution does not send the value(s) <tt>Vs...</tt> to the+ * receiver <tt>R</tt>'s value channel, the program is ill-formed with no+ * diagnostic required.+ *+ * @li Otherwise, <tt>execution::set_value(R, Vs...)</tt> is ill-formed.+ */+inline constexpr unspecified set_value = unspecified;++/// A type trait that determines whether a @c set_value expression is+/// well-formed.+/**+ * Class template @c can_set_value is a trait that is derived from+ * @c true_type if the expression <tt>execution::set_value(std::declval<R>(),+ * std::declval<Vs>()...)</tt> is well formed; otherwise @c false_type.+ */+template <typename R, typename... Vs>+struct can_set_value :+ integral_constant<bool, automatically_determined>+{+};++} // namespace execution+} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_execution_set_value_fn {++using asio::decay;+using asio::declval;+using asio::enable_if;+using asio::traits::set_value_free;+using asio::traits::set_value_member;++void set_value();++enum overload_type+{+ call_member,+ call_free,+ ill_formed+};++template <typename R, typename Vs, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename R, typename Vs>+struct call_traits<R, Vs,+ typename enable_if<+ (+ set_value_member<R, Vs>::is_valid+ )+ >::type> :+ set_value_member<R, Vs>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename R, typename Vs>+struct call_traits<R, Vs,+ typename enable_if<+ (+ !set_value_member<R, Vs>::is_valid+ &&+ set_value_free<R, Vs>::is_valid+ )+ >::type> :+ set_value_free<R, Vs>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++struct impl+{+#if defined(ASIO_HAS_MOVE)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename R, typename... Vs>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R, void(Vs...)>::overload == call_member,+ typename call_traits<R, void(Vs...)>::result_type+ >::type+ operator()(R&& r, Vs&&... v) const+ ASIO_NOEXCEPT_IF((+ call_traits<R, void(Vs...)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(R)(r).set_value(ASIO_MOVE_CAST(Vs)(v)...);+ }++ template <typename R, typename... Vs>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R, void(Vs...)>::overload == call_free,+ typename call_traits<R, void(Vs...)>::result_type+ >::type+ operator()(R&& r, Vs&&... v) const+ ASIO_NOEXCEPT_IF((+ call_traits<R, void(Vs...)>::is_noexcept))+ {+ return set_value(ASIO_MOVE_CAST(R)(r),+ ASIO_MOVE_CAST(Vs)(v)...);+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R, void()>::overload == call_member,+ typename call_traits<R, void()>::result_type+ >::type+ operator()(R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R, void()>::is_noexcept))+ {+ return ASIO_MOVE_CAST(R)(r).set_value();+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R, void()>::overload == call_free,+ typename call_traits<R, void()>::result_type+ >::type+ operator()(R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R, void()>::is_noexcept))+ {+ return set_value(ASIO_MOVE_CAST(R)(r));+ }++#define ASIO_PRIVATE_SET_VALUE_CALL_DEF(n) \+ template <typename R, ASIO_VARIADIC_TPARAMS(n)> \+ ASIO_CONSTEXPR typename enable_if< \+ call_traits<R, \+ void(ASIO_VARIADIC_TARGS(n))>::overload == call_member, \+ typename call_traits<R, void(ASIO_VARIADIC_TARGS(n))>::result_type \+ >::type \+ operator()(R&& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \+ ASIO_NOEXCEPT_IF(( \+ call_traits<R, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \+ { \+ return ASIO_MOVE_CAST(R)(r).set_value( \+ ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ \+ template <typename R, ASIO_VARIADIC_TPARAMS(n)> \+ ASIO_CONSTEXPR typename enable_if< \+ call_traits<R, void(ASIO_VARIADIC_TARGS(n))>::overload == call_free, \+ typename call_traits<R, void(ASIO_VARIADIC_TARGS(n))>::result_type \+ >::type \+ operator()(R&& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \+ ASIO_NOEXCEPT_IF(( \+ call_traits<R, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \+ { \+ return set_value(ASIO_MOVE_CAST(R)(r), \+ ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_CALL_DEF)+#undef ASIO_PRIVATE_SET_VALUE_CALL_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#else // defined(ASIO_HAS_MOVE)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename R, typename... Vs>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R&, void(const Vs&...)>::overload == call_member,+ typename call_traits<R&, void(const Vs&...)>::result_type+ >::type+ operator()(R& r, const Vs&... v) const+ ASIO_NOEXCEPT_IF((+ call_traits<R&, void(const Vs&...)>::is_noexcept))+ {+ return r.set_value(v...);+ }++ template <typename R, typename... Vs>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const R&, void(const Vs&...)>::overload == call_member,+ typename call_traits<const R&, void(const Vs&...)>::result_type+ >::type+ operator()(const R& r, const Vs&... v) const+ ASIO_NOEXCEPT_IF((+ call_traits<const R&, void(const Vs&...)>::is_noexcept))+ {+ return r.set_value(v...);+ }++ template <typename R, typename... Vs>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R&, void(const Vs&...)>::overload == call_free,+ typename call_traits<R&, void(const Vs&...)>::result_type+ >::type+ operator()(R& r, const Vs&... v) const+ ASIO_NOEXCEPT_IF((+ call_traits<R&, void(const Vs&...)>::is_noexcept))+ {+ return set_value(r, v...);+ }++ template <typename R, typename... Vs>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const R&, void(const Vs&...)>::overload == call_free,+ typename call_traits<const R&, void(const Vs&...)>::result_type+ >::type+ operator()(const R& r, const Vs&... v) const+ ASIO_NOEXCEPT_IF((+ call_traits<const R&, void(const Vs&...)>::is_noexcept))+ {+ return set_value(r, v...);+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R&, void()>::overload == call_member,+ typename call_traits<R&, void()>::result_type+ >::type+ operator()(R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R&, void()>::is_noexcept))+ {+ return r.set_value();+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const R&, void()>::overload == call_member,+ typename call_traits<const R&, void()>::result_type+ >::type+ operator()(const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const R&, void()>::is_noexcept))+ {+ return r.set_value();+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R&, void()>::overload == call_free,+ typename call_traits<R&, void()>::result_type+ >::type+ operator()(R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R&, void()>::is_noexcept))+ {+ return set_value(r);+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const R&, void()>::overload == call_free,+ typename call_traits<const R&, void()>::result_type+ >::type+ operator()(const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const R&, void()>::is_noexcept))+ {+ return set_value(r);+ }++#define ASIO_PRIVATE_SET_VALUE_CALL_DEF(n) \+ template <typename R, ASIO_VARIADIC_TPARAMS(n)> \+ ASIO_CONSTEXPR typename enable_if< \+ call_traits<R&, \+ void(ASIO_VARIADIC_TARGS(n))>::overload == call_member, \+ typename call_traits<R&, void(ASIO_VARIADIC_TARGS(n))>::result_type \+ >::type \+ operator()(R& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \+ ASIO_NOEXCEPT_IF(( \+ call_traits<R&, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \+ { \+ return r.set_value(ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ \+ template <typename R, ASIO_VARIADIC_TPARAMS(n)> \+ ASIO_CONSTEXPR typename enable_if< \+ call_traits<const R&, \+ void(ASIO_VARIADIC_TARGS(n))>::overload == call_member, \+ typename call_traits<const R&, \+ void(ASIO_VARIADIC_TARGS(n))>::result_type \+ >::type \+ operator()(const R& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \+ ASIO_NOEXCEPT_IF(( \+ call_traits<const R&, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \+ { \+ return r.set_value(ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ \+ template <typename R, ASIO_VARIADIC_TPARAMS(n)> \+ ASIO_CONSTEXPR typename enable_if< \+ call_traits<R&, \+ void(ASIO_VARIADIC_TARGS(n))>::overload == call_free, \+ typename call_traits<R&, void(ASIO_VARIADIC_TARGS(n))>::result_type \+ >::type \+ operator()(R& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \+ ASIO_NOEXCEPT_IF(( \+ call_traits<R&, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \+ { \+ return set_value(r, ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ \+ template <typename R, ASIO_VARIADIC_TPARAMS(n)> \+ ASIO_CONSTEXPR typename enable_if< \+ call_traits<const R&, \+ void(ASIO_VARIADIC_TARGS(n))>::overload == call_free, \+ typename call_traits<const R&, \+ void(ASIO_VARIADIC_TARGS(n))>::result_type \+ >::type \+ operator()(const R& r, ASIO_VARIADIC_MOVE_PARAMS(n)) const \+ ASIO_NOEXCEPT_IF(( \+ call_traits<const R&, void(ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \+ { \+ return set_value(r, ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_CALL_DEF)+#undef ASIO_PRIVATE_SET_VALUE_CALL_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#endif // defined(ASIO_HAS_MOVE)+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_execution_set_value_fn+namespace asio {+namespace execution {+namespace {++static ASIO_CONSTEXPR const asio_execution_set_value_fn::impl&+ set_value = asio_execution_set_value_fn::static_instance<>::instance;++} // namespace++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename R, typename... Vs>+struct can_set_value :+ integral_constant<bool,+ asio_execution_set_value_fn::call_traits<R, void(Vs...)>::overload !=+ asio_execution_set_value_fn::ill_formed>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R, typename... Vs>+constexpr bool can_set_value_v = can_set_value<R, Vs...>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R, typename... Vs>+struct is_nothrow_set_value :+ integral_constant<bool,+ asio_execution_set_value_fn::call_traits<R, void(Vs...)>::is_noexcept>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R, typename... Vs>+constexpr bool is_nothrow_set_value_v+ = is_nothrow_set_value<R, Vs...>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename R, typename = void,+ typename = void, typename = void, typename = void, typename = void,+ typename = void, typename = void, typename = void, typename = void>+struct can_set_value;++template <typename R, typename = void,+ typename = void, typename = void, typename = void, typename = void,+ typename = void, typename = void, typename = void, typename = void>+struct is_nothrow_set_value;++template <typename R>+struct can_set_value<R> :+ integral_constant<bool,+ asio_execution_set_value_fn::call_traits<R, void()>::overload !=+ asio_execution_set_value_fn::ill_formed>+{+};++template <typename R>+struct is_nothrow_set_value<R> :+ integral_constant<bool,+ asio_execution_set_value_fn::call_traits<R, void()>::is_noexcept>+{+};++#define ASIO_PRIVATE_SET_VALUE_TRAITS_DEF(n) \+ template <typename R, ASIO_VARIADIC_TPARAMS(n)> \+ struct can_set_value<R, ASIO_VARIADIC_TARGS(n)> : \+ integral_constant<bool, \+ asio_execution_set_value_fn::call_traits<R, \+ void(ASIO_VARIADIC_TARGS(n))>::overload != \+ asio_execution_set_value_fn::ill_formed> \+ { \+ }; \+ \+ template <typename R, ASIO_VARIADIC_TPARAMS(n)> \+ struct is_nothrow_set_value<R, ASIO_VARIADIC_TARGS(n)> : \+ integral_constant<bool, \+ asio_execution_set_value_fn::call_traits<R, \+ void(ASIO_VARIADIC_TARGS(n))>::is_noexcept> \+ { \+ }; \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_TRAITS_DEF)+#undef ASIO_PRIVATE_SET_VALUE_TRAITS_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++} // namespace execution+} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_SET_VALUE_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/start.hpp view
@@ -0,0 +1,250 @@+//+// execution/start.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_START_HPP+#define ASIO_EXECUTION_START_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/traits/start_member.hpp"+#include "asio/traits/start_free.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {+namespace execution {++/// A customisation point that notifies an operation state object to start+/// its associated operation.+/**+ * The name <tt>execution::start</tt> denotes a customisation point object.+ * The expression <tt>execution::start(R)</tt> for some subexpression+ * <tt>R</tt> is expression-equivalent to:+ *+ * @li <tt>R.start()</tt>, if that expression is valid.+ *+ * @li Otherwise, <tt>start(R)</tt>, if that expression is valid, with+ * overload resolution performed in a context that includes the declaration+ * <tt>void start();</tt> and that does not include a declaration of+ * <tt>execution::start</tt>.+ *+ * @li Otherwise, <tt>execution::start(R)</tt> is ill-formed.+ */+inline constexpr unspecified start = unspecified;++/// A type trait that determines whether a @c start expression is+/// well-formed.+/**+ * Class template @c can_start is a trait that is derived from+ * @c true_type if the expression <tt>execution::start(std::declval<R>(),+ * std::declval<E>())</tt> is well formed; otherwise @c false_type.+ */+template <typename R>+struct can_start :+ integral_constant<bool, automatically_determined>+{+};++} // namespace execution+} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_execution_start_fn {++using asio::decay;+using asio::declval;+using asio::enable_if;+using asio::traits::start_free;+using asio::traits::start_member;++void start();++enum overload_type+{+ call_member,+ call_free,+ ill_formed+};++template <typename R, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename R>+struct call_traits<R,+ typename enable_if<+ (+ start_member<R>::is_valid+ )+ >::type> :+ start_member<R>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename R>+struct call_traits<R,+ typename enable_if<+ (+ !start_member<R>::is_valid+ &&+ start_free<R>::is_valid+ )+ >::type> :+ start_free<R>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++struct impl+{+#if defined(ASIO_HAS_MOVE)+ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R>::overload == call_member,+ typename call_traits<R>::result_type+ >::type+ operator()(R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R>::is_noexcept))+ {+ return ASIO_MOVE_CAST(R)(r).start();+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R>::overload == call_free,+ typename call_traits<R>::result_type+ >::type+ operator()(R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R>::is_noexcept))+ {+ return start(ASIO_MOVE_CAST(R)(r));+ }+#else // defined(ASIO_HAS_MOVE)+ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R&>::overload == call_member,+ typename call_traits<R&>::result_type+ >::type+ operator()(R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R&>::is_noexcept))+ {+ return r.start();+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const R&>::overload == call_member,+ typename call_traits<const R&>::result_type+ >::type+ operator()(const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const R&>::is_noexcept))+ {+ return r.start();+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<R&>::overload == call_free,+ typename call_traits<R&>::result_type+ >::type+ operator()(R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<R&>::is_noexcept))+ {+ return start(r);+ }++ template <typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const R&>::overload == call_free,+ typename call_traits<const R&>::result_type+ >::type+ operator()(const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const R&>::is_noexcept))+ {+ return start(r);+ }+#endif // defined(ASIO_HAS_MOVE)+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_execution_start_fn+namespace asio {+namespace execution {+namespace {++static ASIO_CONSTEXPR const asio_execution_start_fn::impl&+ start = asio_execution_start_fn::static_instance<>::instance;++} // namespace++template <typename R>+struct can_start :+ integral_constant<bool,+ asio_execution_start_fn::call_traits<R>::overload !=+ asio_execution_start_fn::ill_formed>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R>+constexpr bool can_start_v = can_start<R>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R>+struct is_nothrow_start :+ integral_constant<bool,+ asio_execution_start_fn::call_traits<R>::is_noexcept>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename R>+constexpr bool is_nothrow_start_v+ = is_nothrow_start<R>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++} // namespace execution+} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_START_HPP
+ link/modules/asio-standalone/asio/include/asio/execution/submit.hpp view
@@ -0,0 +1,450 @@+//+// execution/submit.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_SUBMIT_HPP+#define ASIO_EXECUTION_SUBMIT_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/detail/submit_receiver.hpp"+#include "asio/execution/executor.hpp"+#include "asio/execution/receiver.hpp"+#include "asio/execution/sender.hpp"+#include "asio/execution/start.hpp"+#include "asio/traits/submit_member.hpp"+#include "asio/traits/submit_free.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {+namespace execution {++/// A customisation point that submits a sender to a receiver.+/**+ * The name <tt>execution::submit</tt> denotes a customisation point object. For+ * some subexpressions <tt>s</tt> and <tt>r</tt>, let <tt>S</tt> be a type such+ * that <tt>decltype((s))</tt> is <tt>S</tt> and let <tt>R</tt> be a type such+ * that <tt>decltype((r))</tt> is <tt>R</tt>. The expression+ * <tt>execution::submit(s, r)</tt> is ill-formed if <tt>sender_to<S, R></tt> is+ * not <tt>true</tt>. Otherwise, it is expression-equivalent to:+ *+ * @li <tt>s.submit(r)</tt>, if that expression is valid and <tt>S</tt> models+ * <tt>sender</tt>. If the function selected does not submit the receiver+ * object <tt>r</tt> via the sender <tt>s</tt>, the program is ill-formed with+ * no diagnostic required.+ *+ * @li Otherwise, <tt>submit(s, r)</tt>, if that expression is valid and+ * <tt>S</tt> models <tt>sender</tt>, with overload resolution performed in a+ * context that includes the declaration <tt>void submit();</tt> and that does+ * not include a declaration of <tt>execution::submit</tt>. If the function+ * selected by overload resolution does not submit the receiver object+ * <tt>r</tt> via the sender <tt>s</tt>, the program is ill-formed with no+ * diagnostic required.+ *+ * @li Otherwise, <tt>execution::start((new submit_receiver<S,+ * R>{s,r})->state_)</tt>, where <tt>submit_receiver</tt> is an+ * implementation-defined class template equivalent to:+ * @code template<class S, class R>+ * struct submit_receiver {+ * struct wrap {+ * submit_receiver * p_;+ * template<class...As>+ * requires receiver_of<R, As...>+ * void set_value(As&&... as) &&+ * noexcept(is_nothrow_receiver_of_v<R, As...>) {+ * execution::set_value(std::move(p_->r_), (As&&) as...);+ * delete p_;+ * }+ * template<class E>+ * requires receiver<R, E>+ * void set_error(E&& e) && noexcept {+ * execution::set_error(std::move(p_->r_), (E&&) e);+ * delete p_;+ * }+ * void set_done() && noexcept {+ * execution::set_done(std::move(p_->r_));+ * delete p_;+ * }+ * };+ * remove_cvref_t<R> r_;+ * connect_result_t<S, wrap> state_;+ * submit_receiver(S&& s, R&& r)+ * : r_((R&&) r)+ * , state_(execution::connect((S&&) s, wrap{this})) {}+ * };+ * @endcode+ */+inline constexpr unspecified submit = unspecified;++/// A type trait that determines whether a @c submit expression is+/// well-formed.+/**+ * Class template @c can_submit is a trait that is derived from+ * @c true_type if the expression <tt>execution::submit(std::declval<R>(),+ * std::declval<E>())</tt> is well formed; otherwise @c false_type.+ */+template <typename S, typename R>+struct can_submit :+ integral_constant<bool, automatically_determined>+{+};++} // namespace execution+} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_execution_submit_fn {++using asio::declval;+using asio::enable_if;+using asio::execution::is_sender_to;+using asio::traits::submit_free;+using asio::traits::submit_member;++void submit();++enum overload_type+{+ call_member,+ call_free,+ adapter,+ ill_formed+};++template <typename S, typename R, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename S, typename R>+struct call_traits<S, void(R),+ typename enable_if<+ (+ submit_member<S, R>::is_valid+ &&+ is_sender_to<S, R>::value+ )+ >::type> :+ submit_member<S, R>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename S, typename R>+struct call_traits<S, void(R),+ typename enable_if<+ (+ !submit_member<S, R>::is_valid+ &&+ submit_free<S, R>::is_valid+ &&+ is_sender_to<S, R>::value+ )+ >::type> :+ submit_free<S, R>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++template <typename S, typename R>+struct call_traits<S, void(R),+ typename enable_if<+ (+ !submit_member<S, R>::is_valid+ &&+ !submit_free<S, R>::is_valid+ &&+ is_sender_to<S, R>::value+ )+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++struct impl+{+#if defined(ASIO_HAS_MOVE)+ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(R)>::overload == call_member,+ typename call_traits<S, void(R)>::result_type+ >::type+ operator()(S&& s, R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(R)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(S)(s).submit(ASIO_MOVE_CAST(R)(r));+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(R)>::overload == call_free,+ typename call_traits<S, void(R)>::result_type+ >::type+ operator()(S&& s, R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(R)>::is_noexcept))+ {+ return submit(ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r));+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S, void(R)>::overload == adapter,+ typename call_traits<S, void(R)>::result_type+ >::type+ operator()(S&& s, R&& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S, void(R)>::is_noexcept))+ {+ return asio::execution::start(+ (new asio::execution::detail::submit_receiver<S, R>(+ ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r)))->state_);+ }+#else // defined(ASIO_HAS_MOVE)+ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(R&)>::overload == call_member,+ typename call_traits<S&, void(R&)>::result_type+ >::type+ operator()(S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(R&)>::is_noexcept))+ {+ return s.submit(r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(R&)>::overload == call_member,+ typename call_traits<const S&, void(R&)>::result_type+ >::type+ operator()(const S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(R&)>::is_noexcept))+ {+ return s.submit(r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(R&)>::overload == call_free,+ typename call_traits<S&, void(R&)>::result_type+ >::type+ operator()(S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(R&)>::is_noexcept))+ {+ return submit(s, r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(R&)>::overload == call_free,+ typename call_traits<const S&, void(R&)>::result_type+ >::type+ operator()(const S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(R&)>::is_noexcept))+ {+ return submit(s, r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(R&)>::overload == adapter,+ typename call_traits<S&, void(R&)>::result_type+ >::type+ operator()(S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(R&)>::is_noexcept))+ {+ return asio::execution::start(+ (new asio::execution::detail::submit_receiver<+ S&, R&>(s, r))->state_);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(R&)>::overload == adapter,+ typename call_traits<const S&, void(R&)>::result_type+ >::type+ operator()(const S& s, R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(R&)>::is_noexcept))+ {+ asio::execution::start(+ (new asio::execution::detail::submit_receiver<+ const S&, R&>(s, r))->state_);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(const R&)>::overload == call_member,+ typename call_traits<S&, void(const R&)>::result_type+ >::type+ operator()(S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(const R&)>::is_noexcept))+ {+ return s.submit(r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(const R&)>::overload == call_member,+ typename call_traits<const S&, void(const R&)>::result_type+ >::type+ operator()(const S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(const R&)>::is_noexcept))+ {+ return s.submit(r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(const R&)>::overload == call_free,+ typename call_traits<S&, void(const R&)>::result_type+ >::type+ operator()(S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(const R&)>::is_noexcept))+ {+ return submit(s, r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(const R&)>::overload == call_free,+ typename call_traits<const S&, void(const R&)>::result_type+ >::type+ operator()(const S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(const R&)>::is_noexcept))+ {+ return submit(s, r);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<S&, void(const R&)>::overload == adapter,+ typename call_traits<S&, void(const R&)>::result_type+ >::type+ operator()(S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<S&, void(const R&)>::is_noexcept))+ {+ asio::execution::start(+ (new asio::execution::detail::submit_receiver<+ S&, const R&>(s, r))->state_);+ }++ template <typename S, typename R>+ ASIO_CONSTEXPR typename enable_if<+ call_traits<const S&, void(const R&)>::overload == adapter,+ typename call_traits<const S&, void(const R&)>::result_type+ >::type+ operator()(const S& s, const R& r) const+ ASIO_NOEXCEPT_IF((+ call_traits<const S&, void(const R&)>::is_noexcept))+ {+ asio::execution::start(+ (new asio::execution::detail::submit_receiver<+ const S&, const R&>(s, r))->state_);+ }+#endif // defined(ASIO_HAS_MOVE)+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_execution_submit_fn+namespace asio {+namespace execution {+namespace {++static ASIO_CONSTEXPR const asio_execution_submit_fn::impl&+ submit = asio_execution_submit_fn::static_instance<>::instance;++} // namespace++template <typename S, typename R>+struct can_submit :+ integral_constant<bool,+ asio_execution_submit_fn::call_traits<S, void(R)>::overload !=+ asio_execution_submit_fn::ill_formed>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename R>+constexpr bool can_submit_v = can_submit<S, R>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename R>+struct is_nothrow_submit :+ integral_constant<bool,+ asio_execution_submit_fn::call_traits<S, void(R)>::is_noexcept>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename R>+constexpr bool is_nothrow_submit_v+ = is_nothrow_submit<S, R>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename S, typename R>+struct submit_result+{+ typedef typename asio_execution_submit_fn::call_traits<+ S, void(R)>::result_type type;+};++namespace detail {++template <typename S, typename R>+void submit_helper(ASIO_MOVE_ARG(S) s, ASIO_MOVE_ARG(R) r)+{+ execution::submit(ASIO_MOVE_CAST(S)(s), ASIO_MOVE_CAST(R)(r));+}++} // namespace detail+} // namespace execution+} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_EXECUTION_SUBMIT_HPP
+ link/modules/asio-standalone/asio/include/asio/execution_context.hpp view
@@ -0,0 +1,412 @@+//+// execution_context.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTION_CONTEXT_HPP+#define ASIO_EXECUTION_CONTEXT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include <stdexcept>+#include <typeinfo>+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/variadic_templates.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++class execution_context;+class io_context;++#if !defined(GENERATING_DOCUMENTATION)+template <typename Service> Service& use_service(execution_context&);+template <typename Service> Service& use_service(io_context&);+template <typename Service> void add_service(execution_context&, Service*);+template <typename Service> bool has_service(execution_context&);+#endif // !defined(GENERATING_DOCUMENTATION)++namespace detail { class service_registry; }++/// A context for function object execution.+/**+ * An execution context represents a place where function objects will be+ * executed. An @c io_context is an example of an execution context.+ *+ * @par The execution_context class and services+ *+ * Class execution_context implements an extensible, type-safe, polymorphic set+ * of services, indexed by service type.+ *+ * Services exist to manage the resources that are shared across an execution+ * context. For example, timers may be implemented in terms of a single timer+ * queue, and this queue would be stored in a service.+ *+ * Access to the services of an execution_context is via three function+ * templates, use_service(), add_service() and has_service().+ *+ * In a call to @c use_service<Service>(), the type argument chooses a service,+ * making available all members of the named type. If @c Service is not present+ * in an execution_context, an object of type @c Service is created and added+ * to the execution_context. A C++ program can check if an execution_context+ * implements a particular service with the function template @c+ * has_service<Service>().+ *+ * Service objects may be explicitly added to an execution_context using the+ * function template @c add_service<Service>(). If the @c Service is already+ * present, the service_already_exists exception is thrown. If the owner of the+ * service is not the same object as the execution_context parameter, the+ * invalid_service_owner exception is thrown.+ *+ * Once a service reference is obtained from an execution_context object by+ * calling use_service(), that reference remains usable as long as the owning+ * execution_context object exists.+ *+ * All service implementations have execution_context::service as a public base+ * class. Custom services may be implemented by deriving from this class and+ * then added to an execution_context using the facilities described above.+ *+ * @par The execution_context as a base class+ *+ * Class execution_context may be used only as a base class for concrete+ * execution context types. The @c io_context is an example of such a derived+ * type.+ *+ * On destruction, a class that is derived from execution_context must perform+ * <tt>execution_context::shutdown()</tt> followed by+ * <tt>execution_context::destroy()</tt>.+ *+ * This destruction sequence permits programs to simplify their resource+ * management by using @c shared_ptr<>. Where an object's lifetime is tied to+ * the lifetime of a connection (or some other sequence of asynchronous+ * operations), a @c shared_ptr to the object would be bound into the handlers+ * for all asynchronous operations associated with it. This works as follows:+ *+ * @li When a single connection ends, all associated asynchronous operations+ * complete. The corresponding handler objects are destroyed, and all @c+ * shared_ptr references to the objects are destroyed.+ *+ * @li To shut down the whole program, the io_context function stop() is called+ * to terminate any run() calls as soon as possible. The io_context destructor+ * calls @c shutdown() and @c destroy() to destroy all pending handlers,+ * causing all @c shared_ptr references to all connection objects to be+ * destroyed.+ */+class execution_context+ : private noncopyable+{+public:+ class id;+ class service;++public:+ /// Constructor.+ ASIO_DECL execution_context();++ /// Destructor.+ ASIO_DECL ~execution_context();++protected:+ /// Shuts down all services in the context.+ /**+ * This function is implemented as follows:+ *+ * @li For each service object @c svc in the execution_context set, in+ * reverse order of the beginning of service object lifetime, performs @c+ * svc->shutdown().+ */+ ASIO_DECL void shutdown();++ /// Destroys all services in the context.+ /**+ * This function is implemented as follows:+ *+ * @li For each service object @c svc in the execution_context set, in+ * reverse order * of the beginning of service object lifetime, performs+ * <tt>delete static_cast<execution_context::service*>(svc)</tt>.+ */+ ASIO_DECL void destroy();++public:+ /// Fork-related event notifications.+ enum fork_event+ {+ /// Notify the context that the process is about to fork.+ fork_prepare,++ /// Notify the context that the process has forked and is the parent.+ fork_parent,++ /// Notify the context that the process has forked and is the child.+ fork_child+ };++ /// Notify the execution_context of a fork-related event.+ /**+ * This function is used to inform the execution_context that the process is+ * about to fork, or has just forked. This allows the execution_context, and+ * the services it contains, to perform any necessary housekeeping to ensure+ * correct operation following a fork.+ *+ * This function must not be called while any other execution_context+ * function, or any function associated with the execution_context's derived+ * class, is being called in another thread. It is, however, safe to call+ * this function from within a completion handler, provided no other thread+ * is accessing the execution_context or its derived class.+ *+ * @param event A fork-related event.+ *+ * @throws asio::system_error Thrown on failure. If the notification+ * fails the execution_context object should no longer be used and should be+ * destroyed.+ *+ * @par Example+ * The following code illustrates how to incorporate the notify_fork()+ * function:+ * @code my_execution_context.notify_fork(execution_context::fork_prepare);+ * if (fork() == 0)+ * {+ * // This is the child process.+ * my_execution_context.notify_fork(execution_context::fork_child);+ * }+ * else+ * {+ * // This is the parent process.+ * my_execution_context.notify_fork(execution_context::fork_parent);+ * } @endcode+ *+ * @note For each service object @c svc in the execution_context set,+ * performs <tt>svc->notify_fork();</tt>. When processing the fork_prepare+ * event, services are visited in reverse order of the beginning of service+ * object lifetime. Otherwise, services are visited in order of the beginning+ * of service object lifetime.+ */+ ASIO_DECL void notify_fork(fork_event event);++ /// Obtain the service object corresponding to the given type.+ /**+ * This function is used to locate a service object that corresponds to the+ * given service type. If there is no existing implementation of the service,+ * then the execution_context will create a new instance of the service.+ *+ * @param e The execution_context object that owns the service.+ *+ * @return The service interface implementing the specified service type.+ * Ownership of the service interface is not transferred to the caller.+ */+ template <typename Service>+ friend Service& use_service(execution_context& e);++ /// Obtain the service object corresponding to the given type.+ /**+ * This function is used to locate a service object that corresponds to the+ * given service type. If there is no existing implementation of the service,+ * then the io_context will create a new instance of the service.+ *+ * @param ioc The io_context object that owns the service.+ *+ * @return The service interface implementing the specified service type.+ * Ownership of the service interface is not transferred to the caller.+ *+ * @note This overload is preserved for backwards compatibility with services+ * that inherit from io_context::service.+ */+ template <typename Service>+ friend Service& use_service(io_context& ioc);++#if defined(GENERATING_DOCUMENTATION)++ /// Creates a service object and adds it to the execution_context.+ /**+ * This function is used to add a service to the execution_context.+ *+ * @param e The execution_context object that owns the service.+ *+ * @param args Zero or more arguments to be passed to the service+ * constructor.+ *+ * @throws asio::service_already_exists Thrown if a service of the+ * given type is already present in the execution_context.+ */+ template <typename Service, typename... Args>+ friend Service& make_service(execution_context& e, Args&&... args);++#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Service, typename... Args>+ friend Service& make_service(execution_context& e,+ ASIO_MOVE_ARG(Args)... args);++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Service>+ friend Service& make_service(execution_context& e);++#define ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \+ template <typename Service, ASIO_VARIADIC_TPARAMS(n)> \+ friend Service& make_service(execution_context& e, \+ ASIO_VARIADIC_MOVE_PARAMS(n)); \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_MAKE_SERVICE_DEF)+#undef ASIO_PRIVATE_MAKE_SERVICE_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ /// (Deprecated: Use make_service().) Add a service object to the+ /// execution_context.+ /**+ * This function is used to add a service to the execution_context.+ *+ * @param e The execution_context object that owns the service.+ *+ * @param svc The service object. On success, ownership of the service object+ * is transferred to the execution_context. When the execution_context object+ * is destroyed, it will destroy the service object by performing: @code+ * delete static_cast<execution_context::service*>(svc) @endcode+ *+ * @throws asio::service_already_exists Thrown if a service of the+ * given type is already present in the execution_context.+ *+ * @throws asio::invalid_service_owner Thrown if the service's owning+ * execution_context is not the execution_context object specified by the+ * @c e parameter.+ */+ template <typename Service>+ friend void add_service(execution_context& e, Service* svc);++ /// Determine if an execution_context contains a specified service type.+ /**+ * This function is used to determine whether the execution_context contains a+ * service object corresponding to the given service type.+ *+ * @param e The execution_context object that owns the service.+ *+ * @return A boolean indicating whether the execution_context contains the+ * service.+ */+ template <typename Service>+ friend bool has_service(execution_context& e);++private:+ // The service registry.+ asio::detail::service_registry* service_registry_;+};++/// Class used to uniquely identify a service.+class execution_context::id+ : private noncopyable+{+public:+ /// Constructor.+ id() {}+};++/// Base class for all io_context services.+class execution_context::service+ : private noncopyable+{+public:+ /// Get the context object that owns the service.+ execution_context& context();++protected:+ /// Constructor.+ /**+ * @param owner The execution_context object that owns the service.+ */+ ASIO_DECL service(execution_context& owner);++ /// Destructor.+ ASIO_DECL virtual ~service();++private:+ /// Destroy all user-defined handler objects owned by the service.+ virtual void shutdown() = 0;++ /// Handle notification of a fork-related event to perform any necessary+ /// housekeeping.+ /**+ * This function is not a pure virtual so that services only have to+ * implement it if necessary. The default implementation does nothing.+ */+ ASIO_DECL virtual void notify_fork(+ execution_context::fork_event event);++ friend class asio::detail::service_registry;+ struct key+ {+ key() : type_info_(0), id_(0) {}+ const std::type_info* type_info_;+ const execution_context::id* id_;+ } key_;++ execution_context& owner_;+ service* next_;+};++/// Exception thrown when trying to add a duplicate service to an+/// execution_context.+class service_already_exists+ : public std::logic_error+{+public:+ ASIO_DECL service_already_exists();+};++/// Exception thrown when trying to add a service object to an+/// execution_context where the service has a different owner.+class invalid_service_owner+ : public std::logic_error+{+public:+ ASIO_DECL invalid_service_owner();+};++namespace detail {++// Special derived service id type to keep classes header-file only.+template <typename Type>+class service_id+ : public execution_context::id+{+};++// Special service base class to keep classes header-file only.+template <typename Type>+class execution_context_service_base+ : public execution_context::service+{+public:+ static service_id<Type> id;++ // Constructor.+ execution_context_service_base(execution_context& e)+ : execution_context::service(e)+ {+ }+};++template <typename Type>+service_id<Type> execution_context_service_base<Type>::id;++} // namespace detail+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/execution_context.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/impl/execution_context.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_EXECUTION_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/executor.hpp view
@@ -0,0 +1,347 @@+//+// executor.hpp+// ~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTOR_HPP+#define ASIO_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_NO_TS_EXECUTORS)++#include <typeinfo>+#include "asio/detail/cstddef.hpp"+#include "asio/detail/executor_function.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/execution_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Exception thrown when trying to access an empty polymorphic executor.+class bad_executor+ : public std::exception+{+public:+ /// Constructor.+ ASIO_DECL bad_executor() ASIO_NOEXCEPT;++ /// Obtain message associated with exception.+ ASIO_DECL virtual const char* what() const+ ASIO_NOEXCEPT_OR_NOTHROW;+};++/// Polymorphic wrapper for executors.+class executor+{+public:+ /// Default constructor.+ executor() ASIO_NOEXCEPT+ : impl_(0)+ {+ }++ /// Construct from nullptr.+ executor(nullptr_t) ASIO_NOEXCEPT+ : impl_(0)+ {+ }++ /// Copy constructor.+ executor(const executor& other) ASIO_NOEXCEPT+ : impl_(other.clone())+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move constructor.+ executor(executor&& other) ASIO_NOEXCEPT+ : impl_(other.impl_)+ {+ other.impl_ = 0;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Construct a polymorphic wrapper for the specified executor.+ template <typename Executor>+ executor(Executor e);++ /// Allocator-aware constructor to create a polymorphic wrapper for the+ /// specified executor.+ template <typename Executor, typename Allocator>+ executor(allocator_arg_t, const Allocator& a, Executor e);++ /// Destructor.+ ~executor()+ {+ destroy();+ }++ /// Assignment operator.+ executor& operator=(const executor& other) ASIO_NOEXCEPT+ {+ destroy();+ impl_ = other.clone();+ return *this;+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ // Move assignment operator.+ executor& operator=(executor&& other) ASIO_NOEXCEPT+ {+ destroy();+ impl_ = other.impl_;+ other.impl_ = 0;+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Assignment operator for nullptr_t.+ executor& operator=(nullptr_t) ASIO_NOEXCEPT+ {+ destroy();+ impl_ = 0;+ return *this;+ }++ /// Assignment operator to create a polymorphic wrapper for the specified+ /// executor.+ template <typename Executor>+ executor& operator=(ASIO_MOVE_ARG(Executor) e) ASIO_NOEXCEPT+ {+ executor tmp(ASIO_MOVE_CAST(Executor)(e));+ destroy();+ impl_ = tmp.impl_;+ tmp.impl_ = 0;+ return *this;+ }++ /// Obtain the underlying execution context.+ execution_context& context() const ASIO_NOEXCEPT+ {+ return get_impl()->context();+ }++ /// Inform the executor that it has some outstanding work to do.+ void on_work_started() const ASIO_NOEXCEPT+ {+ get_impl()->on_work_started();+ }++ /// Inform the executor that some work is no longer outstanding.+ void on_work_finished() const ASIO_NOEXCEPT+ {+ get_impl()->on_work_finished();+ }++ /// Request the executor to invoke the given function object.+ /**+ * This function is used to ask the executor to execute the given function+ * object. The function object is executed according to the rules of the+ * target executor object.+ *+ * @param f The function object to be called. The executor will make a copy+ * of the handler object as required. The function signature of the function+ * object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename Allocator>+ void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;++ /// Request the executor to invoke the given function object.+ /**+ * This function is used to ask the executor to execute the given function+ * object. The function object is executed according to the rules of the+ * target executor object.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename Allocator>+ void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;++ /// Request the executor to invoke the given function object.+ /**+ * This function is used to ask the executor to execute the given function+ * object. The function object is executed according to the rules of the+ * target executor object.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename Allocator>+ void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;++ struct unspecified_bool_type_t {};+ typedef void (*unspecified_bool_type)(unspecified_bool_type_t);+ static void unspecified_bool_true(unspecified_bool_type_t) {}++ /// Operator to test if the executor contains a valid target.+ operator unspecified_bool_type() const ASIO_NOEXCEPT+ {+ return impl_ ? &executor::unspecified_bool_true : 0;+ }++ /// Obtain type information for the target executor object.+ /**+ * @returns If @c *this has a target type of type @c T, <tt>typeid(T)</tt>;+ * otherwise, <tt>typeid(void)</tt>.+ */+#if !defined(ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)+ const std::type_info& target_type() const ASIO_NOEXCEPT+ {+ return impl_ ? impl_->target_type() : typeid(void);+ }+#else // !defined(ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)+ const void* target_type() const ASIO_NOEXCEPT+ {+ return impl_ ? impl_->target_type() : 0;+ }+#endif // !defined(ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION)++ /// Obtain a pointer to the target executor object.+ /**+ * @returns If <tt>target_type() == typeid(T)</tt>, a pointer to the stored+ * executor target; otherwise, a null pointer.+ */+ template <typename Executor>+ Executor* target() ASIO_NOEXCEPT;++ /// Obtain a pointer to the target executor object.+ /**+ * @returns If <tt>target_type() == typeid(T)</tt>, a pointer to the stored+ * executor target; otherwise, a null pointer.+ */+ template <typename Executor>+ const Executor* target() const ASIO_NOEXCEPT;++ /// Compare two executors for equality.+ friend bool operator==(const executor& a,+ const executor& b) ASIO_NOEXCEPT+ {+ if (a.impl_ == b.impl_)+ return true;+ if (!a.impl_ || !b.impl_)+ return false;+ return a.impl_->equals(b.impl_);+ }++ /// Compare two executors for inequality.+ friend bool operator!=(const executor& a,+ const executor& b) ASIO_NOEXCEPT+ {+ return !(a == b);+ }++private:+#if !defined(GENERATING_DOCUMENTATION)+ typedef detail::executor_function function;+ template <typename, typename> class impl;++#if !defined(ASIO_NO_TYPEID)+ typedef const std::type_info& type_id_result_type;+#else // !defined(ASIO_NO_TYPEID)+ typedef const void* type_id_result_type;+#endif // !defined(ASIO_NO_TYPEID)++ template <typename T>+ static type_id_result_type type_id()+ {+#if !defined(ASIO_NO_TYPEID)+ return typeid(T);+#else // !defined(ASIO_NO_TYPEID)+ static int unique_id;+ return &unique_id;+#endif // !defined(ASIO_NO_TYPEID)+ }++ // Base class for all polymorphic executor implementations.+ class impl_base+ {+ public:+ virtual impl_base* clone() const ASIO_NOEXCEPT = 0;+ virtual void destroy() ASIO_NOEXCEPT = 0;+ virtual execution_context& context() ASIO_NOEXCEPT = 0;+ virtual void on_work_started() ASIO_NOEXCEPT = 0;+ virtual void on_work_finished() ASIO_NOEXCEPT = 0;+ virtual void dispatch(ASIO_MOVE_ARG(function)) = 0;+ virtual void post(ASIO_MOVE_ARG(function)) = 0;+ virtual void defer(ASIO_MOVE_ARG(function)) = 0;+ virtual type_id_result_type target_type() const ASIO_NOEXCEPT = 0;+ virtual void* target() ASIO_NOEXCEPT = 0;+ virtual const void* target() const ASIO_NOEXCEPT = 0;+ virtual bool equals(const impl_base* e) const ASIO_NOEXCEPT = 0;++ protected:+ impl_base(bool fast_dispatch) : fast_dispatch_(fast_dispatch) {}+ virtual ~impl_base() {}++ private:+ friend class executor;+ const bool fast_dispatch_;+ };++ // Helper function to check and return the implementation pointer.+ impl_base* get_impl() const+ {+ if (!impl_)+ {+ bad_executor ex;+ asio::detail::throw_exception(ex);+ }+ return impl_;+ }++ // Helper function to clone another implementation.+ impl_base* clone() const ASIO_NOEXCEPT+ {+ return impl_ ? impl_->clone() : 0;+ }++ // Helper function to destroy an implementation.+ void destroy() ASIO_NOEXCEPT+ {+ if (impl_)+ impl_->destroy();+ }++ impl_base* impl_;+#endif // !defined(GENERATING_DOCUMENTATION)+};++} // namespace asio++ASIO_USES_ALLOCATOR(asio::executor)++#include "asio/detail/pop_options.hpp"++#include "asio/impl/executor.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/impl/executor.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // !defined(ASIO_NO_TS_EXECUTORS)++#endif // ASIO_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/executor_work_guard.hpp view
@@ -0,0 +1,287 @@+//+// executor_work_guard.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_EXECUTOR_WORK_GUARD_HPP+#define ASIO_EXECUTOR_WORK_GUARD_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_NO_TS_EXECUTORS)++#include "asio/associated_executor.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution.hpp"+#include "asio/is_executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if !defined(ASIO_EXECUTOR_WORK_GUARD_DECL)+#define ASIO_EXECUTOR_WORK_GUARD_DECL++template <typename Executor, typename = void>+class executor_work_guard;++#endif // !defined(ASIO_EXECUTOR_WORK_GUARD_DECL)++/// An object of type @c executor_work_guard controls ownership of executor work+/// within a scope.+#if defined(GENERATING_DOCUMENTATION)+template <typename Executor>+#else // defined(GENERATING_DOCUMENTATION)+template <typename Executor, typename>+#endif // defined(GENERATING_DOCUMENTATION)+class executor_work_guard+{+public:+ /// The underlying executor type.+ typedef Executor executor_type;++ /// Constructs a @c executor_work_guard object for the specified executor.+ /**+ * Stores a copy of @c e and calls <tt>on_work_started()</tt> on it.+ */+ explicit executor_work_guard(const executor_type& e) ASIO_NOEXCEPT+ : executor_(e),+ owns_(true)+ {+ executor_.on_work_started();+ }++ /// Copy constructor.+ executor_work_guard(const executor_work_guard& other) ASIO_NOEXCEPT+ : executor_(other.executor_),+ owns_(other.owns_)+ {+ if (owns_)+ executor_.on_work_started();+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move constructor.+ executor_work_guard(executor_work_guard&& other) ASIO_NOEXCEPT+ : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)),+ owns_(other.owns_)+ {+ other.owns_ = false;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destructor.+ /**+ * Unless the object has already been reset, or is in a moved-from state,+ * calls <tt>on_work_finished()</tt> on the stored executor.+ */+ ~executor_work_guard()+ {+ if (owns_)+ executor_.on_work_finished();+ }++ /// Obtain the associated executor.+ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return executor_;+ }++ /// Whether the executor_work_guard object owns some outstanding work.+ bool owns_work() const ASIO_NOEXCEPT+ {+ return owns_;+ }++ /// Indicate that the work is no longer outstanding.+ /**+ * Unless the object has already been reset, or is in a moved-from state,+ * calls <tt>on_work_finished()</tt> on the stored executor.+ */+ void reset() ASIO_NOEXCEPT+ {+ if (owns_)+ {+ executor_.on_work_finished();+ owns_ = false;+ }+ }++private:+ // Disallow assignment.+ executor_work_guard& operator=(const executor_work_guard&);++ executor_type executor_;+ bool owns_;+};++#if !defined(GENERATING_DOCUMENTATION)++template <typename Executor>+class executor_work_guard<Executor,+ typename enable_if<+ !is_executor<Executor>::value && execution::is_executor<Executor>::value+ >::type>+{+public:+ typedef Executor executor_type;++ explicit executor_work_guard(const executor_type& e) ASIO_NOEXCEPT+ : executor_(e),+ owns_(true)+ {+ new (&work_) work_type(asio::prefer(executor_,+ execution::outstanding_work.tracked));+ }++ executor_work_guard(const executor_work_guard& other) ASIO_NOEXCEPT+ : executor_(other.executor_),+ owns_(other.owns_)+ {+ if (owns_)+ {+ new (&work_) work_type(asio::prefer(executor_,+ execution::outstanding_work.tracked));+ }+ }++#if defined(ASIO_HAS_MOVE)+ executor_work_guard(executor_work_guard&& other) ASIO_NOEXCEPT+ : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)),+ owns_(other.owns_)+ {+ if (owns_)+ {+ new (&work_) work_type(+ ASIO_MOVE_CAST(work_type)(+ *static_cast<work_type*>(+ static_cast<void*>(&other.work_))));+ other.owns_ = false;+ }+ }+#endif // defined(ASIO_HAS_MOVE)++ ~executor_work_guard()+ {+ if (owns_)+ static_cast<work_type*>(static_cast<void*>(&work_))->~work_type();+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return executor_;+ }++ bool owns_work() const ASIO_NOEXCEPT+ {+ return owns_;+ }++ void reset() ASIO_NOEXCEPT+ {+ if (owns_)+ {+ static_cast<work_type*>(static_cast<void*>(&work_))->~work_type();+ owns_ = false;+ }+ }++private:+ // Disallow assignment.+ executor_work_guard& operator=(const executor_work_guard&);++ typedef typename decay<+ typename prefer_result<+ const executor_type&,+ execution::outstanding_work_t::tracked_t+ >::type+ >::type work_type;++ executor_type executor_;+ typename aligned_storage<sizeof(work_type),+ alignment_of<work_type>::value>::type work_;+ bool owns_;+};++#endif // !defined(GENERATING_DOCUMENTATION)++/// Create an @ref executor_work_guard object.+template <typename Executor>+inline executor_work_guard<Executor> make_work_guard(const Executor& ex,+ typename enable_if<+ is_executor<Executor>::value || execution::is_executor<Executor>::value+ >::type* = 0)+{+ return executor_work_guard<Executor>(ex);+}++/// Create an @ref executor_work_guard object.+template <typename ExecutionContext>+inline executor_work_guard<typename ExecutionContext::executor_type>+make_work_guard(ExecutionContext& ctx,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+{+ return executor_work_guard<typename ExecutionContext::executor_type>(+ ctx.get_executor());+}++/// Create an @ref executor_work_guard object.+template <typename T>+inline executor_work_guard<typename associated_executor<T>::type>+make_work_guard(const T& t,+ typename enable_if<+ !is_executor<T>::value && !execution::is_executor<T>::value+ && !is_convertible<T&, execution_context&+ >::value>::type* = 0)+{+ return executor_work_guard<typename associated_executor<T>::type>(+ associated_executor<T>::get(t));+}++/// Create an @ref executor_work_guard object.+template <typename T, typename Executor>+inline executor_work_guard<typename associated_executor<T, Executor>::type>+make_work_guard(const T& t, const Executor& ex,+ typename enable_if<+ is_executor<Executor>::value || execution::is_executor<Executor>::value+ >::type* = 0)+{+ return executor_work_guard<typename associated_executor<T, Executor>::type>(+ associated_executor<T, Executor>::get(t, ex));+}++/// Create an @ref executor_work_guard object.+template <typename T, typename ExecutionContext>+inline executor_work_guard<typename associated_executor<T,+ typename ExecutionContext::executor_type>::type>+make_work_guard(const T& t, ExecutionContext& ctx,+ typename enable_if<+ !is_executor<T>::value && !execution::is_executor<T>::value+ && !is_convertible<T&, execution_context&>::value+ && is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+{+ return executor_work_guard<typename associated_executor<T,+ typename ExecutionContext::executor_type>::type>(+ associated_executor<T, typename ExecutionContext::executor_type>::get(+ t, ctx.get_executor()));+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_TS_EXECUTORS)++#endif // ASIO_EXECUTOR_WORK_GUARD_HPP
+ link/modules/asio-standalone/asio/include/asio/generic/basic_endpoint.hpp view
@@ -0,0 +1,193 @@+//+// generic/basic_endpoint.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GENERIC_BASIC_ENDPOINT_HPP+#define ASIO_GENERIC_BASIC_ENDPOINT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/generic/detail/endpoint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace generic {++/// Describes an endpoint for any socket type.+/**+ * The asio::generic::basic_endpoint class template describes an endpoint+ * that may be associated with any socket type.+ *+ * @note The socket types sockaddr type must be able to fit into a+ * @c sockaddr_storage structure.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Concepts:+ * Endpoint.+ */+template <typename Protocol>+class basic_endpoint+{+public:+ /// The protocol type associated with the endpoint.+ typedef Protocol protocol_type;++ /// The type of the endpoint structure. This type is dependent on the+ /// underlying implementation of the socket layer.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined data_type;+#else+ typedef asio::detail::socket_addr_type data_type;+#endif++ /// Default constructor.+ basic_endpoint() ASIO_NOEXCEPT+ {+ }++ /// Construct an endpoint from the specified socket address.+ basic_endpoint(const void* socket_address,+ std::size_t socket_address_size, int socket_protocol = 0)+ : impl_(socket_address, socket_address_size, socket_protocol)+ {+ }++ /// Construct an endpoint from the specific endpoint type.+ template <typename Endpoint>+ basic_endpoint(const Endpoint& endpoint)+ : impl_(endpoint.data(), endpoint.size(), endpoint.protocol().protocol())+ {+ }++ /// Copy constructor.+ basic_endpoint(const basic_endpoint& other)+ : impl_(other.impl_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ /// Move constructor.+ basic_endpoint(basic_endpoint&& other)+ : impl_(other.impl_)+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Assign from another endpoint.+ basic_endpoint& operator=(const basic_endpoint& other)+ {+ impl_ = other.impl_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE)+ /// Move-assign from another endpoint.+ basic_endpoint& operator=(basic_endpoint&& other)+ {+ impl_ = other.impl_;+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE)++ /// The protocol associated with the endpoint.+ protocol_type protocol() const+ {+ return protocol_type(impl_.family(), impl_.protocol());+ }++ /// Get the underlying endpoint in the native type.+ data_type* data()+ {+ return impl_.data();+ }++ /// Get the underlying endpoint in the native type.+ const data_type* data() const+ {+ return impl_.data();+ }++ /// Get the underlying size of the endpoint in the native type.+ std::size_t size() const+ {+ return impl_.size();+ }++ /// Set the underlying size of the endpoint in the native type.+ void resize(std::size_t new_size)+ {+ impl_.resize(new_size);+ }++ /// Get the capacity of the endpoint in the native type.+ std::size_t capacity() const+ {+ return impl_.capacity();+ }++ /// Compare two endpoints for equality.+ friend bool operator==(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return e1.impl_ == e2.impl_;+ }++ /// Compare two endpoints for inequality.+ friend bool operator!=(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return !(e1.impl_ == e2.impl_);+ }++ /// Compare endpoints for ordering.+ friend bool operator<(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return e1.impl_ < e2.impl_;+ }++ /// Compare endpoints for ordering.+ friend bool operator>(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return e2.impl_ < e1.impl_;+ }++ /// Compare endpoints for ordering.+ friend bool operator<=(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return !(e2 < e1);+ }++ /// Compare endpoints for ordering.+ friend bool operator>=(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return !(e1 < e2);+ }++private:+ // The underlying generic endpoint.+ asio::generic::detail::endpoint impl_;+};++} // namespace generic+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_GENERIC_BASIC_ENDPOINT_HPP
+ link/modules/asio-standalone/asio/include/asio/generic/datagram_protocol.hpp view
@@ -0,0 +1,123 @@+//+// generic/datagram_protocol.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GENERIC_DATAGRAM_PROTOCOL_HPP+#define ASIO_GENERIC_DATAGRAM_PROTOCOL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <typeinfo>+#include "asio/basic_datagram_socket.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/generic/basic_endpoint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace generic {++/// Encapsulates the flags needed for a generic datagram-oriented socket.+/**+ * The asio::generic::datagram_protocol class contains flags necessary+ * for datagram-oriented sockets of any address family and protocol.+ *+ * @par Examples+ * Constructing using a native address family and socket protocol:+ * @code datagram_protocol p(AF_INET, IPPROTO_UDP); @endcode+ * Constructing from a specific protocol type:+ * @code datagram_protocol p(asio::ip::udp::v4()); @endcode+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Safe.+ *+ * @par Concepts:+ * Protocol.+ */+class datagram_protocol+{+public:+ /// Construct a protocol object for a specific address family and protocol.+ datagram_protocol(int address_family, int socket_protocol)+ : family_(address_family),+ protocol_(socket_protocol)+ {+ }++ /// Construct a generic protocol object from a specific protocol.+ /**+ * @throws @c bad_cast Thrown if the source protocol is not datagram-oriented.+ */+ template <typename Protocol>+ datagram_protocol(const Protocol& source_protocol)+ : family_(source_protocol.family()),+ protocol_(source_protocol.protocol())+ {+ if (source_protocol.type() != type())+ {+ std::bad_cast ex;+ asio::detail::throw_exception(ex);+ }+ }++ /// Obtain an identifier for the type of the protocol.+ int type() const ASIO_NOEXCEPT+ {+ return ASIO_OS_DEF(SOCK_DGRAM);+ }++ /// Obtain an identifier for the protocol.+ int protocol() const ASIO_NOEXCEPT+ {+ return protocol_;+ }++ /// Obtain an identifier for the protocol family.+ int family() const ASIO_NOEXCEPT+ {+ return family_;+ }++ /// Compare two protocols for equality.+ friend bool operator==(const datagram_protocol& p1,+ const datagram_protocol& p2)+ {+ return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_;+ }++ /// Compare two protocols for inequality.+ friend bool operator!=(const datagram_protocol& p1,+ const datagram_protocol& p2)+ {+ return !(p1 == p2);+ }++ /// The type of an endpoint.+ typedef basic_endpoint<datagram_protocol> endpoint;++ /// The generic socket type.+ typedef basic_datagram_socket<datagram_protocol> socket;++private:+ int family_;+ int protocol_;+};++} // namespace generic+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_GENERIC_DATAGRAM_PROTOCOL_HPP
+ link/modules/asio-standalone/asio/include/asio/generic/detail/endpoint.hpp view
@@ -0,0 +1,133 @@+//+// generic/detail/endpoint.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GENERIC_DETAIL_ENDPOINT_HPP+#define ASIO_GENERIC_DETAIL_ENDPOINT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <cstddef>+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace generic {+namespace detail {++// Helper class for implementing a generic socket endpoint.+class endpoint+{+public:+ // Default constructor.+ ASIO_DECL endpoint();++ // Construct an endpoint from the specified raw bytes.+ ASIO_DECL endpoint(const void* sock_addr,+ std::size_t sock_addr_size, int sock_protocol);++ // Copy constructor.+ endpoint(const endpoint& other)+ : data_(other.data_),+ size_(other.size_),+ protocol_(other.protocol_)+ {+ }++ // Assign from another endpoint.+ endpoint& operator=(const endpoint& other)+ {+ data_ = other.data_;+ size_ = other.size_;+ protocol_ = other.protocol_;+ return *this;+ }++ // Get the address family associated with the endpoint.+ int family() const+ {+ return data_.base.sa_family;+ }++ // Get the socket protocol associated with the endpoint.+ int protocol() const+ {+ return protocol_;+ }++ // Get the underlying endpoint in the native type.+ asio::detail::socket_addr_type* data()+ {+ return &data_.base;+ }++ // Get the underlying endpoint in the native type.+ const asio::detail::socket_addr_type* data() const+ {+ return &data_.base;+ }++ // Get the underlying size of the endpoint in the native type.+ std::size_t size() const+ {+ return size_;+ }++ // Set the underlying size of the endpoint in the native type.+ ASIO_DECL void resize(std::size_t size);++ // Get the capacity of the endpoint in the native type.+ std::size_t capacity() const+ {+ return sizeof(asio::detail::sockaddr_storage_type);+ }++ // Compare two endpoints for equality.+ ASIO_DECL friend bool operator==(+ const endpoint& e1, const endpoint& e2);++ // Compare endpoints for ordering.+ ASIO_DECL friend bool operator<(+ const endpoint& e1, const endpoint& e2);++private:+ // The underlying socket address.+ union data_union+ {+ asio::detail::socket_addr_type base;+ asio::detail::sockaddr_storage_type generic;+ } data_;++ // The length of the socket address stored in the endpoint.+ std::size_t size_;++ // The socket protocol associated with the endpoint.+ int protocol_;++ // Initialise with a specified memory.+ ASIO_DECL void init(const void* sock_addr,+ std::size_t sock_addr_size, int sock_protocol);+};++} // namespace detail+} // namespace generic+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/generic/detail/impl/endpoint.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_GENERIC_DETAIL_ENDPOINT_HPP
+ link/modules/asio-standalone/asio/include/asio/generic/detail/impl/endpoint.ipp view
@@ -0,0 +1,110 @@+//+// generic/detail/impl/endpoint.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GENERIC_DETAIL_IMPL_ENDPOINT_IPP+#define ASIO_GENERIC_DETAIL_IMPL_ENDPOINT_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <cstring>+#include <typeinfo>+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/error.hpp"+#include "asio/generic/detail/endpoint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace generic {+namespace detail {++endpoint::endpoint()+{+ init(0, 0, 0);+}++endpoint::endpoint(const void* sock_addr,+ std::size_t sock_addr_size, int sock_protocol)+{+ init(sock_addr, sock_addr_size, sock_protocol);+}++void endpoint::resize(std::size_t new_size)+{+ if (new_size > sizeof(asio::detail::sockaddr_storage_type))+ {+ asio::error_code ec(asio::error::invalid_argument);+ asio::detail::throw_error(ec);+ }+ else+ {+ size_ = new_size;+ protocol_ = 0;+ }+}++bool operator==(const endpoint& e1, const endpoint& e2)+{+ using namespace std; // For memcmp.+ return e1.size() == e2.size() && memcmp(e1.data(), e2.data(), e1.size()) == 0;+}++bool operator<(const endpoint& e1, const endpoint& e2)+{+ if (e1.protocol() < e2.protocol())+ return true;++ if (e1.protocol() > e2.protocol())+ return false;++ using namespace std; // For memcmp.+ std::size_t compare_size = e1.size() < e2.size() ? e1.size() : e2.size();+ int compare_result = memcmp(e1.data(), e2.data(), compare_size);++ if (compare_result < 0)+ return true;++ if (compare_result > 0)+ return false;++ return e1.size() < e2.size();+}++void endpoint::init(const void* sock_addr,+ std::size_t sock_addr_size, int sock_protocol)+{+ if (sock_addr_size > sizeof(asio::detail::sockaddr_storage_type))+ {+ asio::error_code ec(asio::error::invalid_argument);+ asio::detail::throw_error(ec);+ }++ using namespace std; // For memset and memcpy.+ memset(&data_.generic, 0, sizeof(asio::detail::sockaddr_storage_type));+ if (sock_addr_size > 0)+ memcpy(&data_.generic, sock_addr, sock_addr_size);++ size_ = sock_addr_size;+ protocol_ = sock_protocol;+}++} // namespace detail+} // namespace generic+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_GENERIC_DETAIL_IMPL_ENDPOINT_IPP
+ link/modules/asio-standalone/asio/include/asio/generic/raw_protocol.hpp view
@@ -0,0 +1,121 @@+//+// generic/raw_protocol.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GENERIC_RAW_PROTOCOL_HPP+#define ASIO_GENERIC_RAW_PROTOCOL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <typeinfo>+#include "asio/basic_raw_socket.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/generic/basic_endpoint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace generic {++/// Encapsulates the flags needed for a generic raw socket.+/**+ * The asio::generic::raw_protocol class contains flags necessary for+ * raw sockets of any address family and protocol.+ *+ * @par Examples+ * Constructing using a native address family and socket protocol:+ * @code raw_protocol p(AF_INET, IPPROTO_ICMP); @endcode+ * Constructing from a specific protocol type:+ * @code raw_protocol p(asio::ip::icmp::v4()); @endcode+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Safe.+ *+ * @par Concepts:+ * Protocol.+ */+class raw_protocol+{+public:+ /// Construct a protocol object for a specific address family and protocol.+ raw_protocol(int address_family, int socket_protocol)+ : family_(address_family),+ protocol_(socket_protocol)+ {+ }++ /// Construct a generic protocol object from a specific protocol.+ /**+ * @throws @c bad_cast Thrown if the source protocol is not raw-oriented.+ */+ template <typename Protocol>+ raw_protocol(const Protocol& source_protocol)+ : family_(source_protocol.family()),+ protocol_(source_protocol.protocol())+ {+ if (source_protocol.type() != type())+ {+ std::bad_cast ex;+ asio::detail::throw_exception(ex);+ }+ }++ /// Obtain an identifier for the type of the protocol.+ int type() const ASIO_NOEXCEPT+ {+ return ASIO_OS_DEF(SOCK_RAW);+ }++ /// Obtain an identifier for the protocol.+ int protocol() const ASIO_NOEXCEPT+ {+ return protocol_;+ }++ /// Obtain an identifier for the protocol family.+ int family() const ASIO_NOEXCEPT+ {+ return family_;+ }++ /// Compare two protocols for equality.+ friend bool operator==(const raw_protocol& p1, const raw_protocol& p2)+ {+ return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_;+ }++ /// Compare two protocols for inequality.+ friend bool operator!=(const raw_protocol& p1, const raw_protocol& p2)+ {+ return !(p1 == p2);+ }++ /// The type of an endpoint.+ typedef basic_endpoint<raw_protocol> endpoint;++ /// The generic socket type.+ typedef basic_raw_socket<raw_protocol> socket;++private:+ int family_;+ int protocol_;+};++} // namespace generic+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_GENERIC_RAW_PROTOCOL_HPP
+ link/modules/asio-standalone/asio/include/asio/generic/seq_packet_protocol.hpp view
@@ -0,0 +1,122 @@+//+// generic/seq_packet_protocol.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GENERIC_SEQ_PACKET_PROTOCOL_HPP+#define ASIO_GENERIC_SEQ_PACKET_PROTOCOL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <typeinfo>+#include "asio/basic_seq_packet_socket.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/generic/basic_endpoint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace generic {++/// Encapsulates the flags needed for a generic sequenced packet socket.+/**+ * The asio::generic::seq_packet_protocol class contains flags necessary+ * for seq_packet-oriented sockets of any address family and protocol.+ *+ * @par Examples+ * Constructing using a native address family and socket protocol:+ * @code seq_packet_protocol p(AF_INET, IPPROTO_SCTP); @endcode+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Safe.+ *+ * @par Concepts:+ * Protocol.+ */+class seq_packet_protocol+{+public:+ /// Construct a protocol object for a specific address family and protocol.+ seq_packet_protocol(int address_family, int socket_protocol)+ : family_(address_family),+ protocol_(socket_protocol)+ {+ }++ /// Construct a generic protocol object from a specific protocol.+ /**+ * @throws @c bad_cast Thrown if the source protocol is not based around+ * sequenced packets.+ */+ template <typename Protocol>+ seq_packet_protocol(const Protocol& source_protocol)+ : family_(source_protocol.family()),+ protocol_(source_protocol.protocol())+ {+ if (source_protocol.type() != type())+ {+ std::bad_cast ex;+ asio::detail::throw_exception(ex);+ }+ }++ /// Obtain an identifier for the type of the protocol.+ int type() const ASIO_NOEXCEPT+ {+ return ASIO_OS_DEF(SOCK_SEQPACKET);+ }++ /// Obtain an identifier for the protocol.+ int protocol() const ASIO_NOEXCEPT+ {+ return protocol_;+ }++ /// Obtain an identifier for the protocol family.+ int family() const ASIO_NOEXCEPT+ {+ return family_;+ }++ /// Compare two protocols for equality.+ friend bool operator==(const seq_packet_protocol& p1,+ const seq_packet_protocol& p2)+ {+ return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_;+ }++ /// Compare two protocols for inequality.+ friend bool operator!=(const seq_packet_protocol& p1,+ const seq_packet_protocol& p2)+ {+ return !(p1 == p2);+ }++ /// The type of an endpoint.+ typedef basic_endpoint<seq_packet_protocol> endpoint;++ /// The generic socket type.+ typedef basic_seq_packet_socket<seq_packet_protocol> socket;++private:+ int family_;+ int protocol_;+};++} // namespace generic+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_GENERIC_SEQ_PACKET_PROTOCOL_HPP
+ link/modules/asio-standalone/asio/include/asio/generic/stream_protocol.hpp view
@@ -0,0 +1,127 @@+//+// generic/stream_protocol.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_GENERIC_STREAM_PROTOCOL_HPP+#define ASIO_GENERIC_STREAM_PROTOCOL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <typeinfo>+#include "asio/basic_socket_iostream.hpp"+#include "asio/basic_stream_socket.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/generic/basic_endpoint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace generic {++/// Encapsulates the flags needed for a generic stream-oriented socket.+/**+ * The asio::generic::stream_protocol class contains flags necessary for+ * stream-oriented sockets of any address family and protocol.+ *+ * @par Examples+ * Constructing using a native address family and socket protocol:+ * @code stream_protocol p(AF_INET, IPPROTO_TCP); @endcode+ * Constructing from a specific protocol type:+ * @code stream_protocol p(asio::ip::tcp::v4()); @endcode+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Safe.+ *+ * @par Concepts:+ * Protocol.+ */+class stream_protocol+{+public:+ /// Construct a protocol object for a specific address family and protocol.+ stream_protocol(int address_family, int socket_protocol)+ : family_(address_family),+ protocol_(socket_protocol)+ {+ }++ /// Construct a generic protocol object from a specific protocol.+ /**+ * @throws @c bad_cast Thrown if the source protocol is not stream-oriented.+ */+ template <typename Protocol>+ stream_protocol(const Protocol& source_protocol)+ : family_(source_protocol.family()),+ protocol_(source_protocol.protocol())+ {+ if (source_protocol.type() != type())+ {+ std::bad_cast ex;+ asio::detail::throw_exception(ex);+ }+ }++ /// Obtain an identifier for the type of the protocol.+ int type() const ASIO_NOEXCEPT+ {+ return ASIO_OS_DEF(SOCK_STREAM);+ }++ /// Obtain an identifier for the protocol.+ int protocol() const ASIO_NOEXCEPT+ {+ return protocol_;+ }++ /// Obtain an identifier for the protocol family.+ int family() const ASIO_NOEXCEPT+ {+ return family_;+ }++ /// Compare two protocols for equality.+ friend bool operator==(const stream_protocol& p1, const stream_protocol& p2)+ {+ return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_;+ }++ /// Compare two protocols for inequality.+ friend bool operator!=(const stream_protocol& p1, const stream_protocol& p2)+ {+ return !(p1 == p2);+ }++ /// The type of an endpoint.+ typedef basic_endpoint<stream_protocol> endpoint;++ /// The generic socket type.+ typedef basic_stream_socket<stream_protocol> socket;++#if !defined(ASIO_NO_IOSTREAM)+ /// The generic socket iostream type.+ typedef basic_socket_iostream<stream_protocol> iostream;+#endif // !defined(ASIO_NO_IOSTREAM)++private:+ int family_;+ int protocol_;+};++} // namespace generic+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_GENERIC_STREAM_PROTOCOL_HPP
+ link/modules/asio-standalone/asio/include/asio/handler_alloc_hook.hpp view
@@ -0,0 +1,104 @@+//+// handler_alloc_hook.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HANDLER_ALLOC_HOOK_HPP+#define ASIO_HANDLER_ALLOC_HOOK_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(ASIO_NO_DEPRECATED)++// Places in asio that would have previously called the allocate or deallocate+// hooks to manage memory, now call them only to check whether the result types+// are these types. If the result is not the correct type, it indicates that+// the user code still has the old hooks in place, and if so we want to trigger+// a compile error.+enum asio_handler_allocate_is_no_longer_used {};+enum asio_handler_deallocate_is_no_longer_used {};++typedef asio_handler_allocate_is_no_longer_used+ asio_handler_allocate_is_deprecated;+typedef asio_handler_deallocate_is_no_longer_used+ asio_handler_deallocate_is_deprecated;++#else // defined(ASIO_NO_DEPRECATED)++typedef void* asio_handler_allocate_is_deprecated;+typedef void asio_handler_deallocate_is_deprecated;++#endif // defined(ASIO_NO_DEPRECATED)++/// (Deprecated: Use the associated_allocator trait.) Default allocation+/// function for handlers.+/**+ * Asynchronous operations may need to allocate temporary objects. Since+ * asynchronous operations have a handler function object, these temporary+ * objects can be said to be associated with the handler.+ *+ * Implement asio_handler_allocate and asio_handler_deallocate for your own+ * handlers to provide custom allocation for these temporary objects.+ *+ * The default implementation of these allocation hooks uses <tt>::operator+ * new</tt> and <tt>::operator delete</tt>.+ *+ * @note All temporary objects associated with a handler will be deallocated+ * before the upcall to the handler is performed. This allows the same memory to+ * be reused for a subsequent asynchronous operation initiated by the handler.+ *+ * @par Example+ * @code+ * class my_handler;+ *+ * void* asio_handler_allocate(std::size_t size, my_handler* context)+ * {+ * return ::operator new(size);+ * }+ *+ * void asio_handler_deallocate(void* pointer, std::size_t size,+ * my_handler* context)+ * {+ * ::operator delete(pointer);+ * }+ * @endcode+ */+ASIO_DECL asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size, ...);++/// Default deallocation function for handlers.+/**+ * Implement asio_handler_allocate and asio_handler_deallocate for your own+ * handlers to provide custom allocation for the associated temporary objects.+ *+ * The default implementation of these allocation hooks uses <tt>::operator+ * new</tt> and <tt>::operator delete</tt>.+ *+ * @sa asio_handler_allocate.+ */+ASIO_DECL asio_handler_deallocate_is_deprecated+asio_handler_deallocate(void* pointer, std::size_t size, ...);++} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/impl/handler_alloc_hook.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_HANDLER_ALLOC_HOOK_HPP
+ link/modules/asio-standalone/asio/include/asio/handler_continuation_hook.hpp view
@@ -0,0 +1,54 @@+//+// handler_continuation_hook.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HANDLER_CONTINUATION_HOOK_HPP+#define ASIO_HANDLER_CONTINUATION_HOOK_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 {++/// Default continuation function for handlers.+/**+ * Asynchronous operations may represent a continuation of the asynchronous+ * control flow associated with the current handler. The implementation can use+ * this knowledge to optimise scheduling of the handler.+ *+ * Implement asio_handler_is_continuation for your own handlers to indicate+ * when a handler represents a continuation.+ *+ * The default implementation of the continuation hook returns <tt>false</tt>.+ *+ * @par Example+ * @code+ * class my_handler;+ *+ * bool asio_handler_is_continuation(my_handler* context)+ * {+ * return true;+ * }+ * @endcode+ */+inline bool asio_handler_is_continuation(...)+{+ return false;+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_HANDLER_CONTINUATION_HOOK_HPP
+ link/modules/asio-standalone/asio/include/asio/handler_invoke_hook.hpp view
@@ -0,0 +1,111 @@+//+// handler_invoke_hook.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HANDLER_INVOKE_HOOK_HPP+#define ASIO_HANDLER_INVOKE_HOOK_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 {++/** @defgroup asio_handler_invoke asio::asio_handler_invoke+ *+ * @brief (Deprecated: Use the associated_executor trait.) Default invoke+ * function for handlers.+ *+ * Completion handlers for asynchronous operations are invoked by the+ * io_context associated with the corresponding object (e.g. a socket or+ * deadline_timer). Certain guarantees are made on when the handler may be+ * invoked, in particular that a handler can only be invoked from a thread that+ * is currently calling @c run() on the corresponding io_context object.+ * Handlers may subsequently be invoked through other objects (such as+ * io_context::strand objects) that provide additional guarantees.+ *+ * When asynchronous operations are composed from other asynchronous+ * operations, all intermediate handlers should be invoked using the same+ * method as the final handler. This is required to ensure that user-defined+ * objects are not accessed in a way that may violate the guarantees. This+ * hooking function ensures that the invoked method used for the final handler+ * is accessible at each intermediate step.+ *+ * Implement asio_handler_invoke for your own handlers to specify a custom+ * invocation strategy.+ *+ * This default implementation invokes the function object like so:+ * @code function(); @endcode+ * If necessary, the default implementation makes a copy of the function object+ * so that the non-const operator() can be used.+ *+ * @par Example+ * @code+ * class my_handler;+ *+ * template <typename Function>+ * void asio_handler_invoke(Function function, my_handler* context)+ * {+ * context->strand_.dispatch(function);+ * }+ * @endcode+ */+/*@{*/++#if defined(ASIO_NO_DEPRECATED)++// Places in asio that would have previously called the invocation hook to+// execute a handler, now call it only to check whether the result type is this+// type. If the result is not this type, it indicates that the user code still+// has the old hooks in place, and if so we want to trigger a compile error.+enum asio_handler_invoke_is_no_longer_used {};++typedef asio_handler_invoke_is_no_longer_used+ asio_handler_invoke_is_deprecated;++#else // defined(ASIO_NO_DEPRECATED)++typedef void asio_handler_invoke_is_deprecated;++#endif // defined(ASIO_NO_DEPRECATED)++/// Default handler invocation hook used for non-const function objects.+template <typename Function>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(Function& function, ...)+{+ function();+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++/// Default handler invocation hook used for const function objects.+template <typename Function>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(const Function& function, ...)+{+ Function tmp(function);+ tmp();+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++/*@}*/++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_HANDLER_INVOKE_HOOK_HPP
+ link/modules/asio-standalone/asio/include/asio/high_resolution_timer.hpp view
@@ -0,0 +1,44 @@+//+// high_resolution_timer.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_HIGH_RESOLUTION_TIMER_HPP+#define ASIO_HIGH_RESOLUTION_TIMER_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_CHRONO) || defined(GENERATING_DOCUMENTATION)++#include "asio/basic_waitable_timer.hpp"+#include "asio/detail/chrono.hpp"++namespace asio {++/// Typedef for a timer based on the high resolution clock.+/**+ * This typedef uses the C++11 @c <chrono> standard library facility, if+ * available. Otherwise, it may use the Boost.Chrono library. To explicitly+ * utilise Boost.Chrono, use the basic_waitable_timer template directly:+ * @code+ * typedef basic_waitable_timer<boost::chrono::high_resolution_clock> timer;+ * @endcode+ */+typedef basic_waitable_timer<+ chrono::high_resolution_clock>+ high_resolution_timer;++} // namespace asio++#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_HIGH_RESOLUTION_TIMER_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/awaitable.hpp view
@@ -0,0 +1,436 @@+//+// impl/awaitable.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_AWAITABLE_HPP+#define ASIO_IMPL_AWAITABLE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <exception>+#include <new>+#include <tuple>+#include <utility>+#include "asio/detail/thread_context.hpp"+#include "asio/detail/thread_info_base.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/post.hpp"+#include "asio/system_error.hpp"+#include "asio/this_coro.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// An awaitable_thread represents a thread-of-execution that is composed of one+// or more "stack frames", with each frame represented by an awaitable_frame.+// All execution occurs in the context of the awaitable_thread's executor. An+// awaitable_thread continues to "pump" the stack frames by repeatedly resuming+// the top stack frame until the stack is empty, or until ownership of the+// stack is transferred to another awaitable_thread object.+//+// +------------------------------------++// | top_of_stack_ |+// | V+// +--------------+---+ +-----------------++// | | | |+// | awaitable_thread |<---------------------------+ awaitable_frame |+// | | attached_thread_ | |+// +--------------+---+ (Set only when +---+-------------++// | frames are being |+// | actively pumped | caller_+// | by a thread, and |+// | then only for V+// | the top frame.) +-----------------++// | | |+// | | awaitable_frame |+// | | |+// | +---+-------------++// | |+// | | caller_+// | :+// | :+// | |+// | V+// | +-----------------++// | bottom_of_stack_ | |+// +------------------------------->| awaitable_frame |+// | |+// +-----------------+++template <typename Executor>+class awaitable_frame_base+{+public:+#if !defined(ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)+ void* operator new(std::size_t size)+ {+ return asio::detail::thread_info_base::allocate(+ asio::detail::thread_info_base::awaitable_frame_tag(),+ asio::detail::thread_context::thread_call_stack::top(),+ size);+ }++ void operator delete(void* pointer, std::size_t size)+ {+ asio::detail::thread_info_base::deallocate(+ asio::detail::thread_info_base::awaitable_frame_tag(),+ asio::detail::thread_context::thread_call_stack::top(),+ pointer, size);+ }+#endif // !defined(ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)++ // The frame starts in a suspended state until the awaitable_thread object+ // pumps the stack.+ auto initial_suspend() noexcept+ {+ return suspend_always();+ }++ // On final suspension the frame is popped from the top of the stack.+ auto final_suspend() noexcept+ {+ struct result+ {+ awaitable_frame_base* this_;++ bool await_ready() const noexcept+ {+ return false;+ }++ void await_suspend(coroutine_handle<void>) noexcept+ {+ this_->pop_frame();+ }++ void await_resume() const noexcept+ {+ }+ };++ return result{this};+ }++ void set_except(std::exception_ptr e) noexcept+ {+ pending_exception_ = e;+ }++ void set_error(const asio::error_code& ec)+ {+ this->set_except(std::make_exception_ptr(asio::system_error(ec)));+ }++ void unhandled_exception()+ {+ set_except(std::current_exception());+ }++ void rethrow_exception()+ {+ if (pending_exception_)+ {+ std::exception_ptr ex = std::exchange(pending_exception_, nullptr);+ std::rethrow_exception(ex);+ }+ }++ template <typename T>+ auto await_transform(awaitable<T, Executor> a) const+ {+ return a;+ }++ // This await transformation obtains the associated executor of the thread of+ // execution.+ auto await_transform(this_coro::executor_t) noexcept+ {+ struct result+ {+ awaitable_frame_base* this_;++ bool await_ready() const noexcept+ {+ return true;+ }++ void await_suspend(coroutine_handle<void>) noexcept+ {+ }++ auto await_resume() const noexcept+ {+ return this_->attached_thread_->get_executor();+ }+ };++ return result{this};+ }++ // This await transformation is used to run an async operation's initiation+ // function object after the coroutine has been suspended. This ensures that+ // immediate resumption of the coroutine in another thread does not cause a+ // race condition.+ template <typename Function>+ auto await_transform(Function f,+ typename enable_if<+ is_convertible<+ typename result_of<Function(awaitable_frame_base*)>::type,+ awaitable_thread<Executor>*+ >::value+ >::type* = 0)+ {+ struct result+ {+ Function function_;+ awaitable_frame_base* this_;++ bool await_ready() const noexcept+ {+ return false;+ }++ void await_suspend(coroutine_handle<void>) noexcept+ {+ function_(this_);+ }++ void await_resume() const noexcept+ {+ }+ };++ return result{std::move(f), this};+ }++ void attach_thread(awaitable_thread<Executor>* handler) noexcept+ {+ attached_thread_ = handler;+ }++ awaitable_thread<Executor>* detach_thread() noexcept+ {+ return std::exchange(attached_thread_, nullptr);+ }++ void push_frame(awaitable_frame_base<Executor>* caller) noexcept+ {+ caller_ = caller;+ attached_thread_ = caller_->attached_thread_;+ attached_thread_->top_of_stack_ = this;+ caller_->attached_thread_ = nullptr;+ }++ void pop_frame() noexcept+ {+ if (caller_)+ caller_->attached_thread_ = attached_thread_;+ attached_thread_->top_of_stack_ = caller_;+ attached_thread_ = nullptr;+ caller_ = nullptr;+ }++ void resume()+ {+ coro_.resume();+ }++ void destroy()+ {+ coro_.destroy();+ }++protected:+ coroutine_handle<void> coro_ = nullptr;+ awaitable_thread<Executor>* attached_thread_ = nullptr;+ awaitable_frame_base<Executor>* caller_ = nullptr;+ std::exception_ptr pending_exception_ = nullptr;+};++template <typename T, typename Executor>+class awaitable_frame+ : public awaitable_frame_base<Executor>+{+public:+ awaitable_frame() noexcept+ {+ }++ awaitable_frame(awaitable_frame&& other) noexcept+ : awaitable_frame_base<Executor>(std::move(other))+ {+ }++ ~awaitable_frame()+ {+ if (has_result_)+ static_cast<T*>(static_cast<void*>(result_))->~T();+ }++ awaitable<T, Executor> get_return_object() noexcept+ {+ this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);+ return awaitable<T, Executor>(this);+ };++ template <typename U>+ void return_value(U&& u)+ {+ new (&result_) T(std::forward<U>(u));+ has_result_ = true;+ }++ template <typename... Us>+ void return_values(Us&&... us)+ {+ this->return_value(std::forward_as_tuple(std::forward<Us>(us)...));+ }++ T get()+ {+ this->caller_ = nullptr;+ this->rethrow_exception();+ return std::move(*static_cast<T*>(static_cast<void*>(result_)));+ }++private:+ alignas(T) unsigned char result_[sizeof(T)];+ bool has_result_ = false;+};++template <typename Executor>+class awaitable_frame<void, Executor>+ : public awaitable_frame_base<Executor>+{+public:+ awaitable<void, Executor> get_return_object()+ {+ this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);+ return awaitable<void, Executor>(this);+ };++ void return_void()+ {+ }++ void get()+ {+ this->caller_ = nullptr;+ this->rethrow_exception();+ }+};++template <typename Executor>+class awaitable_thread+{+public:+ typedef Executor executor_type;++ // Construct from the entry point of a new thread of execution.+ awaitable_thread(awaitable<void, Executor> p, const Executor& ex)+ : bottom_of_stack_(std::move(p)),+ top_of_stack_(bottom_of_stack_.frame_),+ executor_(ex)+ {+ }++ // Transfer ownership from another awaitable_thread.+ awaitable_thread(awaitable_thread&& other) noexcept+ : bottom_of_stack_(std::move(other.bottom_of_stack_)),+ top_of_stack_(std::exchange(other.top_of_stack_, nullptr)),+ executor_(std::move(other.executor_))+ {+ }++ // Clean up with a last ditch effort to ensure the thread is unwound within+ // the context of the executor.+ ~awaitable_thread()+ {+ if (bottom_of_stack_.valid())+ {+ // Coroutine "stack unwinding" must be performed through the executor.+ (post)(executor_,+ [a = std::move(bottom_of_stack_)]() mutable+ {+ awaitable<void, Executor>(std::move(a));+ });+ }+ }++ executor_type get_executor() const noexcept+ {+ return executor_;+ }++ // Launch a new thread of execution.+ void launch()+ {+ top_of_stack_->attach_thread(this);+ pump();+ }++protected:+ template <typename> friend class awaitable_frame_base;++ // Repeatedly resume the top stack frame until the stack is empty or until it+ // has been transferred to another resumable_thread object.+ void pump()+ {+ do top_of_stack_->resume(); while (top_of_stack_);+ if (bottom_of_stack_.valid())+ {+ awaitable<void, Executor> a(std::move(bottom_of_stack_));+ a.frame_->rethrow_exception();+ }+ }++ awaitable<void, Executor> bottom_of_stack_;+ awaitable_frame_base<Executor>* top_of_stack_;+ executor_type executor_;+};++} // namespace detail+} // namespace asio++#if !defined(GENERATING_DOCUMENTATION)+# if defined(ASIO_HAS_STD_COROUTINE)++namespace std {++template <typename T, typename Executor, typename... Args>+struct coroutine_traits<asio::awaitable<T, Executor>, Args...>+{+ typedef asio::detail::awaitable_frame<T, Executor> promise_type;+};++} // namespace std++# else // defined(ASIO_HAS_STD_COROUTINE)++namespace std { namespace experimental {++template <typename T, typename Executor, typename... Args>+struct coroutine_traits<asio::awaitable<T, Executor>, Args...>+{+ typedef asio::detail::awaitable_frame<T, Executor> promise_type;+};++}} // namespace std::experimental++# endif // defined(ASIO_HAS_STD_COROUTINE)+#endif // !defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_AWAITABLE_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/buffered_read_stream.hpp view
@@ -0,0 +1,527 @@+//+// impl/buffered_read_stream.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_BUFFERED_READ_STREAM_HPP+#define ASIO_IMPL_BUFFERED_READ_STREAM_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/associated_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_cont_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_type_requirements.hpp"+#include "asio/detail/non_const_lvalue.hpp"+#include "asio/detail/type_traits.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++template <typename Stream>+std::size_t buffered_read_stream<Stream>::fill()+{+ detail::buffer_resize_guard<detail::buffered_stream_storage>+ resize_guard(storage_);+ std::size_t previous_size = storage_.size();+ storage_.resize(storage_.capacity());+ storage_.resize(previous_size + next_layer_.read_some(buffer(+ storage_.data() + previous_size,+ storage_.size() - previous_size)));+ resize_guard.commit();+ return storage_.size() - previous_size;+}++template <typename Stream>+std::size_t buffered_read_stream<Stream>::fill(asio::error_code& ec)+{+ detail::buffer_resize_guard<detail::buffered_stream_storage>+ resize_guard(storage_);+ std::size_t previous_size = storage_.size();+ storage_.resize(storage_.capacity());+ storage_.resize(previous_size + next_layer_.read_some(buffer(+ storage_.data() + previous_size,+ storage_.size() - previous_size),+ ec));+ resize_guard.commit();+ return storage_.size() - previous_size;+}++namespace detail+{+ template <typename ReadHandler>+ class buffered_fill_handler+ {+ public:+ buffered_fill_handler(detail::buffered_stream_storage& storage,+ std::size_t previous_size, ReadHandler& handler)+ : storage_(storage),+ previous_size_(previous_size),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ buffered_fill_handler(const buffered_fill_handler& other)+ : storage_(other.storage_),+ previous_size_(other.previous_size_),+ handler_(other.handler_)+ {+ }++ buffered_fill_handler(buffered_fill_handler&& other)+ : storage_(other.storage_),+ previous_size_(other.previous_size_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ const std::size_t bytes_transferred)+ {+ storage_.resize(previous_size_ + bytes_transferred);+ handler_(ec, bytes_transferred);+ }++ //private:+ detail::buffered_stream_storage& storage_;+ std::size_t previous_size_;+ ReadHandler handler_;+ };++ template <typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ buffered_fill_handler<ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ buffered_fill_handler<ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename ReadHandler>+ inline bool asio_handler_is_continuation(+ buffered_fill_handler<ReadHandler>* this_handler)+ {+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ buffered_fill_handler<ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ buffered_fill_handler<ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Stream>+ class initiate_async_buffered_fill+ {+ public:+ typedef typename remove_reference<+ Stream>::type::lowest_layer_type::executor_type executor_type;++ explicit initiate_async_buffered_fill(+ typename remove_reference<Stream>::type& next_layer)+ : next_layer_(next_layer)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return next_layer_.lowest_layer().get_executor();+ }++ template <typename ReadHandler>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ buffered_stream_storage* storage) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ std::size_t previous_size = storage->size();+ storage->resize(storage->capacity());+ next_layer_.async_read_some(+ buffer(+ storage->data() + previous_size,+ storage->size() - previous_size),+ buffered_fill_handler<typename decay<ReadHandler>::type>(+ *storage, previous_size, handler2.value));+ }++ private:+ typename remove_reference<Stream>::type& next_layer_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::buffered_fill_handler<ReadHandler>, Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(const detail::buffered_fill_handler<ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename ReadHandler, typename Executor>+struct associated_executor<+ detail::buffered_fill_handler<ReadHandler>, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(const detail::buffered_fill_handler<ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename Stream>+template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+buffered_read_stream<Stream>::async_fill(+ ASIO_MOVE_ARG(ReadHandler) handler)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_buffered_fill<Stream>(next_layer_),+ handler, &storage_);+}++template <typename Stream>+template <typename MutableBufferSequence>+std::size_t buffered_read_stream<Stream>::read_some(+ const MutableBufferSequence& buffers)+{+ using asio::buffer_size;+ if (buffer_size(buffers) == 0)+ return 0;++ if (storage_.empty())+ this->fill();++ return this->copy(buffers);+}++template <typename Stream>+template <typename MutableBufferSequence>+std::size_t buffered_read_stream<Stream>::read_some(+ const MutableBufferSequence& buffers, asio::error_code& ec)+{+ ec = asio::error_code();++ using asio::buffer_size;+ if (buffer_size(buffers) == 0)+ return 0;++ if (storage_.empty() && !this->fill(ec))+ return 0;++ return this->copy(buffers);+}++namespace detail+{+ template <typename MutableBufferSequence, typename ReadHandler>+ class buffered_read_some_handler+ {+ public:+ buffered_read_some_handler(detail::buffered_stream_storage& storage,+ const MutableBufferSequence& buffers, ReadHandler& handler)+ : storage_(storage),+ buffers_(buffers),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ buffered_read_some_handler(const buffered_read_some_handler& other)+ : storage_(other.storage_),+ buffers_(other.buffers_),+ handler_(other.handler_)+ {+ }++ buffered_read_some_handler(buffered_read_some_handler&& other)+ : storage_(other.storage_),+ buffers_(other.buffers_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec, std::size_t)+ {+ if (ec || storage_.empty())+ {+ const std::size_t length = 0;+ handler_(ec, length);+ }+ else+ {+ const std::size_t bytes_copied = asio::buffer_copy(+ buffers_, storage_.data(), storage_.size());+ storage_.consume(bytes_copied);+ handler_(ec, bytes_copied);+ }+ }++ //private:+ detail::buffered_stream_storage& storage_;+ MutableBufferSequence buffers_;+ ReadHandler handler_;+ };++ template <typename MutableBufferSequence, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ buffered_read_some_handler<+ MutableBufferSequence, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename MutableBufferSequence, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ buffered_read_some_handler<+ MutableBufferSequence, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename MutableBufferSequence, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ buffered_read_some_handler<+ MutableBufferSequence, ReadHandler>* this_handler)+ {+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename MutableBufferSequence,+ typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ buffered_read_some_handler<+ MutableBufferSequence, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename MutableBufferSequence,+ typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ buffered_read_some_handler<+ MutableBufferSequence, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Stream>+ class initiate_async_buffered_read_some+ {+ public:+ typedef typename remove_reference<+ Stream>::type::lowest_layer_type::executor_type executor_type;++ explicit initiate_async_buffered_read_some(+ typename remove_reference<Stream>::type& next_layer)+ : next_layer_(next_layer)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return next_layer_.lowest_layer().get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ buffered_stream_storage* storage,+ 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;++ using asio::buffer_size;+ non_const_lvalue<ReadHandler> handler2(handler);+ if (buffer_size(buffers) == 0 || !storage->empty())+ {+ next_layer_.async_read_some(ASIO_MUTABLE_BUFFER(0, 0),+ buffered_read_some_handler<MutableBufferSequence,+ typename decay<ReadHandler>::type>(+ *storage, buffers, handler2.value));+ }+ else+ {+ initiate_async_buffered_fill<Stream>(this->next_layer_)(+ buffered_read_some_handler<MutableBufferSequence,+ typename decay<ReadHandler>::type>(+ *storage, buffers, handler2.value),+ storage);+ }+ }++ private:+ typename remove_reference<Stream>::type& next_layer_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename MutableBufferSequence,+ typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::buffered_read_some_handler<+ MutableBufferSequence, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename MutableBufferSequence,+ typename ReadHandler, typename Executor>+struct associated_executor<+ detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>,+ Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::buffered_read_some_handler<+ MutableBufferSequence, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename Stream>+template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+buffered_read_stream<Stream>::async_read_some(+ const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_buffered_read_some<Stream>(next_layer_),+ handler, &storage_, buffers);+}++template <typename Stream>+template <typename MutableBufferSequence>+std::size_t buffered_read_stream<Stream>::peek(+ const MutableBufferSequence& buffers)+{+ if (storage_.empty())+ this->fill();+ return this->peek_copy(buffers);+}++template <typename Stream>+template <typename MutableBufferSequence>+std::size_t buffered_read_stream<Stream>::peek(+ const MutableBufferSequence& buffers, asio::error_code& ec)+{+ ec = asio::error_code();+ if (storage_.empty() && !this->fill(ec))+ return 0;+ return this->peek_copy(buffers);+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_BUFFERED_READ_STREAM_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/buffered_write_stream.hpp view
@@ -0,0 +1,507 @@+//+// impl/buffered_write_stream.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_BUFFERED_WRITE_STREAM_HPP+#define ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/associated_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_cont_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_type_requirements.hpp"+#include "asio/detail/non_const_lvalue.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++template <typename Stream>+std::size_t buffered_write_stream<Stream>::flush()+{+ std::size_t bytes_written = write(next_layer_,+ buffer(storage_.data(), storage_.size()));+ storage_.consume(bytes_written);+ return bytes_written;+}++template <typename Stream>+std::size_t buffered_write_stream<Stream>::flush(asio::error_code& ec)+{+ std::size_t bytes_written = write(next_layer_,+ buffer(storage_.data(), storage_.size()),+ transfer_all(), ec);+ storage_.consume(bytes_written);+ return bytes_written;+}++namespace detail+{+ template <typename WriteHandler>+ class buffered_flush_handler+ {+ public:+ buffered_flush_handler(detail::buffered_stream_storage& storage,+ WriteHandler& handler)+ : storage_(storage),+ handler_(ASIO_MOVE_CAST(WriteHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ buffered_flush_handler(const buffered_flush_handler& other)+ : storage_(other.storage_),+ handler_(other.handler_)+ {+ }++ buffered_flush_handler(buffered_flush_handler&& other)+ : storage_(other.storage_),+ handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ const std::size_t bytes_written)+ {+ storage_.consume(bytes_written);+ handler_(ec, bytes_written);+ }++ //private:+ detail::buffered_stream_storage& storage_;+ WriteHandler handler_;+ };++ template <typename WriteHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ buffered_flush_handler<WriteHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename WriteHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ buffered_flush_handler<WriteHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename WriteHandler>+ inline bool asio_handler_is_continuation(+ buffered_flush_handler<WriteHandler>* this_handler)+ {+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ buffered_flush_handler<WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ buffered_flush_handler<WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Stream>+ class initiate_async_buffered_flush+ {+ public:+ typedef typename remove_reference<+ Stream>::type::lowest_layer_type::executor_type executor_type;++ explicit initiate_async_buffered_flush(+ typename remove_reference<Stream>::type& next_layer)+ : next_layer_(next_layer)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return next_layer_.lowest_layer().get_executor();+ }++ template <typename WriteHandler>+ void operator()(ASIO_MOVE_ARG(WriteHandler) handler,+ buffered_stream_storage* storage) 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;++ non_const_lvalue<WriteHandler> handler2(handler);+ async_write(next_layer_, buffer(storage->data(), storage->size()),+ buffered_flush_handler<typename decay<WriteHandler>::type>(+ *storage, handler2.value));+ }++ private:+ typename remove_reference<Stream>::type& next_layer_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename WriteHandler, typename Allocator>+struct associated_allocator<+ detail::buffered_flush_handler<WriteHandler>, Allocator>+{+ typedef typename associated_allocator<WriteHandler, Allocator>::type type;++ static type get(const detail::buffered_flush_handler<WriteHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename WriteHandler, typename Executor>+struct associated_executor<+ detail::buffered_flush_handler<WriteHandler>, Executor>+{+ typedef typename associated_executor<WriteHandler, Executor>::type type;++ static type get(const detail::buffered_flush_handler<WriteHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename Stream>+template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+buffered_write_stream<Stream>::async_flush(+ ASIO_MOVE_ARG(WriteHandler) handler)+{+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_buffered_flush<Stream>(next_layer_),+ handler, &storage_);+}++template <typename Stream>+template <typename ConstBufferSequence>+std::size_t buffered_write_stream<Stream>::write_some(+ const ConstBufferSequence& buffers)+{+ using asio::buffer_size;+ if (buffer_size(buffers) == 0)+ return 0;++ if (storage_.size() == storage_.capacity())+ this->flush();++ return this->copy(buffers);+}++template <typename Stream>+template <typename ConstBufferSequence>+std::size_t buffered_write_stream<Stream>::write_some(+ const ConstBufferSequence& buffers, asio::error_code& ec)+{+ ec = asio::error_code();++ using asio::buffer_size;+ if (buffer_size(buffers) == 0)+ return 0;++ if (storage_.size() == storage_.capacity() && !flush(ec))+ return 0;++ return this->copy(buffers);+}++namespace detail+{+ template <typename ConstBufferSequence, typename WriteHandler>+ class buffered_write_some_handler+ {+ public:+ buffered_write_some_handler(detail::buffered_stream_storage& storage,+ const ConstBufferSequence& buffers, WriteHandler& handler)+ : storage_(storage),+ buffers_(buffers),+ handler_(ASIO_MOVE_CAST(WriteHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ buffered_write_some_handler(const buffered_write_some_handler& other)+ : storage_(other.storage_),+ buffers_(other.buffers_),+ handler_(other.handler_)+ {+ }++ buffered_write_some_handler(buffered_write_some_handler&& other)+ : storage_(other.storage_),+ buffers_(other.buffers_),+ handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec, std::size_t)+ {+ if (ec)+ {+ const std::size_t length = 0;+ handler_(ec, length);+ }+ else+ {+ using asio::buffer_size;+ std::size_t orig_size = storage_.size();+ std::size_t space_avail = storage_.capacity() - orig_size;+ std::size_t bytes_avail = buffer_size(buffers_);+ std::size_t length = bytes_avail < space_avail+ ? bytes_avail : space_avail;+ storage_.resize(orig_size + length);+ const std::size_t bytes_copied = asio::buffer_copy(+ storage_.data() + orig_size, buffers_, length);+ handler_(ec, bytes_copied);+ }+ }++ //private:+ detail::buffered_stream_storage& storage_;+ ConstBufferSequence buffers_;+ WriteHandler handler_;+ };++ template <typename ConstBufferSequence, typename WriteHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ buffered_write_some_handler<+ ConstBufferSequence, WriteHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename ConstBufferSequence, typename WriteHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ buffered_write_some_handler<+ ConstBufferSequence, WriteHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename ConstBufferSequence, typename WriteHandler>+ inline bool asio_handler_is_continuation(+ buffered_write_some_handler<+ ConstBufferSequence, WriteHandler>* this_handler)+ {+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename ConstBufferSequence,+ typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ buffered_write_some_handler<+ ConstBufferSequence, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename ConstBufferSequence,+ typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ buffered_write_some_handler<+ ConstBufferSequence, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Stream>+ class initiate_async_buffered_write_some+ {+ public:+ typedef typename remove_reference<+ Stream>::type::lowest_layer_type::executor_type executor_type;++ explicit initiate_async_buffered_write_some(+ typename remove_reference<Stream>::type& next_layer)+ : next_layer_(next_layer)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return next_layer_.lowest_layer().get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(WriteHandler) handler,+ buffered_stream_storage* storage,+ 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;++ using asio::buffer_size;+ non_const_lvalue<WriteHandler> handler2(handler);+ if (buffer_size(buffers) == 0 || storage->size() < storage->capacity())+ {+ next_layer_.async_write_some(ASIO_CONST_BUFFER(0, 0),+ buffered_write_some_handler<ConstBufferSequence,+ typename decay<WriteHandler>::type>(+ *storage, buffers, handler2.value));+ }+ else+ {+ initiate_async_buffered_flush<Stream>(this->next_layer_)(+ buffered_write_some_handler<ConstBufferSequence,+ typename decay<WriteHandler>::type>(+ *storage, buffers, handler2.value),+ storage);+ }+ }++ private:+ typename remove_reference<Stream>::type& next_layer_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename ConstBufferSequence,+ typename WriteHandler, typename Allocator>+struct associated_allocator<+ detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,+ Allocator>+{+ typedef typename associated_allocator<WriteHandler, Allocator>::type type;++ static type get(+ const detail::buffered_write_some_handler<+ ConstBufferSequence, WriteHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename ConstBufferSequence,+ typename WriteHandler, typename Executor>+struct associated_executor<+ detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,+ Executor>+{+ typedef typename associated_executor<WriteHandler, Executor>::type type;++ static type get(+ const detail::buffered_write_some_handler<+ ConstBufferSequence, WriteHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename Stream>+template <typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+buffered_write_stream<Stream>::async_write_some(+ const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler)+{+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_buffered_write_some<Stream>(next_layer_),+ handler, &storage_, buffers);+}++template <typename Stream>+template <typename ConstBufferSequence>+std::size_t buffered_write_stream<Stream>::copy(+ const ConstBufferSequence& buffers)+{+ using asio::buffer_size;+ std::size_t orig_size = storage_.size();+ std::size_t space_avail = storage_.capacity() - orig_size;+ std::size_t bytes_avail = buffer_size(buffers);+ std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;+ storage_.resize(orig_size + length);+ return asio::buffer_copy(+ storage_.data() + orig_size, buffers, length);+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/co_spawn.hpp view
@@ -0,0 +1,298 @@+//+// impl/co_spawn.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_CO_SPAWN_HPP+#define ASIO_IMPL_CO_SPAWN_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/awaitable.hpp"+#include "asio/dispatch.hpp"+#include "asio/execution/outstanding_work.hpp"+#include "asio/post.hpp"+#include "asio/prefer.hpp"+#include "asio/use_awaitable.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Executor, typename = void>+class co_spawn_work_guard+{+public:+ typedef typename decay<+ typename prefer_result<Executor,+ execution::outstanding_work_t::tracked_t+ >::type+ >::type executor_type;++ co_spawn_work_guard(const Executor& ex)+ : executor_(asio::prefer(ex, execution::outstanding_work.tracked))+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return executor_;+ }++private:+ executor_type executor_;+};++#if !defined(ASIO_NO_TS_EXECUTORS)++template <typename Executor>+struct co_spawn_work_guard<Executor,+ typename enable_if<+ !execution::is_executor<Executor>::value+ >::type> : executor_work_guard<Executor>+{+ co_spawn_work_guard(const Executor& ex)+ : executor_work_guard<Executor>(ex)+ {+ }+};++#endif // !defined(ASIO_NO_TS_EXECUTORS)++template <typename Executor>+inline co_spawn_work_guard<Executor>+make_co_spawn_work_guard(const Executor& ex)+{+ return co_spawn_work_guard<Executor>(ex);+}++template <typename T, typename Executor, typename F, typename Handler>+awaitable<void, Executor> co_spawn_entry_point(+ awaitable<T, Executor>*, Executor ex, F f, Handler handler)+{+ auto spawn_work = make_co_spawn_work_guard(ex);+ auto handler_work = make_co_spawn_work_guard(+ asio::get_associated_executor(handler, ex));++ (void) co_await (post)(spawn_work.get_executor(),+ use_awaitable_t<Executor>{});++ bool done = false;+ try+ {+ T t = co_await f();++ done = true;++ (dispatch)(handler_work.get_executor(),+ [handler = std::move(handler), t = std::move(t)]() mutable+ {+ handler(std::exception_ptr(), std::move(t));+ });+ }+ catch (...)+ {+ if (done)+ throw;++ (dispatch)(handler_work.get_executor(),+ [handler = std::move(handler), e = std::current_exception()]() mutable+ {+ handler(e, T());+ });+ }+}++template <typename Executor, typename F, typename Handler>+awaitable<void, Executor> co_spawn_entry_point(+ awaitable<void, Executor>*, Executor ex, F f, Handler handler)+{+ auto spawn_work = make_co_spawn_work_guard(ex);+ auto handler_work = make_co_spawn_work_guard(+ asio::get_associated_executor(handler, ex));++ (void) co_await (post)(spawn_work.get_executor(),+ use_awaitable_t<Executor>{__FILE__, __LINE__, "co_spawn_entry_point"});++ std::exception_ptr e = nullptr;+ try+ {+ co_await f();+ }+ catch (...)+ {+ e = std::current_exception();+ }++ (dispatch)(handler_work.get_executor(),+ [handler = std::move(handler), e]() mutable+ {+ handler(e);+ });+}++template <typename T, typename Executor>+class awaitable_as_function+{+public:+ explicit awaitable_as_function(awaitable<T, Executor>&& a)+ : awaitable_(std::move(a))+ {+ }++ awaitable<T, Executor> operator()()+ {+ return std::move(awaitable_);+ }++private:+ awaitable<T, Executor> awaitable_;+};++template <typename Executor>+class initiate_co_spawn+{+public:+ typedef Executor executor_type;++ template <typename OtherExecutor>+ explicit initiate_co_spawn(const OtherExecutor& ex)+ : ex_(ex)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return ex_;+ }++ template <typename Handler, typename F>+ void operator()(Handler&& handler, F&& f) const+ {+ typedef typename result_of<F()>::type awaitable_type;++ auto a = (co_spawn_entry_point)(static_cast<awaitable_type*>(nullptr),+ ex_, std::forward<F>(f), std::forward<Handler>(handler));+ awaitable_handler<executor_type, void>(std::move(a), ex_).launch();+ }++private:+ Executor ex_;+};++} // namespace detail++template <typename Executor, typename T, typename AwaitableExecutor,+ ASIO_COMPLETION_TOKEN_FOR(+ void(std::exception_ptr, T)) CompletionToken>+inline ASIO_INITFN_AUTO_RESULT_TYPE(+ CompletionToken, void(std::exception_ptr, T))+co_spawn(const Executor& ex,+ awaitable<T, AwaitableExecutor> a, CompletionToken&& token,+ typename enable_if<+ (is_executor<Executor>::value || execution::is_executor<Executor>::value)+ && is_convertible<Executor, AwaitableExecutor>::value+ >::type*)+{+ return async_initiate<CompletionToken, void(std::exception_ptr, T)>(+ detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),+ token, detail::awaitable_as_function<T, AwaitableExecutor>(std::move(a)));+}++template <typename Executor, typename AwaitableExecutor,+ ASIO_COMPLETION_TOKEN_FOR(+ void(std::exception_ptr)) CompletionToken>+inline ASIO_INITFN_AUTO_RESULT_TYPE(+ CompletionToken, void(std::exception_ptr))+co_spawn(const Executor& ex,+ awaitable<void, AwaitableExecutor> a, CompletionToken&& token,+ typename enable_if<+ (is_executor<Executor>::value || execution::is_executor<Executor>::value)+ && is_convertible<Executor, AwaitableExecutor>::value+ >::type*)+{+ return async_initiate<CompletionToken, void(std::exception_ptr)>(+ detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),+ token, detail::awaitable_as_function<+ void, AwaitableExecutor>(std::move(a)));+}++template <typename ExecutionContext, typename T, typename AwaitableExecutor,+ ASIO_COMPLETION_TOKEN_FOR(+ void(std::exception_ptr, T)) CompletionToken>+inline ASIO_INITFN_AUTO_RESULT_TYPE(+ CompletionToken, void(std::exception_ptr, T))+co_spawn(ExecutionContext& ctx,+ awaitable<T, AwaitableExecutor> a, CompletionToken&& token,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ && is_convertible<typename ExecutionContext::executor_type,+ AwaitableExecutor>::value+ >::type*)+{+ return (co_spawn)(ctx.get_executor(), std::move(a),+ std::forward<CompletionToken>(token));+}++template <typename ExecutionContext, typename AwaitableExecutor,+ ASIO_COMPLETION_TOKEN_FOR(+ void(std::exception_ptr)) CompletionToken>+inline ASIO_INITFN_AUTO_RESULT_TYPE(+ CompletionToken, void(std::exception_ptr))+co_spawn(ExecutionContext& ctx,+ awaitable<void, AwaitableExecutor> a, CompletionToken&& token,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ && is_convertible<typename ExecutionContext::executor_type,+ AwaitableExecutor>::value+ >::type*)+{+ return (co_spawn)(ctx.get_executor(), std::move(a),+ std::forward<CompletionToken>(token));+}++template <typename Executor, typename F,+ ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<+ typename result_of<F()>::type>::type) CompletionToken>+inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,+ typename detail::awaitable_signature<typename result_of<F()>::type>::type)+co_spawn(const Executor& ex, F&& f, CompletionToken&& token,+ typename enable_if<+ is_executor<Executor>::value || execution::is_executor<Executor>::value+ >::type*)+{+ return async_initiate<CompletionToken,+ typename detail::awaitable_signature<typename result_of<F()>::type>::type>(+ detail::initiate_co_spawn<+ typename result_of<F()>::type::executor_type>(ex),+ token, std::forward<F>(f));+}++template <typename ExecutionContext, typename F,+ ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<+ typename result_of<F()>::type>::type) CompletionToken>+inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,+ typename detail::awaitable_signature<typename result_of<F()>::type>::type)+co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type*)+{+ return (co_spawn)(ctx.get_executor(), std::forward<F>(f),+ std::forward<CompletionToken>(token));+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_CO_SPAWN_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/compose.hpp view
@@ -0,0 +1,635 @@+//+// impl/compose.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_COMPOSE_HPP+#define ASIO_IMPL_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/detail/handler_alloc_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/variadic_templates.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 typename decay<+ typename prefer_result<Executor,+ execution::outstanding_work_t::tracked_t+ >::type+ >::type executor_type;++ composed_work_guard(const Executor& ex)+ : executor_(asio::prefer(ex, execution::outstanding_work.tracked))+ {+ }++ void reset()+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return executor_;+ }++ private:+ executor_type executor_;+ };++#if !defined(ASIO_NO_TS_EXECUTORS)++ template <typename Executor>+ struct composed_work_guard<Executor,+ typename enable_if<+ !execution::is_executor<Executor>::value+ >::type> : 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() ASIO_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) ASIO_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);+ }++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Head, typename... Tail>+ struct composed_io_executors<void(Head, Tail...)>+ {+ explicit composed_io_executors(const Head& head,+ const Tail&... tail) ASIO_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...);+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#define ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF(n) \+ template <typename Head, ASIO_VARIADIC_TPARAMS(n)> \+ struct composed_io_executors<void(Head, ASIO_VARIADIC_TARGS(n))> \+ { \+ explicit composed_io_executors(const Head& head, \+ ASIO_VARIADIC_CONSTREF_PARAMS(n)) ASIO_NOEXCEPT \+ : head_(head), \+ tail_(ASIO_VARIADIC_BYVAL_ARGS(n)) \+ { \+ } \+ \+ void reset() \+ { \+ head_.reset(); \+ tail_.reset(); \+ } \+ \+ typedef Head head_type; \+ Head head_; \+ composed_io_executors<void(ASIO_VARIADIC_TARGS(n))> tail_; \+ }; \+ \+ template <typename Head, ASIO_VARIADIC_TPARAMS(n)> \+ inline composed_io_executors<void(Head, ASIO_VARIADIC_TARGS(n))> \+ make_composed_io_executors(const Head& head, \+ ASIO_VARIADIC_CONSTREF_PARAMS(n)) \+ { \+ return composed_io_executors< \+ void(Head, ASIO_VARIADIC_TARGS(n))>( \+ head, ASIO_VARIADIC_BYVAL_ARGS(n)); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF)+#undef ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename>+ struct composed_work;++ template <>+ struct composed_work<void()>+ {+ typedef composed_io_executors<void()> executors_type;++ composed_work(const executors_type&) ASIO_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) ASIO_NOEXCEPT+ : head_(ex.head_)+ {+ }++ void reset()+ {+ head_.reset();+ }++ typedef Head head_type;+ composed_work_guard<Head> head_;+ };++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ 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) ASIO_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_;+ };++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#define ASIO_PRIVATE_COMPOSED_WORK_DEF(n) \+ template <typename Head, ASIO_VARIADIC_TPARAMS(n)> \+ struct composed_work<void(Head, ASIO_VARIADIC_TARGS(n))> \+ { \+ typedef composed_io_executors<void(Head, \+ ASIO_VARIADIC_TARGS(n))> executors_type; \+ \+ explicit composed_work(const executors_type& ex) ASIO_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(ASIO_VARIADIC_TARGS(n))> tail_; \+ }; \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_COMPOSED_WORK_DEF)+#undef ASIO_PRIVATE_COMPOSED_WORK_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)+ 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...)>+#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ template <typename Impl, typename Work, typename Handler, typename Signature>+ class composed_op+#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ {+ public:+ template <typename I, typename W, typename H>+ composed_op(ASIO_MOVE_ARG(I) impl,+ ASIO_MOVE_ARG(W) work,+ ASIO_MOVE_ARG(H) handler)+ : impl_(ASIO_MOVE_CAST(I)(impl)),+ work_(ASIO_MOVE_CAST(W)(work)),+ handler_(ASIO_MOVE_CAST(H)(handler)),+ invocations_(0)+ {+ }++#if defined(ASIO_HAS_MOVE)+ composed_op(composed_op&& other)+ : impl_(ASIO_MOVE_CAST(Impl)(other.impl_)),+ work_(ASIO_MOVE_CAST(Work)(other.work_)),+ handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),+ invocations_(other.invocations_)+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ typedef typename associated_executor<Handler,+ typename composed_work_guard<+ typename Work::head_type+ >::executor_type+ >::type executor_type;++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return (get_associated_executor)(handler_, work_.head_.get_executor());+ }++ typedef typename associated_allocator<Handler,+ std::allocator<void> >::type allocator_type;++ allocator_type get_allocator() const ASIO_NOEXCEPT+ {+ return (get_associated_allocator)(handler_, std::allocator<void>());+ }++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template<typename... T>+ void operator()(ASIO_MOVE_ARG(T)... t)+ {+ if (invocations_ < ~0u)+ ++invocations_;+ impl_(*this, ASIO_MOVE_CAST(T)(t)...);+ }++ void complete(Args... args)+ {+ this->work_.reset();+ this->handler_(ASIO_MOVE_CAST(Args)(args)...);+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ void operator()()+ {+ if (invocations_ < ~0u)+ ++invocations_;+ impl_(*this);+ }++ void complete()+ {+ this->work_.reset();+ this->handler_();+ }++#define ASIO_PRIVATE_COMPOSED_OP_DEF(n) \+ template<ASIO_VARIADIC_TPARAMS(n)> \+ void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ if (invocations_ < ~0u) \+ ++invocations_; \+ impl_(*this, ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ \+ template<ASIO_VARIADIC_TPARAMS(n)> \+ void complete(ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ this->work_.reset(); \+ this->handler_(ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_COMPOSED_OP_DEF)+#undef ASIO_PRIVATE_COMPOSED_OP_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ //private:+ Impl impl_;+ Work work_;+ Handler handler_;+ unsigned invocations_;+ };++ template <typename Impl, typename Work, typename Handler, typename Signature>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ composed_op<Impl, Work, Handler, Signature>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Impl, typename Work, typename Handler, typename Signature>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ composed_op<Impl, Work, Handler, Signature>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ 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 Function, typename Impl,+ typename Work, typename Handler, typename Signature>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ composed_op<Impl, Work, Handler, Signature>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename Impl,+ typename Work, typename Handler, typename Signature>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ composed_op<Impl, Work, Handler, Signature>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ 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, ASIO_MOVE_ARG(T) executors)+ : executors_(ASIO_MOVE_CAST(T)(executors))+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return executors_.head_;+ }++ template <typename Handler, typename Impl>+ void operator()(ASIO_MOVE_ARG(Handler) handler,+ ASIO_MOVE_ARG(Impl) impl) const+ {+ composed_op<typename decay<Impl>::type, composed_work<Executors>,+ typename decay<Handler>::type, Signature>(+ ASIO_MOVE_CAST(Impl)(impl),+ composed_work<Executors>(executors_),+ ASIO_MOVE_CAST(Handler)(handler))();+ }++ private:+ composed_io_executors<Executors> executors_;+ };++ template <typename Signature, typename Executors>+ inline initiate_composed_op<Signature, Executors> make_initiate_composed_op(+ ASIO_MOVE_ARG(composed_io_executors<Executors>) executors)+ {+ return initiate_composed_op<Signature, Executors>(0,+ ASIO_MOVE_CAST(composed_io_executors<Executors>)(executors));+ }++ template <typename IoObject>+ inline typename IoObject::executor_type+ get_composed_io_executor(IoObject& io_object,+ typename enable_if<+ !is_executor<IoObject>::value+ && !execution::is_executor<IoObject>::value+ >::type* = 0)+ {+ return io_object.get_executor();+ }++ template <typename Executor>+ inline const Executor& get_composed_io_executor(const Executor& ex,+ typename enable_if<+ is_executor<Executor>::value+ || execution::is_executor<Executor>::value+ >::type* = 0)+ {+ return ex;+ }+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename CompletionToken, typename Signature,+ typename Implementation, typename... IoObjectsOrExecutors>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature)+async_compose(ASIO_MOVE_ARG(Implementation) implementation,+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,+ ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors)+{+ return async_initiate<CompletionToken, Signature>(+ detail::make_initiate_composed_op<Signature>(+ detail::make_composed_io_executors(+ detail::get_composed_io_executor(+ ASIO_MOVE_CAST(IoObjectsOrExecutors)(+ io_objects_or_executors))...)),+ token, ASIO_MOVE_CAST(Implementation)(implementation));+}++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename CompletionToken, typename Signature, typename Implementation>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature)+async_compose(ASIO_MOVE_ARG(Implementation) implementation,+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token)+{+ return async_initiate<CompletionToken, Signature>(+ detail::make_initiate_composed_op<Signature>(+ detail::make_composed_io_executors()),+ token, ASIO_MOVE_CAST(Implementation)(implementation));+}++# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n) \+ ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_##n++# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_1 \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1))+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_2 \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2))+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_3 \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3))+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_4 \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T4)(x4))+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_5 \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T4)(x4)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T5)(x5))+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_6 \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T4)(x4)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T5)(x5)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T6)(x6))+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_7 \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T4)(x4)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T5)(x5)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T6)(x6)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T7)(x7))+# define ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_8 \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T1)(x1)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T2)(x2)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T3)(x3)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T4)(x4)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T5)(x5)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T6)(x6)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T7)(x7)), \+ detail::get_composed_io_executor(ASIO_MOVE_CAST(T8)(x8))++#define ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \+ template <typename CompletionToken, typename Signature, \+ typename Implementation, ASIO_VARIADIC_TPARAMS(n)> \+ ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) \+ async_compose(ASIO_MOVE_ARG(Implementation) implementation, \+ ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \+ ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ return async_initiate<CompletionToken, Signature>( \+ detail::make_initiate_composed_op<Signature>( \+ detail::make_composed_io_executors( \+ ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n))), \+ token, ASIO_MOVE_CAST(Implementation)(implementation)); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_COMPOSE_DEF)+#undef ASIO_PRIVATE_ASYNC_COMPOSE_DEF++#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_1+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_2+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_3+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_4+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_5+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_6+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_7+#undef ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_8++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_COMPOSE_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/connect.hpp view
@@ -0,0 +1,916 @@+//+// impl/connect.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_CONNECT_HPP+#define ASIO_IMPL_CONNECT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include <algorithm>+#include "asio/associated_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_cont_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_tracking.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/post.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++namespace detail+{+ struct default_connect_condition+ {+ template <typename Endpoint>+ bool operator()(const asio::error_code&, const Endpoint&)+ {+ return true;+ }+ };++ template <typename Protocol, typename Iterator>+ inline typename Protocol::endpoint deref_connect_result(+ Iterator iter, asio::error_code& ec)+ {+ return ec ? typename Protocol::endpoint() : *iter;+ }++ template <typename T, typename Iterator>+ struct legacy_connect_condition_helper : T+ {+ typedef char (*fallback_func_type)(...);+ operator fallback_func_type() const;+ };++ template <typename R, typename Arg1, typename Arg2, typename Iterator>+ struct legacy_connect_condition_helper<R (*)(Arg1, Arg2), Iterator>+ {+ R operator()(Arg1, Arg2) const;+ char operator()(...) const;+ };++ template <typename T, typename Iterator>+ struct is_legacy_connect_condition+ {+ static char asio_connect_condition_check(char);+ static char (&asio_connect_condition_check(Iterator))[2];++ static const bool value =+ sizeof(asio_connect_condition_check(+ (*static_cast<legacy_connect_condition_helper<T, Iterator>*>(0))(+ *static_cast<const asio::error_code*>(0),+ *static_cast<const Iterator*>(0)))) != 1;+ };++ template <typename ConnectCondition, typename Iterator>+ inline Iterator call_connect_condition(ConnectCondition& connect_condition,+ const asio::error_code& ec, Iterator next, Iterator end,+ typename enable_if<is_legacy_connect_condition<+ ConnectCondition, Iterator>::value>::type* = 0)+ {+ if (next != end)+ return connect_condition(ec, next);+ return end;+ }++ template <typename ConnectCondition, typename Iterator>+ inline Iterator call_connect_condition(ConnectCondition& connect_condition,+ const asio::error_code& ec, Iterator next, Iterator end,+ typename enable_if<!is_legacy_connect_condition<+ ConnectCondition, Iterator>::value>::type* = 0)+ {+ for (;next != end; ++next)+ if (connect_condition(ec, *next))+ return next;+ return end;+ }+}++template <typename Protocol, typename Executor, typename EndpointSequence>+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints,+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type*)+{+ asio::error_code ec;+ typename Protocol::endpoint result = connect(s, endpoints, ec);+ asio::detail::throw_error(ec, "connect");+ return result;+}++template <typename Protocol, typename Executor, typename EndpointSequence>+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints, asio::error_code& ec,+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type*)+{+ return detail::deref_connect_result<Protocol>(+ connect(s, endpoints.begin(), endpoints.end(),+ detail::default_connect_condition(), ec), ec);+}++#if !defined(ASIO_NO_DEPRECATED)+template <typename Protocol, typename Executor, typename Iterator>+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)+{+ asio::error_code ec;+ Iterator result = connect(s, begin, ec);+ asio::detail::throw_error(ec, "connect");+ return result;+}++template <typename Protocol, typename Executor, typename Iterator>+inline Iterator connect(basic_socket<Protocol, Executor>& s,+ Iterator begin, asio::error_code& ec,+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)+{+ return connect(s, begin, Iterator(), detail::default_connect_condition(), ec);+}+#endif // !defined(ASIO_NO_DEPRECATED)++template <typename Protocol, typename Executor, typename Iterator>+Iterator connect(basic_socket<Protocol, Executor>& s,+ Iterator begin, Iterator end)+{+ asio::error_code ec;+ Iterator result = connect(s, begin, end, ec);+ asio::detail::throw_error(ec, "connect");+ return result;+}++template <typename Protocol, typename Executor, typename Iterator>+inline Iterator connect(basic_socket<Protocol, Executor>& s,+ Iterator begin, Iterator end, asio::error_code& ec)+{+ return connect(s, begin, end, detail::default_connect_condition(), ec);+}++template <typename Protocol, typename Executor,+ typename EndpointSequence, typename ConnectCondition>+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints, ConnectCondition connect_condition,+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type*)+{+ asio::error_code ec;+ typename Protocol::endpoint result = connect(+ s, endpoints, connect_condition, ec);+ asio::detail::throw_error(ec, "connect");+ return result;+}++template <typename Protocol, typename Executor,+ typename EndpointSequence, typename ConnectCondition>+typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints, ConnectCondition connect_condition,+ asio::error_code& ec,+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type*)+{+ return detail::deref_connect_result<Protocol>(+ connect(s, endpoints.begin(), endpoints.end(),+ connect_condition, ec), ec);+}++#if !defined(ASIO_NO_DEPRECATED)+template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition>+Iterator connect(basic_socket<Protocol, Executor>& s,+ Iterator begin, ConnectCondition connect_condition,+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)+{+ asio::error_code ec;+ Iterator result = connect(s, begin, connect_condition, ec);+ asio::detail::throw_error(ec, "connect");+ return result;+}++template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition>+inline Iterator connect(basic_socket<Protocol, Executor>& s,+ Iterator begin, ConnectCondition connect_condition,+ asio::error_code& ec,+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)+{+ return connect(s, begin, Iterator(), connect_condition, ec);+}+#endif // !defined(ASIO_NO_DEPRECATED)++template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition>+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ Iterator end, ConnectCondition connect_condition)+{+ asio::error_code ec;+ Iterator result = connect(s, begin, end, connect_condition, ec);+ asio::detail::throw_error(ec, "connect");+ return result;+}++template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition>+Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ Iterator end, ConnectCondition connect_condition,+ asio::error_code& ec)+{+ ec = asio::error_code();++ for (Iterator iter = begin; iter != end; ++iter)+ {+ iter = (detail::call_connect_condition(connect_condition, ec, iter, end));+ if (iter != end)+ {+ s.close(ec);+ s.connect(*iter, ec);+ if (!ec)+ return iter;+ }+ else+ break;+ }++ if (!ec)+ ec = asio::error::not_found;++ return end;+}++namespace detail+{+ // Enable the empty base class optimisation for the connect condition.+ template <typename ConnectCondition>+ class base_from_connect_condition+ {+ protected:+ explicit base_from_connect_condition(+ const ConnectCondition& connect_condition)+ : connect_condition_(connect_condition)+ {+ }++ template <typename Iterator>+ void check_condition(const asio::error_code& ec,+ Iterator& iter, Iterator& end)+ {+ iter = detail::call_connect_condition(connect_condition_, ec, iter, end);+ }++ private:+ ConnectCondition connect_condition_;+ };++ // The default_connect_condition implementation is essentially a no-op. This+ // template specialisation lets us eliminate all costs associated with it.+ template <>+ class base_from_connect_condition<default_connect_condition>+ {+ protected:+ explicit base_from_connect_condition(const default_connect_condition&)+ {+ }++ template <typename Iterator>+ void check_condition(const asio::error_code&, Iterator&, Iterator&)+ {+ }+ };++ template <typename Protocol, typename Executor, typename EndpointSequence,+ typename ConnectCondition, typename RangeConnectHandler>+ class range_connect_op : base_from_connect_condition<ConnectCondition>+ {+ public:+ range_connect_op(basic_socket<Protocol, Executor>& sock,+ const EndpointSequence& endpoints,+ const ConnectCondition& connect_condition,+ RangeConnectHandler& handler)+ : base_from_connect_condition<ConnectCondition>(connect_condition),+ socket_(sock),+ endpoints_(endpoints),+ index_(0),+ start_(0),+ handler_(ASIO_MOVE_CAST(RangeConnectHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ range_connect_op(const range_connect_op& other)+ : base_from_connect_condition<ConnectCondition>(other),+ socket_(other.socket_),+ endpoints_(other.endpoints_),+ index_(other.index_),+ start_(other.start_),+ handler_(other.handler_)+ {+ }++ range_connect_op(range_connect_op&& other)+ : base_from_connect_condition<ConnectCondition>(other),+ socket_(other.socket_),+ endpoints_(other.endpoints_),+ index_(other.index_),+ start_(other.start_),+ handler_(ASIO_MOVE_CAST(RangeConnectHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(asio::error_code ec, int start = 0)+ {+ this->process(ec, start,+ const_cast<const EndpointSequence&>(endpoints_).begin(),+ const_cast<const EndpointSequence&>(endpoints_).end());+ }++ //private:+ template <typename Iterator>+ void process(asio::error_code ec,+ int start, Iterator begin, Iterator end)+ {+ Iterator iter = begin;+ std::advance(iter, index_);++ switch (start_ = start)+ {+ case 1:+ for (;;)+ {+ this->check_condition(ec, iter, end);+ index_ = std::distance(begin, iter);++ if (iter != end)+ {+ socket_.close(ec);+ ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));+ socket_.async_connect(*iter,+ ASIO_MOVE_CAST(range_connect_op)(*this));+ return;+ }++ if (start)+ {+ ec = asio::error::not_found;+ ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));+ asio::post(socket_.get_executor(),+ detail::bind_handler(+ ASIO_MOVE_CAST(range_connect_op)(*this), ec));+ return;+ }++ /* fall-through */ default:++ if (iter == end)+ break;++ if (!socket_.is_open())+ {+ ec = asio::error::operation_aborted;+ break;+ }++ if (!ec)+ break;++ ++iter;+ ++index_;+ }++ handler_(static_cast<const asio::error_code&>(ec),+ static_cast<const typename Protocol::endpoint&>(+ ec || iter == end ? typename Protocol::endpoint() : *iter));+ }+ }++ basic_socket<Protocol, Executor>& socket_;+ EndpointSequence endpoints_;+ std::size_t index_;+ int start_;+ RangeConnectHandler handler_;+ };++ template <typename Protocol, typename Executor, typename EndpointSequence,+ typename ConnectCondition, typename RangeConnectHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ range_connect_op<Protocol, Executor, EndpointSequence,+ ConnectCondition, RangeConnectHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Protocol, typename Executor, typename EndpointSequence,+ typename ConnectCondition, typename RangeConnectHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ range_connect_op<Protocol, Executor, EndpointSequence,+ ConnectCondition, RangeConnectHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Protocol, typename Executor, typename EndpointSequence,+ typename ConnectCondition, typename RangeConnectHandler>+ inline bool asio_handler_is_continuation(+ range_connect_op<Protocol, Executor, EndpointSequence,+ ConnectCondition, RangeConnectHandler>* this_handler)+ {+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename Executor, typename Protocol,+ typename EndpointSequence, typename ConnectCondition,+ typename RangeConnectHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ range_connect_op<Protocol, Executor, EndpointSequence,+ ConnectCondition, RangeConnectHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename Executor, typename Protocol,+ typename EndpointSequence, typename ConnectCondition,+ typename RangeConnectHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ range_connect_op<Protocol, Executor, EndpointSequence,+ ConnectCondition, RangeConnectHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Protocol, typename Executor>+ class initiate_async_range_connect+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_range_connect(basic_socket<Protocol, Executor>& s)+ : socket_(s)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return socket_.get_executor();+ }++ template <typename RangeConnectHandler,+ typename EndpointSequence, typename ConnectCondition>+ void operator()(ASIO_MOVE_ARG(RangeConnectHandler) handler,+ const EndpointSequence& endpoints,+ const ConnectCondition& connect_condition) const+ {+ // If you get an error on the following line it means that your+ // handler does not meet the documented type requirements for an+ // RangeConnectHandler.+ ASIO_RANGE_CONNECT_HANDLER_CHECK(RangeConnectHandler,+ handler, typename Protocol::endpoint) type_check;++ non_const_lvalue<RangeConnectHandler> handler2(handler);+ range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition,+ typename decay<RangeConnectHandler>::type>(socket_, endpoints,+ connect_condition, handler2.value)(asio::error_code(), 1);+ }++ private:+ basic_socket<Protocol, Executor>& socket_;+ };++ template <typename Protocol, typename Executor, typename Iterator,+ typename ConnectCondition, typename IteratorConnectHandler>+ class iterator_connect_op : base_from_connect_condition<ConnectCondition>+ {+ public:+ iterator_connect_op(basic_socket<Protocol, Executor>& sock,+ const Iterator& begin, const Iterator& end,+ const ConnectCondition& connect_condition,+ IteratorConnectHandler& handler)+ : base_from_connect_condition<ConnectCondition>(connect_condition),+ socket_(sock),+ iter_(begin),+ end_(end),+ start_(0),+ handler_(ASIO_MOVE_CAST(IteratorConnectHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ iterator_connect_op(const iterator_connect_op& other)+ : base_from_connect_condition<ConnectCondition>(other),+ socket_(other.socket_),+ iter_(other.iter_),+ end_(other.end_),+ start_(other.start_),+ handler_(other.handler_)+ {+ }++ iterator_connect_op(iterator_connect_op&& other)+ : base_from_connect_condition<ConnectCondition>(other),+ socket_(other.socket_),+ iter_(other.iter_),+ end_(other.end_),+ start_(other.start_),+ handler_(ASIO_MOVE_CAST(IteratorConnectHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(asio::error_code ec, int start = 0)+ {+ switch (start_ = start)+ {+ case 1:+ for (;;)+ {+ this->check_condition(ec, iter_, end_);++ if (iter_ != end_)+ {+ socket_.close(ec);+ ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));+ socket_.async_connect(*iter_,+ ASIO_MOVE_CAST(iterator_connect_op)(*this));+ return;+ }++ if (start)+ {+ ec = asio::error::not_found;+ ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect"));+ asio::post(socket_.get_executor(),+ detail::bind_handler(+ ASIO_MOVE_CAST(iterator_connect_op)(*this), ec));+ return;+ }++ /* fall-through */ default:++ if (iter_ == end_)+ break;++ if (!socket_.is_open())+ {+ ec = asio::error::operation_aborted;+ break;+ }++ if (!ec)+ break;++ ++iter_;+ }++ handler_(static_cast<const asio::error_code&>(ec),+ static_cast<const Iterator&>(iter_));+ }+ }++ //private:+ basic_socket<Protocol, Executor>& socket_;+ Iterator iter_;+ Iterator end_;+ int start_;+ IteratorConnectHandler handler_;+ };++ template <typename Protocol, typename Executor, typename Iterator,+ typename ConnectCondition, typename IteratorConnectHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ iterator_connect_op<Protocol, Executor, Iterator,+ ConnectCondition, IteratorConnectHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Protocol, typename Executor, typename Iterator,+ typename ConnectCondition, typename IteratorConnectHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ iterator_connect_op<Protocol, Executor, Iterator,+ ConnectCondition, IteratorConnectHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Protocol, typename Executor, typename Iterator,+ typename ConnectCondition, typename IteratorConnectHandler>+ inline bool asio_handler_is_continuation(+ iterator_connect_op<Protocol, Executor, Iterator,+ ConnectCondition, IteratorConnectHandler>* this_handler)+ {+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename Executor, typename Protocol,+ typename Iterator, typename ConnectCondition,+ typename IteratorConnectHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ iterator_connect_op<Protocol, Executor, Iterator,+ ConnectCondition, IteratorConnectHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename Executor, typename Protocol,+ typename Iterator, typename ConnectCondition,+ typename IteratorConnectHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ iterator_connect_op<Protocol, Executor, Iterator,+ ConnectCondition, IteratorConnectHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Protocol, typename Executor>+ class initiate_async_iterator_connect+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_iterator_connect(+ basic_socket<Protocol, Executor>& s)+ : socket_(s)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return socket_.get_executor();+ }++ template <typename IteratorConnectHandler,+ typename Iterator, typename ConnectCondition>+ void operator()(ASIO_MOVE_ARG(IteratorConnectHandler) handler,+ Iterator begin, Iterator end,+ const ConnectCondition& connect_condition) const+ {+ // If you get an error on the following line it means that your+ // handler does not meet the documented type requirements for an+ // IteratorConnectHandler.+ ASIO_ITERATOR_CONNECT_HANDLER_CHECK(+ IteratorConnectHandler, handler, Iterator) type_check;++ non_const_lvalue<IteratorConnectHandler> handler2(handler);+ iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition,+ typename decay<IteratorConnectHandler>::type>(socket_, begin, end,+ connect_condition, handler2.value)(asio::error_code(), 1);+ }++ private:+ basic_socket<Protocol, Executor>& socket_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename Protocol, typename Executor, typename EndpointSequence,+ typename ConnectCondition, typename RangeConnectHandler, typename Allocator>+struct associated_allocator<+ detail::range_connect_op<Protocol, Executor, EndpointSequence,+ ConnectCondition, RangeConnectHandler>, Allocator>+{+ typedef typename associated_allocator<+ RangeConnectHandler, Allocator>::type type;++ static type get(+ const detail::range_connect_op<Protocol, Executor, EndpointSequence,+ ConnectCondition, RangeConnectHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<RangeConnectHandler,+ Allocator>::get(h.handler_, a);+ }+};++template <typename Protocol, typename Executor, typename EndpointSequence,+ typename ConnectCondition, typename RangeConnectHandler, typename Executor1>+struct associated_executor<+ detail::range_connect_op<Protocol, Executor, EndpointSequence,+ ConnectCondition, RangeConnectHandler>, Executor1>+ : detail::associated_executor_forwarding_base<RangeConnectHandler, Executor1>+{+ typedef typename associated_executor<+ RangeConnectHandler, Executor1>::type type;++ static type get(+ const detail::range_connect_op<Protocol, Executor, EndpointSequence,+ ConnectCondition, RangeConnectHandler>& h,+ const Executor1& ex = Executor1()) ASIO_NOEXCEPT+ {+ return associated_executor<RangeConnectHandler,+ Executor1>::get(h.handler_, ex);+ }+};++template <typename Protocol, typename Executor, typename Iterator,+ typename ConnectCondition, typename IteratorConnectHandler,+ typename Allocator>+struct associated_allocator<+ detail::iterator_connect_op<Protocol, Executor,+ Iterator, ConnectCondition, IteratorConnectHandler>,+ Allocator>+{+ typedef typename associated_allocator<+ IteratorConnectHandler, Allocator>::type type;++ static type get(+ const detail::iterator_connect_op<Protocol, Executor,+ Iterator, ConnectCondition, IteratorConnectHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<IteratorConnectHandler,+ Allocator>::get(h.handler_, a);+ }+};++template <typename Protocol, typename Executor, typename Iterator,+ typename ConnectCondition, typename IteratorConnectHandler,+ typename Executor1>+struct associated_executor<+ detail::iterator_connect_op<Protocol, Executor,+ Iterator, ConnectCondition, IteratorConnectHandler>,+ Executor1>+ : detail::associated_executor_forwarding_base<+ IteratorConnectHandler, Executor1>+{+ typedef typename associated_executor<+ IteratorConnectHandler, Executor1>::type type;++ static type get(+ const detail::iterator_connect_op<Protocol, Executor,+ Iterator, ConnectCondition, IteratorConnectHandler>& h,+ const Executor1& ex = Executor1()) ASIO_NOEXCEPT+ {+ return associated_executor<IteratorConnectHandler,+ Executor1>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename Protocol, typename Executor, typename EndpointSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ typename Protocol::endpoint)) RangeConnectHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,+ void (asio::error_code, typename Protocol::endpoint))+async_connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints,+ ASIO_MOVE_ARG(RangeConnectHandler) handler,+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type*)+{+ return async_initiate<RangeConnectHandler,+ void (asio::error_code, typename Protocol::endpoint)>(+ detail::initiate_async_range_connect<Protocol, Executor>(s),+ handler, endpoints, detail::default_connect_condition());+}++#if !defined(ASIO_NO_DEPRECATED)+template <typename Protocol, typename Executor, typename Iterator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ Iterator)) IteratorConnectHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,+ void (asio::error_code, Iterator))+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ ASIO_MOVE_ARG(IteratorConnectHandler) handler,+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)+{+ return async_initiate<IteratorConnectHandler,+ void (asio::error_code, Iterator)>(+ detail::initiate_async_iterator_connect<Protocol, Executor>(s),+ handler, begin, Iterator(), detail::default_connect_condition());+}+#endif // !defined(ASIO_NO_DEPRECATED)++template <typename Protocol, typename Executor, typename Iterator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ Iterator)) IteratorConnectHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,+ void (asio::error_code, Iterator))+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end,+ ASIO_MOVE_ARG(IteratorConnectHandler) handler)+{+ return async_initiate<IteratorConnectHandler,+ void (asio::error_code, Iterator)>(+ detail::initiate_async_iterator_connect<Protocol, Executor>(s),+ handler, begin, end, detail::default_connect_condition());+}++template <typename Protocol, typename Executor,+ typename EndpointSequence, typename ConnectCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ typename Protocol::endpoint)) RangeConnectHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,+ void (asio::error_code, typename Protocol::endpoint))+async_connect(basic_socket<Protocol, Executor>& s,+ const EndpointSequence& endpoints, ConnectCondition connect_condition,+ ASIO_MOVE_ARG(RangeConnectHandler) handler,+ typename enable_if<is_endpoint_sequence<+ EndpointSequence>::value>::type*)+{+ return async_initiate<RangeConnectHandler,+ void (asio::error_code, typename Protocol::endpoint)>(+ detail::initiate_async_range_connect<Protocol, Executor>(s),+ handler, endpoints, connect_condition);+}++#if !defined(ASIO_NO_DEPRECATED)+template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ Iterator)) IteratorConnectHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,+ void (asio::error_code, Iterator))+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ ConnectCondition connect_condition,+ ASIO_MOVE_ARG(IteratorConnectHandler) handler,+ typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*)+{+ return async_initiate<IteratorConnectHandler,+ void (asio::error_code, Iterator)>(+ detail::initiate_async_iterator_connect<Protocol, Executor>(s),+ handler, begin, Iterator(), connect_condition);+}+#endif // !defined(ASIO_NO_DEPRECATED)++template <typename Protocol, typename Executor,+ typename Iterator, typename ConnectCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ Iterator)) IteratorConnectHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,+ void (asio::error_code, Iterator))+async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,+ Iterator end, ConnectCondition connect_condition,+ ASIO_MOVE_ARG(IteratorConnectHandler) handler)+{+ return async_initiate<IteratorConnectHandler,+ void (asio::error_code, Iterator)>(+ detail::initiate_async_iterator_connect<Protocol, Executor>(s),+ handler, begin, end, connect_condition);+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_CONNECT_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/defer.hpp view
@@ -0,0 +1,248 @@+//+// impl/defer.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_DEFER_HPP+#define ASIO_IMPL_DEFER_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_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/detail/work_dispatcher.hpp"+#include "asio/execution/allocator.hpp"+#include "asio/execution/blocking.hpp"+#include "asio/execution/relationship.hpp"+#include "asio/prefer.hpp"+#include "asio/require.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class initiate_defer+{+public:+ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ execution::is_executor<+ typename associated_executor<+ typename decay<CompletionHandler>::type+ >::type+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_executor<handler_t>::type ex(+ (get_associated_executor)(handler));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ execution::execute(+ asio::prefer(+ asio::require(ex, execution::blocking.never),+ execution::relationship.continuation,+ execution::allocator(alloc)),+ ASIO_MOVE_CAST(CompletionHandler)(handler));+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ !execution::is_executor<+ typename associated_executor<+ typename decay<CompletionHandler>::type+ >::type+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_executor<handler_t>::type ex(+ (get_associated_executor)(handler));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ ex.defer(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);+ }+};++template <typename Executor>+class initiate_defer_with_executor+{+public:+ typedef Executor executor_type;++ explicit initiate_defer_with_executor(const Executor& ex)+ : ex_(ex)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return ex_;+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ !detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ execution::execute(+ asio::prefer(+ asio::require(ex_, execution::blocking.never),+ execution::relationship.continuation,+ execution::allocator(alloc)),+ ASIO_MOVE_CAST(CompletionHandler)(handler));+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typedef typename associated_executor<+ handler_t, Executor>::type handler_ex_t;+ handler_ex_t handler_ex((get_associated_executor)(handler, ex_));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ execution::execute(+ asio::prefer(+ asio::require(ex_, execution::blocking.never),+ execution::relationship.continuation,+ execution::allocator(alloc)),+ detail::work_dispatcher<handler_t, handler_ex_t>(+ ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex));+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ !execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ !detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ ex_.defer(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ !execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typedef typename associated_executor<+ handler_t, Executor>::type handler_ex_t;+ handler_ex_t handler_ex((get_associated_executor)(handler, ex_));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ ex_.defer(detail::work_dispatcher<handler_t, handler_ex_t>(+ ASIO_MOVE_CAST(CompletionHandler)(handler),+ handler_ex), alloc);+ }++private:+ Executor ex_;+};++} // namespace detail++template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(+ ASIO_MOVE_ARG(CompletionToken) token)+{+ return async_initiate<CompletionToken, void()>(+ detail::initiate_defer(), token);+}++template <typename Executor,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(+ const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token,+ typename enable_if<+ execution::is_executor<Executor>::value || is_executor<Executor>::value+ >::type*)+{+ return async_initiate<CompletionToken, void()>(+ detail::initiate_defer_with_executor<Executor>(ex), token);+}++template <typename ExecutionContext,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(+ ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token,+ typename enable_if<is_convertible<+ ExecutionContext&, execution_context&>::value>::type*)+{+ return async_initiate<CompletionToken, void()>(+ detail::initiate_defer_with_executor<+ typename ExecutionContext::executor_type>(+ ctx.get_executor()), token);+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_DEFER_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/detached.hpp view
@@ -0,0 +1,130 @@+//+// impl/detached.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_DETACHED_HPP+#define ASIO_IMPL_DETACHED_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/async_result.hpp"+#include "asio/detail/variadic_templates.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++ // Class to adapt a detached_t as a completion handler.+ class detached_handler+ {+ public:+ typedef void result_type;++ detached_handler(detached_t)+ {+ }++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename... Args>+ void operator()(Args...)+ {+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ void operator()()+ {+ }++#define ASIO_PRIVATE_DETACHED_DEF(n) \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ void operator()(ASIO_VARIADIC_TARGS(n)) \+ { \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_DETACHED_DEF)+#undef ASIO_PRIVATE_DETACHED_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ };++} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename Signature>+struct async_result<detached_t, Signature>+{+ typedef asio::detail::detached_handler completion_handler_type;++ typedef void return_type;++ explicit async_result(completion_handler_type&)+ {+ }++ void get()+ {+ }++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Initiation, typename RawCompletionToken, typename... Args>+ static return_type initiate(+ ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_MOVE_ARG(RawCompletionToken),+ ASIO_MOVE_ARG(Args)... args)+ {+ ASIO_MOVE_CAST(Initiation)(initiation)(+ detail::detached_handler(detached_t()),+ ASIO_MOVE_CAST(Args)(args)...);+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Initiation, typename RawCompletionToken>+ static return_type initiate(+ ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_MOVE_ARG(RawCompletionToken))+ {+ ASIO_MOVE_CAST(Initiation)(initiation)(+ detail::detached_handler(detached_t()));+ }++#define ASIO_PRIVATE_INITIATE_DEF(n) \+ template <typename Initiation, typename RawCompletionToken, \+ ASIO_VARIADIC_TPARAMS(n)> \+ static return_type initiate( \+ ASIO_MOVE_ARG(Initiation) initiation, \+ ASIO_MOVE_ARG(RawCompletionToken), \+ ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ ASIO_MOVE_CAST(Initiation)(initiation)( \+ detail::detached_handler(detached_t()), \+ ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)+#undef ASIO_PRIVATE_INITIATE_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+};++#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_DETACHED_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/dispatch.hpp view
@@ -0,0 +1,243 @@+//+// impl/dispatch.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_DISPATCH_HPP+#define ASIO_IMPL_DISPATCH_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_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/detail/work_dispatcher.hpp"+#include "asio/execution/allocator.hpp"+#include "asio/execution/blocking.hpp"+#include "asio/prefer.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class initiate_dispatch+{+public:+ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ execution::is_executor<+ typename associated_executor<+ typename decay<CompletionHandler>::type+ >::type+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_executor<handler_t>::type ex(+ (get_associated_executor)(handler));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ execution::execute(+ asio::prefer(ex,+ execution::blocking.possibly,+ execution::allocator(alloc)),+ ASIO_MOVE_CAST(CompletionHandler)(handler));+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ !execution::is_executor<+ typename associated_executor<+ typename decay<CompletionHandler>::type+ >::type+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_executor<handler_t>::type ex(+ (get_associated_executor)(handler));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ ex.dispatch(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);+ }+};++template <typename Executor>+class initiate_dispatch_with_executor+{+public:+ typedef Executor executor_type;++ explicit initiate_dispatch_with_executor(const Executor& ex)+ : ex_(ex)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return ex_;+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ !detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ execution::execute(+ asio::prefer(ex_,+ execution::blocking.possibly,+ execution::allocator(alloc)),+ ASIO_MOVE_CAST(CompletionHandler)(handler));+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typedef typename associated_executor<+ handler_t, Executor>::type handler_ex_t;+ handler_ex_t handler_ex((get_associated_executor)(handler, ex_));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ execution::execute(+ asio::prefer(ex_,+ execution::blocking.possibly,+ execution::allocator(alloc)),+ detail::work_dispatcher<handler_t, handler_ex_t>(+ ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex));+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ !execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ !detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ ex_.dispatch(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ !execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typedef typename associated_executor<+ handler_t, Executor>::type handler_ex_t;+ handler_ex_t handler_ex((get_associated_executor)(handler, ex_));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ ex_.dispatch(detail::work_dispatcher<handler_t, handler_ex_t>(+ ASIO_MOVE_CAST(CompletionHandler)(handler),+ handler_ex), alloc);+ }++private:+ Executor ex_;+};++} // namespace detail++template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(+ ASIO_MOVE_ARG(CompletionToken) token)+{+ return async_initiate<CompletionToken, void()>(+ detail::initiate_dispatch(), token);+}++template <typename Executor,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(+ const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token,+ typename enable_if<+ execution::is_executor<Executor>::value || is_executor<Executor>::value+ >::type*)+{+ return async_initiate<CompletionToken, void()>(+ detail::initiate_dispatch_with_executor<Executor>(ex), token);+}++template <typename ExecutionContext,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch(+ ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token,+ typename enable_if<is_convertible<+ ExecutionContext&, execution_context&>::value>::type*)+{+ return async_initiate<CompletionToken, void()>(+ detail::initiate_dispatch_with_executor<+ typename ExecutionContext::executor_type>(+ ctx.get_executor()), token);+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_DISPATCH_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/error.ipp view
@@ -0,0 +1,128 @@+//+// impl/error.ipp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_ERROR_IPP+#define ASIO_IMPL_ERROR_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <string>+#include "asio/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace error {++#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++namespace detail {++class netdb_category : public asio::error_category+{+public:+ const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT+ {+ return "asio.netdb";+ }++ std::string message(int value) const+ {+ if (value == error::host_not_found)+ return "Host not found (authoritative)";+ if (value == error::host_not_found_try_again)+ return "Host not found (non-authoritative), try again later";+ if (value == error::no_data)+ return "The query is valid, but it does not have associated data";+ if (value == error::no_recovery)+ return "A non-recoverable error occurred during database lookup";+ return "asio.netdb error";+ }+};++} // namespace detail++const asio::error_category& get_netdb_category()+{+ static detail::netdb_category instance;+ return instance;+}++namespace detail {++class addrinfo_category : public asio::error_category+{+public:+ const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT+ {+ return "asio.addrinfo";+ }++ std::string message(int value) const+ {+ if (value == error::service_not_found)+ return "Service not found";+ if (value == error::socket_type_not_supported)+ return "Socket type not supported";+ return "asio.addrinfo error";+ }+};++} // namespace detail++const asio::error_category& get_addrinfo_category()+{+ static detail::addrinfo_category instance;+ return instance;+}++#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++namespace detail {++class misc_category : public asio::error_category+{+public:+ const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT+ {+ return "asio.misc";+ }++ std::string message(int value) const+ {+ if (value == error::already_open)+ return "Already open";+ if (value == error::eof)+ return "End of file";+ if (value == error::not_found)+ return "Element not found";+ if (value == error::fd_set_failure)+ return "The descriptor does not fit into the select call's fd_set";+ return "asio.misc error";+ }+};++} // namespace detail++const asio::error_category& get_misc_category()+{+ static detail::misc_category instance;+ return instance;+}++} // namespace error+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_ERROR_IPP
+ link/modules/asio-standalone/asio/include/asio/impl/error_code.ipp view
@@ -0,0 +1,206 @@+//+// impl/error_code.ipp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_ERROR_CODE_IPP+#define ASIO_IMPL_ERROR_CODE_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# include <winerror.h>+#elif defined(ASIO_WINDOWS_RUNTIME)+# include <windows.h>+#else+# include <cerrno>+# include <cstring>+# include <string>+#endif+#include "asio/detail/local_free_on_block_exit.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/error_code.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class system_category : public error_category+{+public:+ const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT+ {+ return "asio.system";+ }++ std::string message(int value) const+ {+#if defined(ASIO_WINDOWS_RUNTIME) || defined(ASIO_WINDOWS_APP)+ std::wstring wmsg(128, wchar_t());+ for (;;)+ {+ DWORD wlength = ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM+ | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value,+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),+ &wmsg[0], static_cast<DWORD>(wmsg.size()), 0);+ if (wlength == 0 && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)+ {+ wmsg.resize(wmsg.size() + wmsg.size() / 2);+ continue;+ }+ if (wlength && wmsg[wlength - 1] == '\n')+ --wlength;+ if (wlength && wmsg[wlength - 1] == '\r')+ --wlength;+ if (wlength)+ {+ std::string msg(wlength * 2, char());+ int length = ::WideCharToMultiByte(CP_ACP, 0,+ wmsg.c_str(), static_cast<int>(wlength),+ &msg[0], static_cast<int>(wlength * 2), 0, 0);+ if (length <= 0)+ return "asio.system error";+ msg.resize(static_cast<std::size_t>(length));+ return msg;+ }+ else+ return "asio.system error";+ }+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ char* msg = 0;+ DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER+ | FORMAT_MESSAGE_FROM_SYSTEM+ | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value,+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0);+ detail::local_free_on_block_exit local_free_obj(msg);+ if (length && msg[length - 1] == '\n')+ msg[--length] = '\0';+ if (length && msg[length - 1] == '\r')+ msg[--length] = '\0';+ if (length)+ return msg;+ else+ return "asio.system error";+#else // defined(ASIO_WINDOWS_DESKTOP) || defined(__CYGWIN__)+#if !defined(__sun)+ if (value == ECANCELED)+ return "Operation aborted.";+#endif // !defined(__sun)+#if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__)+ using namespace std;+ return strerror(value);+#else+ char buf[256] = "";+ using namespace std;+ return strerror_result(strerror_r(value, buf, sizeof(buf)), buf);+#endif+#endif // defined(ASIO_WINDOWS_DESKTOP) || defined(__CYGWIN__)+ }++#if defined(ASIO_HAS_STD_ERROR_CODE)+ std::error_condition default_error_condition(+ int ev) const ASIO_ERROR_CATEGORY_NOEXCEPT+ {+ switch (ev)+ {+ case access_denied:+ return std::errc::permission_denied;+ case address_family_not_supported:+ return std::errc::address_family_not_supported;+ case address_in_use:+ return std::errc::address_in_use;+ case already_connected:+ return std::errc::already_connected;+ case already_started:+ return std::errc::connection_already_in_progress;+ case broken_pipe:+ return std::errc::broken_pipe;+ case connection_aborted:+ return std::errc::connection_aborted;+ case connection_refused:+ return std::errc::connection_refused;+ case connection_reset:+ return std::errc::connection_reset;+ case bad_descriptor:+ return std::errc::bad_file_descriptor;+ case fault:+ return std::errc::bad_address;+ case host_unreachable:+ return std::errc::host_unreachable;+ case in_progress:+ return std::errc::operation_in_progress;+ case interrupted:+ return std::errc::interrupted;+ case invalid_argument:+ return std::errc::invalid_argument;+ case message_size:+ return std::errc::message_size;+ case name_too_long:+ return std::errc::filename_too_long;+ case network_down:+ return std::errc::network_down;+ case network_reset:+ return std::errc::network_reset;+ case network_unreachable:+ return std::errc::network_unreachable;+ case no_descriptors:+ return std::errc::too_many_files_open;+ case no_buffer_space:+ return std::errc::no_buffer_space;+ case no_memory:+ return std::errc::not_enough_memory;+ case no_permission:+ return std::errc::operation_not_permitted;+ case no_protocol_option:+ return std::errc::no_protocol_option;+ case no_such_device:+ return std::errc::no_such_device;+ case not_connected:+ return std::errc::not_connected;+ case not_socket:+ return std::errc::not_a_socket;+ case operation_aborted:+ return std::errc::operation_canceled;+ case operation_not_supported:+ return std::errc::operation_not_supported;+ case shut_down:+ return std::make_error_condition(ev, *this);+ case timed_out:+ return std::errc::timed_out;+ case try_again:+ return std::errc::resource_unavailable_try_again;+ case would_block:+ return std::errc::operation_would_block;+ default:+ return std::make_error_condition(ev, *this);+ }+#endif // defined(ASIO_HAS_STD_ERROR_CODE)++private:+ // Helper function to adapt the result from glibc's variant of strerror_r.+ static const char* strerror_result(int, const char* s) { return s; }+ static const char* strerror_result(const char* s, const char*) { return s; }+};++} // namespace detail++const error_category& system_category()+{+ static detail::system_category instance;+ return instance;+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_ERROR_CODE_IPP
+ link/modules/asio-standalone/asio/include/asio/impl/execution_context.hpp view
@@ -0,0 +1,109 @@+//+// impl/execution_context.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_EXECUTION_CONTEXT_HPP+#define ASIO_IMPL_EXECUTION_CONTEXT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/handler_type_requirements.hpp"+#include "asio/detail/scoped_ptr.hpp"+#include "asio/detail/service_registry.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if !defined(GENERATING_DOCUMENTATION)++template <typename Service>+inline Service& use_service(execution_context& e)+{+ // Check that Service meets the necessary type requirements.+ (void)static_cast<execution_context::service*>(static_cast<Service*>(0));++ return e.service_registry_->template use_service<Service>();+}++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename Service, typename... Args>+Service& make_service(execution_context& e, ASIO_MOVE_ARG(Args)... args)+{+ detail::scoped_ptr<Service> svc(+ new Service(e, ASIO_MOVE_CAST(Args)(args)...));+ e.service_registry_->template add_service<Service>(svc.get());+ Service& result = *svc;+ svc.release();+ return result;+}++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename Service>+Service& make_service(execution_context& e)+{+ detail::scoped_ptr<Service> svc(new Service(e));+ e.service_registry_->template add_service<Service>(svc.get());+ Service& result = *svc;+ svc.release();+ return result;+}++#define ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \+ template <typename Service, ASIO_VARIADIC_TPARAMS(n)> \+ Service& make_service(execution_context& e, \+ ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ detail::scoped_ptr<Service> svc( \+ new Service(e, ASIO_VARIADIC_MOVE_ARGS(n))); \+ e.service_registry_->template add_service<Service>(svc.get()); \+ Service& result = *svc; \+ svc.release(); \+ return result; \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_MAKE_SERVICE_DEF)+#undef ASIO_PRIVATE_MAKE_SERVICE_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename Service>+inline void add_service(execution_context& e, Service* svc)+{+ // Check that Service meets the necessary type requirements.+ (void)static_cast<execution_context::service*>(static_cast<Service*>(0));++ e.service_registry_->template add_service<Service>(svc);+}++template <typename Service>+inline bool has_service(execution_context& e)+{+ // Check that Service meets the necessary type requirements.+ (void)static_cast<execution_context::service*>(static_cast<Service*>(0));++ return e.service_registry_->template has_service<Service>();+}++#endif // !defined(GENERATING_DOCUMENTATION)++inline execution_context& execution_context::service::context()+{+ return owner_;+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_EXECUTION_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/execution_context.ipp view
@@ -0,0 +1,82 @@+//+// impl/execution_context.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_EXECUTION_CONTEXT_IPP+#define ASIO_IMPL_EXECUTION_CONTEXT_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/execution_context.hpp"+#include "asio/detail/service_registry.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++execution_context::execution_context()+ : service_registry_(new asio::detail::service_registry(*this))+{+}++execution_context::~execution_context()+{+ shutdown();+ destroy();+ delete service_registry_;+}++void execution_context::shutdown()+{+ service_registry_->shutdown_services();+}++void execution_context::destroy()+{+ service_registry_->destroy_services();+}++void execution_context::notify_fork(+ asio::execution_context::fork_event event)+{+ service_registry_->notify_fork(event);+}++execution_context::service::service(execution_context& owner)+ : owner_(owner),+ next_(0)+{+}++execution_context::service::~service()+{+}++void execution_context::service::notify_fork(execution_context::fork_event)+{+}++service_already_exists::service_already_exists()+ : std::logic_error("Service already exists.")+{+}++invalid_service_owner::invalid_service_owner()+ : std::logic_error("Invalid service owner.")+{+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_EXECUTION_CONTEXT_IPP
+ link/modules/asio-standalone/asio/include/asio/impl/executor.hpp view
@@ -0,0 +1,301 @@+//+// impl/executor.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_EXECUTOR_HPP+#define ASIO_IMPL_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_NO_TS_EXECUTORS)++#include "asio/detail/atomic_count.hpp"+#include "asio/detail/global.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/recycling_allocator.hpp"+#include "asio/executor.hpp"+#include "asio/system_executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if !defined(GENERATING_DOCUMENTATION)++// Default polymorphic executor implementation.+template <typename Executor, typename Allocator>+class executor::impl+ : public executor::impl_base+{+public:+ typedef ASIO_REBIND_ALLOC(Allocator, impl) allocator_type;++ static impl_base* create(const Executor& e, Allocator a = Allocator())+ {+ raw_mem mem(a);+ impl* p = new (mem.ptr_) impl(e, a);+ mem.ptr_ = 0;+ return p;+ }++ impl(const Executor& e, const Allocator& a) ASIO_NOEXCEPT+ : impl_base(false),+ ref_count_(1),+ executor_(e),+ allocator_(a)+ {+ }++ impl_base* clone() const ASIO_NOEXCEPT+ {+ detail::ref_count_up(ref_count_);+ return const_cast<impl_base*>(static_cast<const impl_base*>(this));+ }++ void destroy() ASIO_NOEXCEPT+ {+ if (detail::ref_count_down(ref_count_))+ {+ allocator_type alloc(allocator_);+ impl* p = this;+ p->~impl();+ alloc.deallocate(p, 1);+ }+ }++ void on_work_started() ASIO_NOEXCEPT+ {+ executor_.on_work_started();+ }++ void on_work_finished() ASIO_NOEXCEPT+ {+ executor_.on_work_finished();+ }++ execution_context& context() ASIO_NOEXCEPT+ {+ return executor_.context();+ }++ void dispatch(ASIO_MOVE_ARG(function) f)+ {+ executor_.dispatch(ASIO_MOVE_CAST(function)(f), allocator_);+ }++ void post(ASIO_MOVE_ARG(function) f)+ {+ executor_.post(ASIO_MOVE_CAST(function)(f), allocator_);+ }++ void defer(ASIO_MOVE_ARG(function) f)+ {+ executor_.defer(ASIO_MOVE_CAST(function)(f), allocator_);+ }++ type_id_result_type target_type() const ASIO_NOEXCEPT+ {+ return type_id<Executor>();+ }++ void* target() ASIO_NOEXCEPT+ {+ return &executor_;+ }++ const void* target() const ASIO_NOEXCEPT+ {+ return &executor_;+ }++ bool equals(const impl_base* e) const ASIO_NOEXCEPT+ {+ if (this == e)+ return true;+ if (target_type() != e->target_type())+ return false;+ return executor_ == *static_cast<const Executor*>(e->target());+ }++private:+ mutable detail::atomic_count ref_count_;+ Executor executor_;+ Allocator allocator_;++ struct raw_mem+ {+ allocator_type allocator_;+ impl* ptr_;++ explicit raw_mem(const Allocator& a)+ : allocator_(a),+ ptr_(allocator_.allocate(1))+ {+ }++ ~raw_mem()+ {+ if (ptr_)+ allocator_.deallocate(ptr_, 1);+ }++ private:+ // Disallow copying and assignment.+ raw_mem(const raw_mem&);+ raw_mem operator=(const raw_mem&);+ };+};++// Polymorphic executor specialisation for system_executor.+template <typename Allocator>+class executor::impl<system_executor, Allocator>+ : public executor::impl_base+{+public:+ static impl_base* create(const system_executor&,+ const Allocator& = Allocator())+ {+ return &detail::global<impl<system_executor, std::allocator<void> > >();+ }++ impl()+ : impl_base(true)+ {+ }++ impl_base* clone() const ASIO_NOEXCEPT+ {+ return const_cast<impl_base*>(static_cast<const impl_base*>(this));+ }++ void destroy() ASIO_NOEXCEPT+ {+ }++ void on_work_started() ASIO_NOEXCEPT+ {+ executor_.on_work_started();+ }++ void on_work_finished() ASIO_NOEXCEPT+ {+ executor_.on_work_finished();+ }++ execution_context& context() ASIO_NOEXCEPT+ {+ return executor_.context();+ }++ void dispatch(ASIO_MOVE_ARG(function) f)+ {+ executor_.dispatch(ASIO_MOVE_CAST(function)(f),+ std::allocator<void>());+ }++ void post(ASIO_MOVE_ARG(function) f)+ {+ executor_.post(ASIO_MOVE_CAST(function)(f),+ std::allocator<void>());+ }++ void defer(ASIO_MOVE_ARG(function) f)+ {+ executor_.defer(ASIO_MOVE_CAST(function)(f),+ std::allocator<void>());+ }++ type_id_result_type target_type() const ASIO_NOEXCEPT+ {+ return type_id<system_executor>();+ }++ void* target() ASIO_NOEXCEPT+ {+ return &executor_;+ }++ const void* target() const ASIO_NOEXCEPT+ {+ return &executor_;+ }++ bool equals(const impl_base* e) const ASIO_NOEXCEPT+ {+ return this == e;+ }++private:+ system_executor executor_;+};++template <typename Executor>+executor::executor(Executor e)+ : impl_(impl<Executor, std::allocator<void> >::create(e))+{+}++template <typename Executor, typename Allocator>+executor::executor(allocator_arg_t, const Allocator& a, Executor e)+ : impl_(impl<Executor, Allocator>::create(e, a))+{+}++template <typename Function, typename Allocator>+void executor::dispatch(ASIO_MOVE_ARG(Function) f,+ const Allocator& a) const+{+ impl_base* i = get_impl();+ if (i->fast_dispatch_)+ system_executor().dispatch(ASIO_MOVE_CAST(Function)(f), a);+ else+ i->dispatch(function(ASIO_MOVE_CAST(Function)(f), a));+}++template <typename Function, typename Allocator>+void executor::post(ASIO_MOVE_ARG(Function) f,+ const Allocator& a) const+{+ get_impl()->post(function(ASIO_MOVE_CAST(Function)(f), a));+}++template <typename Function, typename Allocator>+void executor::defer(ASIO_MOVE_ARG(Function) f,+ const Allocator& a) const+{+ get_impl()->defer(function(ASIO_MOVE_CAST(Function)(f), a));+}++template <typename Executor>+Executor* executor::target() ASIO_NOEXCEPT+{+ return impl_ && impl_->target_type() == type_id<Executor>()+ ? static_cast<Executor*>(impl_->target()) : 0;+}++template <typename Executor>+const Executor* executor::target() const ASIO_NOEXCEPT+{+ return impl_ && impl_->target_type() == type_id<Executor>()+ ? static_cast<Executor*>(impl_->target()) : 0;+}++#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_TS_EXECUTORS)++#endif // ASIO_IMPL_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/executor.ipp view
@@ -0,0 +1,43 @@+//+// impl/executor.ipp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_EXECUTOR_IPP+#define ASIO_IMPL_EXECUTOR_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if !defined(ASIO_NO_TS_EXECUTORS)++#include "asio/executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++bad_executor::bad_executor() ASIO_NOEXCEPT+{+}++const char* bad_executor::what() const ASIO_NOEXCEPT_OR_NOTHROW+{+ return "bad executor";+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_TS_EXECUTORS)++#endif // ASIO_IMPL_EXECUTOR_IPP
+ link/modules/asio-standalone/asio/include/asio/impl/handler_alloc_hook.ipp view
@@ -0,0 +1,61 @@+//+// impl/handler_alloc_hook.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_HANDLER_ALLOC_HOOK_IPP+#define ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/detail/thread_context.hpp"+#include "asio/detail/thread_info_base.hpp"+#include "asio/handler_alloc_hook.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size, ...)+{+#if defined(ASIO_NO_DEPRECATED)+ (void)size;+ return asio_handler_allocate_is_no_longer_used();+#elif !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+ return detail::thread_info_base::allocate(+ detail::thread_context::thread_call_stack::top(), size);+#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+ return ::operator new(size);+#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+}++asio_handler_deallocate_is_deprecated+asio_handler_deallocate(void* pointer, std::size_t size, ...)+{+#if defined(ASIO_NO_DEPRECATED)+ (void)pointer;+ (void)size;+ return asio_handler_deallocate_is_no_longer_used();+#elif !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+ detail::thread_info_base::deallocate(+ detail::thread_context::thread_call_stack::top(), pointer, size);+#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+ (void)size;+ ::operator delete(pointer);+#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING)+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP
+ link/modules/asio-standalone/asio/include/asio/impl/io_context.hpp view
@@ -0,0 +1,440 @@+//+// impl/io_context.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_IO_CONTEXT_HPP+#define ASIO_IMPL_IO_CONTEXT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/completion_handler.hpp"+#include "asio/detail/executor_op.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/handler_type_requirements.hpp"+#include "asio/detail/non_const_lvalue.hpp"+#include "asio/detail/recycling_allocator.hpp"+#include "asio/detail/service_registry.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/type_traits.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if !defined(GENERATING_DOCUMENTATION)++template <typename Service>+inline Service& use_service(io_context& ioc)+{+ // Check that Service meets the necessary type requirements.+ (void)static_cast<execution_context::service*>(static_cast<Service*>(0));+ (void)static_cast<const execution_context::id*>(&Service::id);++ return ioc.service_registry_->template use_service<Service>(ioc);+}++template <>+inline detail::io_context_impl& use_service<detail::io_context_impl>(+ io_context& ioc)+{+ return ioc.impl_;+}++#endif // !defined(GENERATING_DOCUMENTATION)++inline io_context::executor_type+io_context::get_executor() ASIO_NOEXCEPT+{+ return executor_type(*this);+}++#if defined(ASIO_HAS_CHRONO)++template <typename Rep, typename Period>+std::size_t io_context::run_for(+ const chrono::duration<Rep, Period>& rel_time)+{+ return this->run_until(chrono::steady_clock::now() + rel_time);+}++template <typename Clock, typename Duration>+std::size_t io_context::run_until(+ const chrono::time_point<Clock, Duration>& abs_time)+{+ std::size_t n = 0;+ while (this->run_one_until(abs_time))+ if (n != (std::numeric_limits<std::size_t>::max)())+ ++n;+ return n;+}++template <typename Rep, typename Period>+std::size_t io_context::run_one_for(+ const chrono::duration<Rep, Period>& rel_time)+{+ return this->run_one_until(chrono::steady_clock::now() + rel_time);+}++template <typename Clock, typename Duration>+std::size_t io_context::run_one_until(+ const chrono::time_point<Clock, Duration>& abs_time)+{+ typename Clock::time_point now = Clock::now();+ while (now < abs_time)+ {+ typename Clock::duration rel_time = abs_time - now;+ if (rel_time > chrono::seconds(1))+ rel_time = chrono::seconds(1);++ asio::error_code ec;+ std::size_t s = impl_.wait_one(+ static_cast<long>(chrono::duration_cast<+ chrono::microseconds>(rel_time).count()), ec);+ asio::detail::throw_error(ec);++ if (s || impl_.stopped())+ return s;++ now = Clock::now();+ }++ return 0;+}++#endif // defined(ASIO_HAS_CHRONO)++#if !defined(ASIO_NO_DEPRECATED)++inline void io_context::reset()+{+ restart();+}++struct io_context::initiate_dispatch+{+ template <typename LegacyCompletionHandler>+ void operator()(ASIO_MOVE_ARG(LegacyCompletionHandler) handler,+ io_context* self) const+ {+ // If you get an error on the following line it means that your handler does+ // not meet the documented type requirements for a LegacyCompletionHandler.+ ASIO_LEGACY_COMPLETION_HANDLER_CHECK(+ LegacyCompletionHandler, handler) type_check;++ detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);+ if (self->impl_.can_dispatch())+ {+ detail::fenced_block b(detail::fenced_block::full);+ asio_handler_invoke_helpers::invoke(+ handler2.value, handler2.value);+ }+ else+ {+ // Allocate and construct an operation to wrap the handler.+ typedef detail::completion_handler<+ typename decay<LegacyCompletionHandler>::type, executor_type> op;+ typename op::ptr p = { detail::addressof(handler2.value),+ op::ptr::allocate(handler2.value), 0 };+ p.p = new (p.v) op(handler2.value, self->get_executor());++ ASIO_HANDLER_CREATION((*self, *p.p,+ "io_context", self, 0, "dispatch"));++ self->impl_.do_dispatch(p.p);+ p.v = p.p = 0;+ }+ }+};++template <typename LegacyCompletionHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())+io_context::dispatch(ASIO_MOVE_ARG(LegacyCompletionHandler) handler)+{+ return async_initiate<LegacyCompletionHandler, void ()>(+ initiate_dispatch(), handler, this);+}++struct io_context::initiate_post+{+ template <typename LegacyCompletionHandler>+ void operator()(ASIO_MOVE_ARG(LegacyCompletionHandler) handler,+ io_context* self) const+ {+ // If you get an error on the following line it means that your handler does+ // not meet the documented type requirements for a LegacyCompletionHandler.+ ASIO_LEGACY_COMPLETION_HANDLER_CHECK(+ LegacyCompletionHandler, handler) type_check;++ detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);++ bool is_continuation =+ asio_handler_cont_helpers::is_continuation(handler2.value);++ // Allocate and construct an operation to wrap the handler.+ typedef detail::completion_handler<+ typename decay<LegacyCompletionHandler>::type, executor_type> op;+ typename op::ptr p = { detail::addressof(handler2.value),+ op::ptr::allocate(handler2.value), 0 };+ p.p = new (p.v) op(handler2.value, self->get_executor());++ ASIO_HANDLER_CREATION((*self, *p.p,+ "io_context", self, 0, "post"));++ self->impl_.post_immediate_completion(p.p, is_continuation);+ p.v = p.p = 0;+ }+};++template <typename LegacyCompletionHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())+io_context::post(ASIO_MOVE_ARG(LegacyCompletionHandler) handler)+{+ return async_initiate<LegacyCompletionHandler, void ()>(+ initiate_post(), handler, this);+}++template <typename Handler>+#if defined(GENERATING_DOCUMENTATION)+unspecified+#else+inline detail::wrapped_handler<io_context&, Handler>+#endif+io_context::wrap(Handler handler)+{+ return detail::wrapped_handler<io_context&, Handler>(*this, handler);+}++#endif // !defined(ASIO_NO_DEPRECATED)++template <typename Allocator, unsigned int Bits>+io_context::basic_executor_type<Allocator, Bits>&+io_context::basic_executor_type<Allocator, Bits>::operator=(+ const basic_executor_type& other) ASIO_NOEXCEPT+{+ if (this != &other)+ {+ io_context* old_io_context = io_context_;+ io_context_ = other.io_context_;+ allocator_ = other.allocator_;+ bits_ = other.bits_;+ if (Bits & outstanding_work_tracked)+ {+ if (io_context_)+ io_context_->impl_.work_started();+ if (old_io_context)+ old_io_context->impl_.work_finished();+ }+ }+ return *this;+}++#if defined(ASIO_HAS_MOVE)+template <typename Allocator, unsigned int Bits>+io_context::basic_executor_type<Allocator, Bits>&+io_context::basic_executor_type<Allocator, Bits>::operator=(+ basic_executor_type&& other) ASIO_NOEXCEPT+{+ if (this != &other)+ {+ io_context_ = other.io_context_;+ allocator_ = std::move(other.allocator_);+ bits_ = other.bits_;+ if (Bits & outstanding_work_tracked)+ other.io_context_ = 0;+ }+ return *this;+}+#endif // defined(ASIO_HAS_MOVE)++template <typename Allocator, unsigned int Bits>+inline bool io_context::basic_executor_type<Allocator,+ Bits>::running_in_this_thread() const ASIO_NOEXCEPT+{+ return io_context_->impl_.can_dispatch();+}++template <typename Allocator, unsigned int Bits>+template <typename Function>+void io_context::basic_executor_type<Allocator, Bits>::execute(+ ASIO_MOVE_ARG(Function) f) const+{+ typedef typename decay<Function>::type function_type;++ // Invoke immediately if the blocking.possibly property is enabled and we are+ // already inside the thread pool.+ if ((bits_ & blocking_never) == 0 && io_context_->impl_.can_dispatch())+ {+ // Make a local, non-const copy of the function.+ function_type tmp(ASIO_MOVE_CAST(Function)(f));++#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \+ && !defined(ASIO_NO_EXCEPTIONS)+ try+ {+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ // && !defined(ASIO_NO_EXCEPTIONS)+ detail::fenced_block b(detail::fenced_block::full);+ asio_handler_invoke_helpers::invoke(tmp, tmp);+ return;+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \+ && !defined(ASIO_NO_EXCEPTIONS)+ }+ catch (...)+ {+ io_context_->impl_.capture_current_exception();+ return;+ }+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ // && !defined(ASIO_NO_EXCEPTIONS)+ }++ // Allocate and construct an operation to wrap the function.+ typedef detail::executor_op<function_type, Allocator, detail::operation> op;+ typename op::ptr p = { detail::addressof(allocator_),+ op::ptr::allocate(allocator_), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), allocator_);++ ASIO_HANDLER_CREATION((*io_context_, *p.p,+ "io_context", io_context_, 0, "execute"));++ io_context_->impl_.post_immediate_completion(p.p,+ (bits_ & relationship_continuation) != 0);+ p.v = p.p = 0;+}++#if !defined(ASIO_NO_TS_EXECUTORS)+template <typename Allocator, unsigned int Bits>+inline io_context& io_context::basic_executor_type<+ Allocator, Bits>::context() const ASIO_NOEXCEPT+{+ return *io_context_;+}++template <typename Allocator, unsigned int Bits>+inline void io_context::basic_executor_type<Allocator,+ Bits>::on_work_started() const ASIO_NOEXCEPT+{+ io_context_->impl_.work_started();+}++template <typename Allocator, unsigned int Bits>+inline void io_context::basic_executor_type<Allocator,+ Bits>::on_work_finished() const ASIO_NOEXCEPT+{+ io_context_->impl_.work_finished();+}++template <typename Allocator, unsigned int Bits>+template <typename Function, typename OtherAllocator>+void io_context::basic_executor_type<Allocator, Bits>::dispatch(+ ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const+{+ typedef typename decay<Function>::type function_type;++ // Invoke immediately if we are already inside the thread pool.+ if (io_context_->impl_.can_dispatch())+ {+ // Make a local, non-const copy of the function.+ function_type tmp(ASIO_MOVE_CAST(Function)(f));++ detail::fenced_block b(detail::fenced_block::full);+ asio_handler_invoke_helpers::invoke(tmp, tmp);+ return;+ }++ // Allocate and construct an operation to wrap the function.+ typedef detail::executor_op<function_type,+ OtherAllocator, detail::operation> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);++ ASIO_HANDLER_CREATION((*io_context_, *p.p,+ "io_context", io_context_, 0, "dispatch"));++ io_context_->impl_.post_immediate_completion(p.p, false);+ p.v = p.p = 0;+}++template <typename Allocator, unsigned int Bits>+template <typename Function, typename OtherAllocator>+void io_context::basic_executor_type<Allocator, Bits>::post(+ ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const+{+ typedef typename decay<Function>::type function_type;++ // Allocate and construct an operation to wrap the function.+ typedef detail::executor_op<function_type,+ OtherAllocator, detail::operation> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);++ ASIO_HANDLER_CREATION((*io_context_, *p.p,+ "io_context", io_context_, 0, "post"));++ io_context_->impl_.post_immediate_completion(p.p, false);+ p.v = p.p = 0;+}++template <typename Allocator, unsigned int Bits>+template <typename Function, typename OtherAllocator>+void io_context::basic_executor_type<Allocator, Bits>::defer(+ ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const+{+ typedef typename decay<Function>::type function_type;++ // Allocate and construct an operation to wrap the function.+ typedef detail::executor_op<function_type,+ OtherAllocator, detail::operation> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);++ ASIO_HANDLER_CREATION((*io_context_, *p.p,+ "io_context", io_context_, 0, "defer"));++ io_context_->impl_.post_immediate_completion(p.p, true);+ p.v = p.p = 0;+}+#endif // !defined(ASIO_NO_TS_EXECUTORS)++#if !defined(ASIO_NO_DEPRECATED)+inline io_context::work::work(asio::io_context& io_context)+ : io_context_impl_(io_context.impl_)+{+ io_context_impl_.work_started();+}++inline io_context::work::work(const work& other)+ : io_context_impl_(other.io_context_impl_)+{+ io_context_impl_.work_started();+}++inline io_context::work::~work()+{+ io_context_impl_.work_finished();+}++inline asio::io_context& io_context::work::get_io_context()+{+ return static_cast<asio::io_context&>(io_context_impl_.context());+}+#endif // !defined(ASIO_NO_DEPRECATED)++inline asio::io_context& io_context::service::get_io_context()+{+ return static_cast<asio::io_context&>(context());+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_IO_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/io_context.ipp view
@@ -0,0 +1,175 @@+//+// impl/io_context.ipp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_IO_CONTEXT_IPP+#define ASIO_IMPL_IO_CONTEXT_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/io_context.hpp"+#include "asio/detail/concurrency_hint.hpp"+#include "asio/detail/limits.hpp"+#include "asio/detail/scoped_ptr.hpp"+#include "asio/detail/service_registry.hpp"+#include "asio/detail/throw_error.hpp"++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#else+# include "asio/detail/scheduler.hpp"+#endif++#include "asio/detail/push_options.hpp"++namespace asio {++io_context::io_context()+ : impl_(add_impl(new impl_type(*this,+ ASIO_CONCURRENCY_HINT_DEFAULT, false)))+{+}++io_context::io_context(int concurrency_hint)+ : impl_(add_impl(new impl_type(*this, concurrency_hint == 1+ ? ASIO_CONCURRENCY_HINT_1 : concurrency_hint, false)))+{+}++io_context::impl_type& io_context::add_impl(io_context::impl_type* impl)+{+ asio::detail::scoped_ptr<impl_type> scoped_impl(impl);+ asio::add_service<impl_type>(*this, scoped_impl.get());+ return *scoped_impl.release();+}++io_context::~io_context()+{+}++io_context::count_type io_context::run()+{+ asio::error_code ec;+ count_type s = impl_.run(ec);+ asio::detail::throw_error(ec);+ return s;+}++#if !defined(ASIO_NO_DEPRECATED)+io_context::count_type io_context::run(asio::error_code& ec)+{+ return impl_.run(ec);+}+#endif // !defined(ASIO_NO_DEPRECATED)++io_context::count_type io_context::run_one()+{+ asio::error_code ec;+ count_type s = impl_.run_one(ec);+ asio::detail::throw_error(ec);+ return s;+}++#if !defined(ASIO_NO_DEPRECATED)+io_context::count_type io_context::run_one(asio::error_code& ec)+{+ return impl_.run_one(ec);+}+#endif // !defined(ASIO_NO_DEPRECATED)++io_context::count_type io_context::poll()+{+ asio::error_code ec;+ count_type s = impl_.poll(ec);+ asio::detail::throw_error(ec);+ return s;+}++#if !defined(ASIO_NO_DEPRECATED)+io_context::count_type io_context::poll(asio::error_code& ec)+{+ return impl_.poll(ec);+}+#endif // !defined(ASIO_NO_DEPRECATED)++io_context::count_type io_context::poll_one()+{+ asio::error_code ec;+ count_type s = impl_.poll_one(ec);+ asio::detail::throw_error(ec);+ return s;+}++#if !defined(ASIO_NO_DEPRECATED)+io_context::count_type io_context::poll_one(asio::error_code& ec)+{+ return impl_.poll_one(ec);+}+#endif // !defined(ASIO_NO_DEPRECATED)++void io_context::stop()+{+ impl_.stop();+}++bool io_context::stopped() const+{+ return impl_.stopped();+}++void io_context::restart()+{+ impl_.restart();+}++io_context::service::service(asio::io_context& owner)+ : execution_context::service(owner)+{+}++io_context::service::~service()+{+}++void io_context::service::shutdown()+{+#if !defined(ASIO_NO_DEPRECATED)+ shutdown_service();+#endif // !defined(ASIO_NO_DEPRECATED)+}++#if !defined(ASIO_NO_DEPRECATED)+void io_context::service::shutdown_service()+{+}+#endif // !defined(ASIO_NO_DEPRECATED)++void io_context::service::notify_fork(io_context::fork_event ev)+{+#if !defined(ASIO_NO_DEPRECATED)+ fork_service(ev);+#else // !defined(ASIO_NO_DEPRECATED)+ (void)ev;+#endif // !defined(ASIO_NO_DEPRECATED)+}++#if !defined(ASIO_NO_DEPRECATED)+void io_context::service::fork_service(io_context::fork_event)+{+}+#endif // !defined(ASIO_NO_DEPRECATED)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_IO_CONTEXT_IPP
+ link/modules/asio-standalone/asio/include/asio/impl/multiple_exceptions.ipp view
@@ -0,0 +1,49 @@+//+// impl/multiple_exceptions.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_MULTIPLE_EXCEPTIONS_IPP+#define ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/multiple_exceptions.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(ASIO_HAS_STD_EXCEPTION_PTR)++multiple_exceptions::multiple_exceptions(+ std::exception_ptr first) ASIO_NOEXCEPT+ : first_(ASIO_MOVE_CAST(std::exception_ptr)(first))+{+}++const char* multiple_exceptions::what() const ASIO_NOEXCEPT_OR_NOTHROW+{+ return "multiple exceptions";+}++std::exception_ptr multiple_exceptions::first_exception() const+{+ return first_;+}++#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP
+ link/modules/asio-standalone/asio/include/asio/impl/post.hpp view
@@ -0,0 +1,248 @@+//+// impl/post.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_POST_HPP+#define ASIO_IMPL_POST_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_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/detail/work_dispatcher.hpp"+#include "asio/execution/allocator.hpp"+#include "asio/execution/blocking.hpp"+#include "asio/execution/relationship.hpp"+#include "asio/prefer.hpp"+#include "asio/require.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++class initiate_post+{+public:+ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ execution::is_executor<+ typename associated_executor<+ typename decay<CompletionHandler>::type+ >::type+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_executor<handler_t>::type ex(+ (get_associated_executor)(handler));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ execution::execute(+ asio::prefer(+ asio::require(ex, execution::blocking.never),+ execution::relationship.fork,+ execution::allocator(alloc)),+ ASIO_MOVE_CAST(CompletionHandler)(handler));+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ !execution::is_executor<+ typename associated_executor<+ typename decay<CompletionHandler>::type+ >::type+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_executor<handler_t>::type ex(+ (get_associated_executor)(handler));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ ex.post(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);+ }+};++template <typename Executor>+class initiate_post_with_executor+{+public:+ typedef Executor executor_type;++ explicit initiate_post_with_executor(const Executor& ex)+ : ex_(ex)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return ex_;+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ !detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ execution::execute(+ asio::prefer(+ asio::require(ex_, execution::blocking.never),+ execution::relationship.fork,+ execution::allocator(alloc)),+ ASIO_MOVE_CAST(CompletionHandler)(handler));+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typedef typename associated_executor<+ handler_t, Executor>::type handler_ex_t;+ handler_ex_t handler_ex((get_associated_executor)(handler, ex_));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ execution::execute(+ asio::prefer(+ asio::require(ex_, execution::blocking.never),+ execution::relationship.fork,+ execution::allocator(alloc)),+ detail::work_dispatcher<handler_t, handler_ex_t>(+ ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex));+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ !execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ !detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ ex_.post(ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);+ }++ template <typename CompletionHandler>+ void operator()(ASIO_MOVE_ARG(CompletionHandler) handler,+ typename enable_if<+ !execution::is_executor<+ typename conditional<true, executor_type, CompletionHandler>::type+ >::value+ &&+ detail::is_work_dispatcher_required<+ typename decay<CompletionHandler>::type,+ Executor+ >::value+ >::type* = 0) const+ {+ typedef typename decay<CompletionHandler>::type handler_t;++ typedef typename associated_executor<+ handler_t, Executor>::type handler_ex_t;+ handler_ex_t handler_ex((get_associated_executor)(handler, ex_));++ typename associated_allocator<handler_t>::type alloc(+ (get_associated_allocator)(handler));++ ex_.post(detail::work_dispatcher<handler_t, handler_ex_t>(+ ASIO_MOVE_CAST(CompletionHandler)(handler),+ handler_ex), alloc);+ }++private:+ Executor ex_;+};++} // namespace detail++template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(+ ASIO_MOVE_ARG(CompletionToken) token)+{+ return async_initiate<CompletionToken, void()>(+ detail::initiate_post(), token);+}++template <typename Executor,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(+ const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token,+ typename enable_if<+ execution::is_executor<Executor>::value || is_executor<Executor>::value+ >::type*)+{+ return async_initiate<CompletionToken, void()>(+ detail::initiate_post_with_executor<Executor>(ex), token);+}++template <typename ExecutionContext,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+inline ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(+ ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token,+ typename enable_if<is_convertible<+ ExecutionContext&, execution_context&>::value>::type*)+{+ return async_initiate<CompletionToken, void()>(+ detail::initiate_post_with_executor<+ typename ExecutionContext::executor_type>(+ ctx.get_executor()), token);+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_POST_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/read.hpp view
@@ -0,0 +1,1202 @@+//+// impl/read.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_READ_HPP+#define ASIO_IMPL_READ_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include <algorithm>+#include "asio/associated_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/buffer.hpp"+#include "asio/completion_condition.hpp"+#include "asio/detail/array_fwd.hpp"+#include "asio/detail/base_from_completion_cond.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/consuming_buffers.hpp"+#include "asio/detail/dependent_type.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_cont_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_tracking.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 {++namespace detail+{+ template <typename SyncReadStream, typename MutableBufferSequence,+ typename MutableBufferIterator, typename CompletionCondition>+ std::size_t read_buffer_sequence(SyncReadStream& s,+ const MutableBufferSequence& buffers, const MutableBufferIterator&,+ CompletionCondition completion_condition, asio::error_code& ec)+ {+ ec = asio::error_code();+ asio::detail::consuming_buffers<mutable_buffer,+ MutableBufferSequence, MutableBufferIterator> tmp(buffers);+ while (!tmp.empty())+ {+ if (std::size_t max_size = detail::adapt_completion_condition_result(+ completion_condition(ec, tmp.total_consumed())))+ tmp.consume(s.read_some(tmp.prepare(max_size), ec));+ else+ break;+ }+ return tmp.total_consumed();;+ }+} // namespace detail++template <typename SyncReadStream, typename MutableBufferSequence,+ typename CompletionCondition>+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type*)+{+ return detail::read_buffer_sequence(s, buffers,+ asio::buffer_sequence_begin(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+}++template <typename SyncReadStream, typename MutableBufferSequence>+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec);+ asio::detail::throw_error(ec, "read");+ return bytes_transferred;+}++template <typename SyncReadStream, typename MutableBufferSequence>+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,+ asio::error_code& ec,+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type*)+{+ return read(s, buffers, transfer_all(), ec);+}++template <typename SyncReadStream, typename MutableBufferSequence,+ typename CompletionCondition>+inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read(s, buffers,+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ asio::detail::throw_error(ec, "read");+ return bytes_transferred;+}++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++template <typename SyncReadStream, typename DynamicBuffer_v1,+ typename CompletionCondition>+std::size_t read(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ typename decay<DynamicBuffer_v1>::type b(+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));++ ec = asio::error_code();+ std::size_t total_transferred = 0;+ std::size_t max_size = detail::adapt_completion_condition_result(+ completion_condition(ec, total_transferred));+ std::size_t bytes_available = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(max_size, b.max_size() - b.size()));+ while (bytes_available > 0)+ {+ std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec);+ b.commit(bytes_transferred);+ total_transferred += bytes_transferred;+ max_size = detail::adapt_completion_condition_result(+ completion_condition(ec, total_transferred));+ bytes_available = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(max_size, b.max_size() - b.size()));+ }+ return total_transferred;+}++template <typename SyncReadStream, typename DynamicBuffer_v1>+inline std::size_t read(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read(s,+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), ec);+ asio::detail::throw_error(ec, "read");+ return bytes_transferred;+}++template <typename SyncReadStream, typename DynamicBuffer_v1>+inline std::size_t read(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ return read(s, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ transfer_all(), ec);+}++template <typename SyncReadStream, typename DynamicBuffer_v1,+ typename CompletionCondition>+inline std::size_t read(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read(s,+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ asio::detail::throw_error(ec, "read");+ return bytes_transferred;+}++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++template <typename SyncReadStream, typename Allocator,+ typename CompletionCondition>+inline std::size_t read(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition, asio::error_code& ec)+{+ return read(s, basic_streambuf_ref<Allocator>(b),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+}++template <typename SyncReadStream, typename Allocator>+inline std::size_t read(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b)+{+ return read(s, basic_streambuf_ref<Allocator>(b));+}++template <typename SyncReadStream, typename Allocator>+inline std::size_t read(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ asio::error_code& ec)+{+ return read(s, basic_streambuf_ref<Allocator>(b), ec);+}++template <typename SyncReadStream, typename Allocator,+ typename CompletionCondition>+inline std::size_t read(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition)+{+ return read(s, basic_streambuf_ref<Allocator>(b),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++template <typename SyncReadStream, typename DynamicBuffer_v2,+ typename CompletionCondition>+std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ DynamicBuffer_v2& b = buffers;++ ec = asio::error_code();+ std::size_t total_transferred = 0;+ std::size_t max_size = detail::adapt_completion_condition_result(+ completion_condition(ec, total_transferred));+ std::size_t bytes_available = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(max_size, b.max_size() - b.size()));+ while (bytes_available > 0)+ {+ std::size_t pos = b.size();+ b.grow(bytes_available);+ std::size_t bytes_transferred = s.read_some(+ b.data(pos, bytes_available), ec);+ b.shrink(bytes_available - bytes_transferred);+ total_transferred += bytes_transferred;+ max_size = detail::adapt_completion_condition_result(+ completion_condition(ec, total_transferred));+ bytes_available = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(max_size, b.max_size() - b.size()));+ }+ return total_transferred;+}++template <typename SyncReadStream, typename DynamicBuffer_v2>+inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read(s,+ ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), transfer_all(), ec);+ asio::detail::throw_error(ec, "read");+ return bytes_transferred;+}++template <typename SyncReadStream, typename DynamicBuffer_v2>+inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,+ asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ return read(s, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ transfer_all(), ec);+}++template <typename SyncReadStream, typename DynamicBuffer_v2,+ typename CompletionCondition>+inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read(s,+ ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ asio::detail::throw_error(ec, "read");+ return bytes_transferred;+}++namespace detail+{+ template <typename AsyncReadStream, typename MutableBufferSequence,+ typename MutableBufferIterator, typename CompletionCondition,+ typename ReadHandler>+ class read_op+ : detail::base_from_completion_cond<CompletionCondition>+ {+ public:+ read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers,+ CompletionCondition& completion_condition, ReadHandler& handler)+ : detail::base_from_completion_cond<+ CompletionCondition>(completion_condition),+ stream_(stream),+ buffers_(buffers),+ start_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_op(const read_op& other)+ : detail::base_from_completion_cond<CompletionCondition>(other),+ stream_(other.stream_),+ buffers_(other.buffers_),+ start_(other.start_),+ handler_(other.handler_)+ {+ }++ read_op(read_op&& other)+ : detail::base_from_completion_cond<CompletionCondition>(+ ASIO_MOVE_CAST(detail::base_from_completion_cond<+ CompletionCondition>)(other)),+ stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(buffers_type)(other.buffers_)),+ start_(other.start_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ std::size_t max_size;+ switch (start_ = start)+ {+ case 1:+ max_size = this->check_for_completion(ec, buffers_.total_consumed());+ do+ {+ {+ ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read"));+ stream_.async_read_some(buffers_.prepare(max_size),+ ASIO_MOVE_CAST(read_op)(*this));+ }+ return; default:+ buffers_.consume(bytes_transferred);+ if ((!ec && bytes_transferred == 0) || buffers_.empty())+ break;+ max_size = this->check_for_completion(ec, buffers_.total_consumed());+ } while (max_size > 0);++ handler_(ec, buffers_.total_consumed());+ }+ }++ //private:+ typedef asio::detail::consuming_buffers<mutable_buffer,+ MutableBufferSequence, MutableBufferIterator> buffers_type;++ AsyncReadStream& stream_;+ buffers_type buffers_;+ int start_;+ ReadHandler handler_;+ };++ template <typename AsyncReadStream, typename MutableBufferSequence,+ typename MutableBufferIterator, typename CompletionCondition,+ typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator,+ CompletionCondition, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename MutableBufferSequence,+ typename MutableBufferIterator, typename CompletionCondition,+ typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename MutableBufferSequence,+ typename MutableBufferIterator, typename CompletionCondition,+ typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator,+ CompletionCondition, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncReadStream,+ typename MutableBufferSequence, typename MutableBufferIterator,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncReadStream,+ typename MutableBufferSequence, typename MutableBufferIterator,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename MutableBufferSequence,+ typename MutableBufferIterator, typename CompletionCondition,+ typename ReadHandler>+ inline void start_read_buffer_sequence_op(AsyncReadStream& stream,+ const MutableBufferSequence& buffers, const MutableBufferIterator&,+ CompletionCondition& completion_condition, ReadHandler& handler)+ {+ detail::read_op<AsyncReadStream, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>(+ stream, buffers, completion_condition, handler)(+ asio::error_code(), 0, 1);+ }++ template <typename AsyncReadStream>+ class initiate_async_read_buffer_sequence+ {+ public:+ typedef typename AsyncReadStream::executor_type executor_type;++ explicit initiate_async_read_buffer_sequence(AsyncReadStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence,+ typename CompletionCondition>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(CompletionCondition) completion_cond) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);+ start_read_buffer_sequence_op(stream_, buffers,+ asio::buffer_sequence_begin(buffers),+ completion_cond2.value, handler2.value);+ }++ private:+ AsyncReadStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename MutableBufferSequence,+ typename MutableBufferIterator, typename CompletionCondition,+ typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_op<AsyncReadStream, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_op<AsyncReadStream, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncReadStream, typename MutableBufferSequence,+ typename MutableBufferIterator, typename CompletionCondition,+ typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_op<AsyncReadStream, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_op<AsyncReadStream, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream,+ typename MutableBufferSequence, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_buffer_sequence<AsyncReadStream>(s), handler,+ buffers, ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++template <typename AsyncReadStream, typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_buffer_sequence<AsyncReadStream>(s),+ handler, buffers, transfer_all());+}++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++namespace detail+{+ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename ReadHandler>+ class read_dynbuf_v1_op+ : detail::base_from_completion_cond<CompletionCondition>+ {+ public:+ template <typename BufferSequence>+ read_dynbuf_v1_op(AsyncReadStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ CompletionCondition& completion_condition, ReadHandler& handler)+ : detail::base_from_completion_cond<+ CompletionCondition>(completion_condition),+ stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ start_(0),+ total_transferred_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_dynbuf_v1_op(const read_dynbuf_v1_op& other)+ : detail::base_from_completion_cond<CompletionCondition>(other),+ stream_(other.stream_),+ buffers_(other.buffers_),+ start_(other.start_),+ total_transferred_(other.total_transferred_),+ handler_(other.handler_)+ {+ }++ read_dynbuf_v1_op(read_dynbuf_v1_op&& other)+ : detail::base_from_completion_cond<CompletionCondition>(+ ASIO_MOVE_CAST(detail::base_from_completion_cond<+ CompletionCondition>)(other)),+ stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),+ start_(other.start_),+ total_transferred_(other.total_transferred_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ std::size_t max_size, bytes_available;+ switch (start_ = start)+ {+ case 1:+ max_size = this->check_for_completion(ec, total_transferred_);+ bytes_available = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(max_size,+ buffers_.max_size() - buffers_.size()));+ for (;;)+ {+ {+ ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read"));+ stream_.async_read_some(buffers_.prepare(bytes_available),+ ASIO_MOVE_CAST(read_dynbuf_v1_op)(*this));+ }+ return; default:+ total_transferred_ += bytes_transferred;+ buffers_.commit(bytes_transferred);+ max_size = this->check_for_completion(ec, total_transferred_);+ bytes_available = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(max_size,+ buffers_.max_size() - buffers_.size()));+ if ((!ec && bytes_transferred == 0) || bytes_available == 0)+ break;+ }++ handler_(ec, static_cast<const std::size_t&>(total_transferred_));+ }+ }++ //private:+ AsyncReadStream& stream_;+ DynamicBuffer_v1 buffers_;+ int start_;+ std::size_t total_transferred_;+ ReadHandler handler_;+ };++ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,+ CompletionCondition, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,+ CompletionCondition, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v1, typename CompletionCondition,+ typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v1, typename CompletionCondition,+ typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream>+ class initiate_async_read_dynbuf_v1+ {+ public:+ typedef typename AsyncReadStream::executor_type executor_type;++ explicit initiate_async_read_dynbuf_v1(AsyncReadStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename ReadHandler, typename DynamicBuffer_v1,+ typename CompletionCondition>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_MOVE_ARG(CompletionCondition) completion_cond) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);+ read_dynbuf_v1_op<AsyncReadStream, typename decay<DynamicBuffer_v1>::type,+ CompletionCondition, typename decay<ReadHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ completion_cond2.value, handler2.value)(+ asio::error_code(), 0, 1);+ }++ private:+ AsyncReadStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_dynbuf_v1_op<AsyncReadStream,+ DynamicBuffer_v1, CompletionCondition, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_dynbuf_v1_op<AsyncReadStream,+ DynamicBuffer_v1, CompletionCondition, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_dynbuf_v1_op<AsyncReadStream,+ DynamicBuffer_v1, CompletionCondition, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_dynbuf_v1_op<AsyncReadStream,+ DynamicBuffer_v1, CompletionCondition, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ return async_read(s,+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ transfer_all(), ASIO_MOVE_CAST(ReadHandler)(handler));+}++template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_dynbuf_v1<AsyncReadStream>(s),+ handler, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++template <typename AsyncReadStream, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,+ ASIO_MOVE_ARG(ReadHandler) handler)+{+ return async_read(s, basic_streambuf_ref<Allocator>(b),+ ASIO_MOVE_CAST(ReadHandler)(handler));+}++template <typename AsyncReadStream,+ typename Allocator, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler)+{+ return async_read(s, basic_streambuf_ref<Allocator>(b),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition),+ ASIO_MOVE_CAST(ReadHandler)(handler));+}++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++namespace detail+{+ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename ReadHandler>+ class read_dynbuf_v2_op+ : detail::base_from_completion_cond<CompletionCondition>+ {+ public:+ template <typename BufferSequence>+ read_dynbuf_v2_op(AsyncReadStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ CompletionCondition& completion_condition, ReadHandler& handler)+ : detail::base_from_completion_cond<+ CompletionCondition>(completion_condition),+ stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ start_(0),+ total_transferred_(0),+ bytes_available_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_dynbuf_v2_op(const read_dynbuf_v2_op& other)+ : detail::base_from_completion_cond<CompletionCondition>(other),+ stream_(other.stream_),+ buffers_(other.buffers_),+ start_(other.start_),+ total_transferred_(other.total_transferred_),+ bytes_available_(other.bytes_available_),+ handler_(other.handler_)+ {+ }++ read_dynbuf_v2_op(read_dynbuf_v2_op&& other)+ : detail::base_from_completion_cond<CompletionCondition>(+ ASIO_MOVE_CAST(detail::base_from_completion_cond<+ CompletionCondition>)(other)),+ stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),+ start_(other.start_),+ total_transferred_(other.total_transferred_),+ bytes_available_(other.bytes_available_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ std::size_t max_size, pos;+ switch (start_ = start)+ {+ case 1:+ max_size = this->check_for_completion(ec, total_transferred_);+ bytes_available_ = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(max_size,+ buffers_.max_size() - buffers_.size()));+ for (;;)+ {+ pos = buffers_.size();+ buffers_.grow(bytes_available_);+ {+ ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read"));+ stream_.async_read_some(buffers_.data(pos, bytes_available_),+ ASIO_MOVE_CAST(read_dynbuf_v2_op)(*this));+ }+ return; default:+ total_transferred_ += bytes_transferred;+ buffers_.shrink(bytes_available_ - bytes_transferred);+ max_size = this->check_for_completion(ec, total_transferred_);+ bytes_available_ = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(max_size,+ buffers_.max_size() - buffers_.size()));+ if ((!ec && bytes_transferred == 0) || bytes_available_ == 0)+ break;+ }++ handler_(ec, static_cast<const std::size_t&>(total_transferred_));+ }+ }++ //private:+ AsyncReadStream& stream_;+ DynamicBuffer_v2 buffers_;+ int start_;+ std::size_t total_transferred_;+ std::size_t bytes_available_;+ ReadHandler handler_;+ };++ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,+ CompletionCondition, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,+ CompletionCondition, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v2, typename CompletionCondition,+ typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v2, typename CompletionCondition,+ typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream>+ class initiate_async_read_dynbuf_v2+ {+ public:+ typedef typename AsyncReadStream::executor_type executor_type;++ explicit initiate_async_read_dynbuf_v2(AsyncReadStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename ReadHandler, typename DynamicBuffer_v2,+ typename CompletionCondition>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,+ ASIO_MOVE_ARG(CompletionCondition) completion_cond) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);+ read_dynbuf_v2_op<AsyncReadStream, typename decay<DynamicBuffer_v2>::type,+ CompletionCondition, typename decay<ReadHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ completion_cond2.value, handler2.value)(+ asio::error_code(), 0, 1);+ }++ private:+ AsyncReadStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_dynbuf_v2_op<AsyncReadStream,+ DynamicBuffer_v2, CompletionCondition, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_dynbuf_v2_op<AsyncReadStream,+ DynamicBuffer_v2, CompletionCondition, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_dynbuf_v2_op<AsyncReadStream,+ DynamicBuffer_v2, CompletionCondition, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_dynbuf_v2_op<AsyncReadStream,+ DynamicBuffer_v2, CompletionCondition, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers,+ ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ return async_read(s,+ ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ transfer_all(), ASIO_MOVE_CAST(ReadHandler)(handler));+}++template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_dynbuf_v2<AsyncReadStream>(s),+ handler, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_READ_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/read_at.hpp view
@@ -0,0 +1,744 @@+//+// impl/read_at.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_READ_AT_HPP+#define ASIO_IMPL_READ_AT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include <algorithm>+#include "asio/associated_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/buffer.hpp"+#include "asio/completion_condition.hpp"+#include "asio/detail/array_fwd.hpp"+#include "asio/detail/base_from_completion_cond.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/consuming_buffers.hpp"+#include "asio/detail/dependent_type.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_cont_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_tracking.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 {++namespace detail+{+ template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,+ typename MutableBufferIterator, typename CompletionCondition>+ std::size_t read_at_buffer_sequence(SyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers,+ const MutableBufferIterator&, CompletionCondition completion_condition,+ asio::error_code& ec)+ {+ ec = asio::error_code();+ asio::detail::consuming_buffers<mutable_buffer,+ MutableBufferSequence, MutableBufferIterator> tmp(buffers);+ while (!tmp.empty())+ {+ if (std::size_t max_size = detail::adapt_completion_condition_result(+ completion_condition(ec, tmp.total_consumed())))+ {+ tmp.consume(d.read_some_at(offset + tmp.total_consumed(),+ tmp.prepare(max_size), ec));+ }+ else+ break;+ }+ return tmp.total_consumed();;+ }+} // namespace detail++template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,+ typename CompletionCondition>+std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition, asio::error_code& ec)+{+ return detail::read_at_buffer_sequence(d, offset, buffers,+ asio::buffer_sequence_begin(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+}++template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>+inline std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_at(+ d, offset, buffers, transfer_all(), ec);+ asio::detail::throw_error(ec, "read_at");+ return bytes_transferred;+}++template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>+inline std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers,+ asio::error_code& ec)+{+ return read_at(d, offset, buffers, transfer_all(), ec);+}++template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,+ typename CompletionCondition>+inline std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_at(d, offset, buffers,+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ asio::detail::throw_error(ec, "read_at");+ return bytes_transferred;+}++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++template <typename SyncRandomAccessReadDevice, typename Allocator,+ typename CompletionCondition>+std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition, asio::error_code& ec)+{+ ec = asio::error_code();+ std::size_t total_transferred = 0;+ std::size_t max_size = detail::adapt_completion_condition_result(+ completion_condition(ec, total_transferred));+ std::size_t bytes_available = read_size_helper(b, max_size);+ while (bytes_available > 0)+ {+ std::size_t bytes_transferred = d.read_some_at(+ offset + total_transferred, b.prepare(bytes_available), ec);+ b.commit(bytes_transferred);+ total_transferred += bytes_transferred;+ max_size = detail::adapt_completion_condition_result(+ completion_condition(ec, total_transferred));+ bytes_available = read_size_helper(b, max_size);+ }+ return total_transferred;+}++template <typename SyncRandomAccessReadDevice, typename Allocator>+inline std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_at(+ d, offset, b, transfer_all(), ec);+ asio::detail::throw_error(ec, "read_at");+ return bytes_transferred;+}++template <typename SyncRandomAccessReadDevice, typename Allocator>+inline std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b,+ asio::error_code& ec)+{+ return read_at(d, offset, b, transfer_all(), ec);+}++template <typename SyncRandomAccessReadDevice, typename Allocator,+ typename CompletionCondition>+inline std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_at(d, offset, b,+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ asio::detail::throw_error(ec, "read_at");+ return bytes_transferred;+}++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)++namespace detail+{+ template <typename AsyncRandomAccessReadDevice,+ typename MutableBufferSequence, typename MutableBufferIterator,+ typename CompletionCondition, typename ReadHandler>+ class read_at_op+ : detail::base_from_completion_cond<CompletionCondition>+ {+ public:+ read_at_op(AsyncRandomAccessReadDevice& device,+ uint64_t offset, const MutableBufferSequence& buffers,+ CompletionCondition& completion_condition, ReadHandler& handler)+ : detail::base_from_completion_cond<+ CompletionCondition>(completion_condition),+ device_(device),+ offset_(offset),+ buffers_(buffers),+ start_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_at_op(const read_at_op& other)+ : detail::base_from_completion_cond<CompletionCondition>(other),+ device_(other.device_),+ offset_(other.offset_),+ buffers_(other.buffers_),+ start_(other.start_),+ handler_(other.handler_)+ {+ }++ read_at_op(read_at_op&& other)+ : detail::base_from_completion_cond<CompletionCondition>(+ ASIO_MOVE_CAST(detail::base_from_completion_cond<+ CompletionCondition>)(other)),+ device_(other.device_),+ offset_(other.offset_),+ buffers_(ASIO_MOVE_CAST(buffers_type)(other.buffers_)),+ start_(other.start_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ std::size_t max_size;+ switch (start_ = start)+ {+ case 1:+ max_size = this->check_for_completion(ec, buffers_.total_consumed());+ do+ {+ {+ ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at"));+ device_.async_read_some_at(+ offset_ + buffers_.total_consumed(), buffers_.prepare(max_size),+ ASIO_MOVE_CAST(read_at_op)(*this));+ }+ return; default:+ buffers_.consume(bytes_transferred);+ if ((!ec && bytes_transferred == 0) || buffers_.empty())+ break;+ max_size = this->check_for_completion(ec, buffers_.total_consumed());+ } while (max_size > 0);++ handler_(ec, buffers_.total_consumed());+ }+ }++ //private:+ typedef asio::detail::consuming_buffers<mutable_buffer,+ MutableBufferSequence, MutableBufferIterator> buffers_type;++ AsyncRandomAccessReadDevice& device_;+ uint64_t offset_;+ buffers_type buffers_;+ int start_;+ ReadHandler handler_;+ };++ template <typename AsyncRandomAccessReadDevice,+ typename MutableBufferSequence, typename MutableBufferIterator,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncRandomAccessReadDevice,+ typename MutableBufferSequence, typename MutableBufferIterator,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncRandomAccessReadDevice,+ typename MutableBufferSequence, typename MutableBufferIterator,+ typename CompletionCondition, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncRandomAccessReadDevice,+ typename MutableBufferSequence, typename MutableBufferIterator,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncRandomAccessReadDevice,+ typename MutableBufferSequence, typename MutableBufferIterator,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncRandomAccessReadDevice,+ typename MutableBufferSequence, typename MutableBufferIterator,+ typename CompletionCondition, typename ReadHandler>+ inline void start_read_at_buffer_sequence_op(AsyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers,+ const MutableBufferIterator&, CompletionCondition& completion_condition,+ ReadHandler& handler)+ {+ detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>(+ d, offset, buffers, completion_condition, handler)(+ asio::error_code(), 0, 1);+ }++ template <typename AsyncRandomAccessReadDevice>+ class initiate_async_read_at_buffer_sequence+ {+ public:+ typedef typename AsyncRandomAccessReadDevice::executor_type executor_type;++ explicit initiate_async_read_at_buffer_sequence(+ AsyncRandomAccessReadDevice& device)+ : device_(device)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return device_.get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence,+ typename CompletionCondition>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ uint64_t offset, const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(CompletionCondition) completion_cond) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);+ start_read_at_buffer_sequence_op(device_, offset, buffers,+ asio::buffer_sequence_begin(buffers),+ completion_cond2.value, handler2.value);+ }++ private:+ AsyncRandomAccessReadDevice& device_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncRandomAccessReadDevice,+ typename MutableBufferSequence, typename MutableBufferIterator,+ typename CompletionCondition, typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_at_op<AsyncRandomAccessReadDevice,+ MutableBufferSequence, MutableBufferIterator,+ CompletionCondition, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncRandomAccessReadDevice,+ typename MutableBufferSequence, typename MutableBufferIterator,+ typename CompletionCondition, typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,+ MutableBufferIterator, CompletionCondition, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_at_op<AsyncRandomAccessReadDevice,+ MutableBufferSequence, MutableBufferIterator,+ CompletionCondition, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncRandomAccessReadDevice,+ typename MutableBufferSequence, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_at(AsyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_at_buffer_sequence<+ AsyncRandomAccessReadDevice>(d),+ handler, offset, buffers,+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_at(AsyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_at_buffer_sequence<+ AsyncRandomAccessReadDevice>(d),+ handler, offset, buffers, transfer_all());+}++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++namespace detail+{+ template <typename AsyncRandomAccessReadDevice, typename Allocator,+ typename CompletionCondition, typename ReadHandler>+ class read_at_streambuf_op+ : detail::base_from_completion_cond<CompletionCondition>+ {+ public:+ read_at_streambuf_op(AsyncRandomAccessReadDevice& device,+ uint64_t offset, basic_streambuf<Allocator>& streambuf,+ CompletionCondition& completion_condition, ReadHandler& handler)+ : detail::base_from_completion_cond<+ CompletionCondition>(completion_condition),+ device_(device),+ offset_(offset),+ streambuf_(streambuf),+ start_(0),+ total_transferred_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_at_streambuf_op(const read_at_streambuf_op& other)+ : detail::base_from_completion_cond<CompletionCondition>(other),+ device_(other.device_),+ offset_(other.offset_),+ streambuf_(other.streambuf_),+ start_(other.start_),+ total_transferred_(other.total_transferred_),+ handler_(other.handler_)+ {+ }++ read_at_streambuf_op(read_at_streambuf_op&& other)+ : detail::base_from_completion_cond<CompletionCondition>(+ ASIO_MOVE_CAST(detail::base_from_completion_cond<+ CompletionCondition>)(other)),+ device_(other.device_),+ offset_(other.offset_),+ streambuf_(other.streambuf_),+ start_(other.start_),+ total_transferred_(other.total_transferred_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ std::size_t max_size, bytes_available;+ switch (start_ = start)+ {+ case 1:+ max_size = this->check_for_completion(ec, total_transferred_);+ bytes_available = read_size_helper(streambuf_, max_size);+ for (;;)+ {+ {+ ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at"));+ device_.async_read_some_at(offset_ + total_transferred_,+ streambuf_.prepare(bytes_available),+ ASIO_MOVE_CAST(read_at_streambuf_op)(*this));+ }+ return; default:+ total_transferred_ += bytes_transferred;+ streambuf_.commit(bytes_transferred);+ max_size = this->check_for_completion(ec, total_transferred_);+ bytes_available = read_size_helper(streambuf_, max_size);+ if ((!ec && bytes_transferred == 0) || bytes_available == 0)+ break;+ }++ handler_(ec, static_cast<const std::size_t&>(total_transferred_));+ }+ }++ //private:+ AsyncRandomAccessReadDevice& device_;+ uint64_t offset_;+ asio::basic_streambuf<Allocator>& streambuf_;+ int start_;+ std::size_t total_transferred_;+ ReadHandler handler_;+ };++ template <typename AsyncRandomAccessReadDevice, typename Allocator,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,+ CompletionCondition, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncRandomAccessReadDevice, typename Allocator,+ typename CompletionCondition, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncRandomAccessReadDevice, typename Allocator,+ typename CompletionCondition, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,+ CompletionCondition, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncRandomAccessReadDevice,+ typename Allocator, typename CompletionCondition, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncRandomAccessReadDevice,+ typename Allocator, typename CompletionCondition, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,+ CompletionCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncRandomAccessReadDevice>+ class initiate_async_read_at_streambuf+ {+ public:+ typedef typename AsyncRandomAccessReadDevice::executor_type executor_type;++ explicit initiate_async_read_at_streambuf(+ AsyncRandomAccessReadDevice& device)+ : device_(device)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return device_.get_executor();+ }++ template <typename ReadHandler,+ typename Allocator, typename CompletionCondition>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ uint64_t offset, basic_streambuf<Allocator>* b,+ ASIO_MOVE_ARG(CompletionCondition) completion_cond) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);+ read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,+ CompletionCondition, typename decay<ReadHandler>::type>(+ device_, offset, *b, completion_cond2.value, handler2.value)(+ asio::error_code(), 0, 1);+ }++ private:+ AsyncRandomAccessReadDevice& device_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncRandomAccessReadDevice, typename Allocator,+ typename CompletionCondition, typename ReadHandler, typename Allocator1>+struct associated_allocator<+ detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,+ Allocator, CompletionCondition, ReadHandler>,+ Allocator1>+{+ typedef typename associated_allocator<ReadHandler, Allocator1>::type type;++ static type get(+ const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,+ Allocator, CompletionCondition, ReadHandler>& h,+ const Allocator1& a = Allocator1()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a);+ }+};++template <typename AsyncRandomAccessReadDevice, typename Executor,+ typename CompletionCondition, typename ReadHandler, typename Executor1>+struct associated_executor<+ detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,+ Executor, CompletionCondition, ReadHandler>,+ Executor1>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor1>::type type;++ static type get(+ const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,+ Executor, CompletionCondition, ReadHandler>& h,+ const Executor1& ex = Executor1()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncRandomAccessReadDevice,+ typename Allocator, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_at(AsyncRandomAccessReadDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d),+ handler, offset, &b,+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++template <typename AsyncRandomAccessReadDevice, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_at(AsyncRandomAccessReadDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b,+ ASIO_MOVE_ARG(ReadHandler) handler)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d),+ handler, offset, &b, transfer_all());+}++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_READ_AT_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/read_until.hpp view
@@ -0,0 +1,3335 @@+//+// impl/read_until.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_READ_UNTIL_HPP+#define ASIO_IMPL_READ_UNTIL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include <algorithm>+#include <string>+#include <vector>+#include <utility>+#include "asio/associated_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/buffer.hpp"+#include "asio/buffers_iterator.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_cont_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_tracking.hpp"+#include "asio/detail/handler_type_requirements.hpp"+#include "asio/detail/limits.hpp"+#include "asio/detail/non_const_lvalue.hpp"+#include "asio/detail/throw_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++namespace detail+{+ // Algorithm that finds a subsequence of equal values in a sequence. Returns+ // (iterator,true) if a full match was found, in which case the iterator+ // points to the beginning of the match. Returns (iterator,false) if a+ // partial match was found at the end of the first sequence, in which case+ // the iterator points to the beginning of the partial match. Returns+ // (last1,false) if no full or partial match was found.+ template <typename Iterator1, typename Iterator2>+ std::pair<Iterator1, bool> partial_search(+ Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)+ {+ for (Iterator1 iter1 = first1; iter1 != last1; ++iter1)+ {+ Iterator1 test_iter1 = iter1;+ Iterator2 test_iter2 = first2;+ for (;; ++test_iter1, ++test_iter2)+ {+ if (test_iter2 == last2)+ return std::make_pair(iter1, true);+ if (test_iter1 == last1)+ {+ if (test_iter2 != first2)+ return std::make_pair(iter1, false);+ else+ break;+ }+ if (*test_iter1 != *test_iter2)+ break;+ }+ }+ return std::make_pair(last1, false);+ }+} // namespace detail++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++template <typename SyncReadStream, typename DynamicBuffer_v1>+inline std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_until(s,+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, ec);+ asio::detail::throw_error(ec, "read_until");+ return bytes_transferred;+}++template <typename SyncReadStream, typename DynamicBuffer_v1>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ char delim, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ typename decay<DynamicBuffer_v1>::type b(+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));++ std::size_t search_position = 0;+ for (;;)+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers = b.data();+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ iterator iter = std::find(start_pos, end, delim);+ if (iter != end)+ {+ // Found a match. We're done.+ ec = asio::error_code();+ return iter - begin + 1;+ }+ else+ {+ // No match. Next search can start with the new data.+ search_position = end - begin;+ }++ // Check if buffer is full.+ if (b.size() == b.max_size())+ {+ ec = error::not_found;+ return 0;+ }++ // Need more data.+ std::size_t bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(65536, b.max_size() - b.size()));+ b.commit(s.read_some(b.prepare(bytes_to_read), ec));+ if (ec)+ return 0;+ }+}++template <typename SyncReadStream, typename DynamicBuffer_v1>+inline std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_STRING_VIEW_PARAM delim,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_until(s,+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, ec);+ asio::detail::throw_error(ec, "read_until");+ return bytes_transferred;+}++template <typename SyncReadStream, typename DynamicBuffer_v1>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ typename decay<DynamicBuffer_v1>::type b(+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));++ std::size_t search_position = 0;+ for (;;)+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers = b.data();+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ std::pair<iterator, bool> result = detail::partial_search(+ start_pos, end, delim.begin(), delim.end());+ if (result.first != end)+ {+ if (result.second)+ {+ // Full match. We're done.+ ec = asio::error_code();+ return result.first - begin + delim.length();+ }+ else+ {+ // Partial match. Next search needs to start from beginning of match.+ search_position = result.first - begin;+ }+ }+ else+ {+ // No match. Next search can start with the new data.+ search_position = end - begin;+ }++ // Check if buffer is full.+ if (b.size() == b.max_size())+ {+ ec = error::not_found;+ return 0;+ }++ // Need more data.+ std::size_t bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(65536, b.max_size() - b.size()));+ b.commit(s.read_some(b.prepare(bytes_to_read), ec));+ if (ec)+ return 0;+ }+}++#if !defined(ASIO_NO_EXTENSIONS)+#if defined(ASIO_HAS_BOOST_REGEX)++template <typename SyncReadStream, typename DynamicBuffer_v1>+inline std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ const boost::regex& expr,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_until(s,+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr, ec);+ asio::detail::throw_error(ec, "read_until");+ return bytes_transferred;+}++template <typename SyncReadStream, typename DynamicBuffer_v1>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ const boost::regex& expr, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ typename decay<DynamicBuffer_v1>::type b(+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));++ std::size_t search_position = 0;+ for (;;)+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers = b.data();+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ boost::match_results<iterator,+ typename std::vector<boost::sub_match<iterator> >::allocator_type>+ match_results;+ if (regex_search(start_pos, end, match_results, expr,+ boost::match_default | boost::match_partial))+ {+ if (match_results[0].matched)+ {+ // Full match. We're done.+ ec = asio::error_code();+ return match_results[0].second - begin;+ }+ else+ {+ // Partial match. Next search needs to start from beginning of match.+ search_position = match_results[0].first - begin;+ }+ }+ else+ {+ // No match. Next search can start with the new data.+ search_position = end - begin;+ }++ // Check if buffer is full.+ if (b.size() == b.max_size())+ {+ ec = error::not_found;+ return 0;+ }++ // Need more data.+ std::size_t bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(65536, b.max_size() - b.size()));+ b.commit(s.read_some(b.prepare(bytes_to_read), ec));+ if (ec)+ return 0;+ }+}++#endif // defined(ASIO_HAS_BOOST_REGEX)++template <typename SyncReadStream,+ typename DynamicBuffer_v1, typename MatchCondition>+inline std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ MatchCondition match_condition,+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_until(s,+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ match_condition, ec);+ asio::detail::throw_error(ec, "read_until");+ return bytes_transferred;+}++template <typename SyncReadStream,+ typename DynamicBuffer_v1, typename MatchCondition>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ MatchCondition match_condition, asio::error_code& ec,+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ typename decay<DynamicBuffer_v1>::type b(+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));++ std::size_t search_position = 0;+ for (;;)+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v1::const_buffers_type buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers = b.data();+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ std::pair<iterator, bool> result = match_condition(start_pos, end);+ if (result.second)+ {+ // Full match. We're done.+ ec = asio::error_code();+ return result.first - begin;+ }+ else if (result.first != end)+ {+ // Partial match. Next search needs to start from beginning of match.+ search_position = result.first - begin;+ }+ else+ {+ // No match. Next search can start with the new data.+ search_position = end - begin;+ }++ // Check if buffer is full.+ if (b.size() == b.max_size())+ {+ ec = error::not_found;+ return 0;+ }++ // Need more data.+ std::size_t bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(65536, b.max_size() - b.size()));+ b.commit(s.read_some(b.prepare(bytes_to_read), ec));+ if (ec)+ return 0;+ }+}++#if !defined(ASIO_NO_IOSTREAM)++template <typename SyncReadStream, typename Allocator>+inline std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, char delim)+{+ return read_until(s, basic_streambuf_ref<Allocator>(b), delim);+}++template <typename SyncReadStream, typename Allocator>+inline std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, char delim,+ asio::error_code& ec)+{+ return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);+}++template <typename SyncReadStream, typename Allocator>+inline std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ ASIO_STRING_VIEW_PARAM delim)+{+ return read_until(s, basic_streambuf_ref<Allocator>(b), delim);+}++template <typename SyncReadStream, typename Allocator>+inline std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec)+{+ return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec);+}++#if defined(ASIO_HAS_BOOST_REGEX)++template <typename SyncReadStream, typename Allocator>+inline std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr)+{+ return read_until(s, basic_streambuf_ref<Allocator>(b), expr);+}++template <typename SyncReadStream, typename Allocator>+inline std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr,+ asio::error_code& ec)+{+ return read_until(s, basic_streambuf_ref<Allocator>(b), expr, ec);+}++#endif // defined(ASIO_HAS_BOOST_REGEX)++template <typename SyncReadStream, typename Allocator, typename MatchCondition>+inline std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,+ typename enable_if<is_match_condition<MatchCondition>::value>::type*)+{+ return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition);+}++template <typename SyncReadStream, typename Allocator, typename MatchCondition>+inline std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ MatchCondition match_condition, asio::error_code& ec,+ typename enable_if<is_match_condition<MatchCondition>::value>::type*)+{+ return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition, ec);+}++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++template <typename SyncReadStream, typename DynamicBuffer_v2>+inline std::size_t read_until(SyncReadStream& s,+ DynamicBuffer_v2 buffers, char delim,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_until(s,+ ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, ec);+ asio::detail::throw_error(ec, "read_until");+ return bytes_transferred;+}++template <typename SyncReadStream, typename DynamicBuffer_v2>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,+ char delim, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ DynamicBuffer_v2& b = buffers;++ std::size_t search_position = 0;+ for (;;)+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers =+ const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ iterator iter = std::find(start_pos, end, delim);+ if (iter != end)+ {+ // Found a match. We're done.+ ec = asio::error_code();+ return iter - begin + 1;+ }+ else+ {+ // No match. Next search can start with the new data.+ search_position = end - begin;+ }++ // Check if buffer is full.+ if (b.size() == b.max_size())+ {+ ec = error::not_found;+ return 0;+ }++ // Need more data.+ std::size_t bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(65536, b.max_size() - b.size()));+ std::size_t pos = b.size();+ b.grow(bytes_to_read);+ std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);+ b.shrink(bytes_to_read - bytes_transferred);+ if (ec)+ return 0;+ }+}++template <typename SyncReadStream, typename DynamicBuffer_v2>+inline std::size_t read_until(SyncReadStream& s,+ DynamicBuffer_v2 buffers, ASIO_STRING_VIEW_PARAM delim,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_until(s,+ ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, ec);+ asio::detail::throw_error(ec, "read_until");+ return bytes_transferred;+}++template <typename SyncReadStream, typename DynamicBuffer_v2>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,+ ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ DynamicBuffer_v2& b = buffers;++ std::size_t search_position = 0;+ for (;;)+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers =+ const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ std::pair<iterator, bool> result = detail::partial_search(+ start_pos, end, delim.begin(), delim.end());+ if (result.first != end)+ {+ if (result.second)+ {+ // Full match. We're done.+ ec = asio::error_code();+ return result.first - begin + delim.length();+ }+ else+ {+ // Partial match. Next search needs to start from beginning of match.+ search_position = result.first - begin;+ }+ }+ else+ {+ // No match. Next search can start with the new data.+ search_position = end - begin;+ }++ // Check if buffer is full.+ if (b.size() == b.max_size())+ {+ ec = error::not_found;+ return 0;+ }++ // Need more data.+ std::size_t bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(65536, b.max_size() - b.size()));+ std::size_t pos = b.size();+ b.grow(bytes_to_read);+ std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);+ b.shrink(bytes_to_read - bytes_transferred);+ if (ec)+ return 0;+ }+}++#if !defined(ASIO_NO_EXTENSIONS)+#if defined(ASIO_HAS_BOOST_REGEX)++template <typename SyncReadStream, typename DynamicBuffer_v2>+inline std::size_t read_until(SyncReadStream& s,+ DynamicBuffer_v2 buffers, const boost::regex& expr,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_until(s,+ ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr, ec);+ asio::detail::throw_error(ec, "read_until");+ return bytes_transferred;+}++template <typename SyncReadStream, typename DynamicBuffer_v2>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,+ const boost::regex& expr, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ DynamicBuffer_v2& b = buffers;++ std::size_t search_position = 0;+ for (;;)+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers =+ const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ boost::match_results<iterator,+ typename std::vector<boost::sub_match<iterator> >::allocator_type>+ match_results;+ if (regex_search(start_pos, end, match_results, expr,+ boost::match_default | boost::match_partial))+ {+ if (match_results[0].matched)+ {+ // Full match. We're done.+ ec = asio::error_code();+ return match_results[0].second - begin;+ }+ else+ {+ // Partial match. Next search needs to start from beginning of match.+ search_position = match_results[0].first - begin;+ }+ }+ else+ {+ // No match. Next search can start with the new data.+ search_position = end - begin;+ }++ // Check if buffer is full.+ if (b.size() == b.max_size())+ {+ ec = error::not_found;+ return 0;+ }++ // Need more data.+ std::size_t bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(65536, b.max_size() - b.size()));+ std::size_t pos = b.size();+ b.grow(bytes_to_read);+ std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);+ b.shrink(bytes_to_read - bytes_transferred);+ if (ec)+ return 0;+ }+}++#endif // defined(ASIO_HAS_BOOST_REGEX)++template <typename SyncReadStream,+ typename DynamicBuffer_v2, typename MatchCondition>+inline std::size_t read_until(SyncReadStream& s,+ DynamicBuffer_v2 buffers, MatchCondition match_condition,+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = read_until(s,+ ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ match_condition, ec);+ asio::detail::throw_error(ec, "read_until");+ return bytes_transferred;+}++template <typename SyncReadStream,+ typename DynamicBuffer_v2, typename MatchCondition>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,+ MatchCondition match_condition, asio::error_code& ec,+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ DynamicBuffer_v2& b = buffers;++ std::size_t search_position = 0;+ for (;;)+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v2::const_buffers_type buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers =+ const_cast<const DynamicBuffer_v2&>(b).data(0, b.size());+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ std::pair<iterator, bool> result = match_condition(start_pos, end);+ if (result.second)+ {+ // Full match. We're done.+ ec = asio::error_code();+ return result.first - begin;+ }+ else if (result.first != end)+ {+ // Partial match. Next search needs to start from beginning of match.+ search_position = result.first - begin;+ }+ else+ {+ // No match. Next search can start with the new data.+ search_position = end - begin;+ }++ // Check if buffer is full.+ if (b.size() == b.max_size())+ {+ ec = error::not_found;+ return 0;+ }++ // Need more data.+ std::size_t bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512, b.capacity() - b.size()),+ std::min<std::size_t>(65536, b.max_size() - b.size()));+ std::size_t pos = b.size();+ b.grow(bytes_to_read);+ std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec);+ b.shrink(bytes_to_read - bytes_transferred);+ if (ec)+ return 0;+ }+}++#endif // !defined(ASIO_NO_EXTENSIONS)++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++namespace detail+{+ template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ class read_until_delim_op_v1+ {+ public:+ template <typename BufferSequence>+ read_until_delim_op_v1(AsyncReadStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ char delim, ReadHandler& handler)+ : stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ delim_(delim),+ start_(0),+ search_position_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_until_delim_op_v1(const read_until_delim_op_v1& other)+ : stream_(other.stream_),+ buffers_(other.buffers_),+ delim_(other.delim_),+ start_(other.start_),+ search_position_(other.search_position_),+ handler_(other.handler_)+ {+ }++ read_until_delim_op_v1(read_until_delim_op_v1&& other)+ : stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),+ delim_(other.delim_),+ start_(other.start_),+ search_position_(other.search_position_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();+ std::size_t bytes_to_read;+ switch (start_ = start)+ {+ case 1:+ for (;;)+ {+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v1::const_buffers_type+ buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers = buffers_.data();+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position_;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ iterator iter = std::find(start_pos, end, delim_);+ if (iter != end)+ {+ // Found a match. We're done.+ search_position_ = iter - begin + 1;+ bytes_to_read = 0;+ }++ // No match yet. Check if buffer is full.+ else if (buffers_.size() == buffers_.max_size())+ {+ search_position_ = not_found;+ bytes_to_read = 0;+ }++ // Need to read some more data.+ else+ {+ // Next search can start with the new data.+ search_position_ = end - begin;+ bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(65536,+ buffers_.max_size() - buffers_.size()));+ }+ }++ // Check if we're done.+ if (!start && bytes_to_read == 0)+ break;++ // Start a new asynchronous read operation to obtain more data.+ {+ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, "async_read_until"));+ stream_.async_read_some(buffers_.prepare(bytes_to_read),+ ASIO_MOVE_CAST(read_until_delim_op_v1)(*this));+ }+ return; default:+ buffers_.commit(bytes_transferred);+ if (ec || bytes_transferred == 0)+ break;+ }++ const asio::error_code result_ec =+ (search_position_ == not_found)+ ? error::not_found : ec;++ const std::size_t result_n =+ (ec || search_position_ == not_found)+ ? 0 : search_position_;++ handler_(result_ec, result_n);+ }+ }++ //private:+ AsyncReadStream& stream_;+ DynamicBuffer_v1 buffers_;+ char delim_;+ int start_;+ std::size_t search_position_;+ ReadHandler handler_;+ };++ template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_until_delim_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_until_delim_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_until_delim_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_until_delim_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_until_delim_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream>+ class initiate_async_read_until_delim_v1+ {+ public:+ typedef typename AsyncReadStream::executor_type executor_type;++ explicit initiate_async_read_until_delim_v1(AsyncReadStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename ReadHandler, typename DynamicBuffer_v1>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ char delim) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ read_until_delim_op_v1<AsyncReadStream,+ typename decay<DynamicBuffer_v1>::type,+ typename decay<ReadHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ delim, handler2.value)(asio::error_code(), 0, 1);+ }++ private:+ AsyncReadStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_until_delim_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_until_delim_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_until_delim_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_until_delim_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ char delim, ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_until_delim_v1<AsyncReadStream>(s),+ handler, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim);+}++namespace detail+{+ template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ class read_until_delim_string_op_v1+ {+ public:+ template <typename BufferSequence>+ read_until_delim_string_op_v1(AsyncReadStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ const std::string& delim, ReadHandler& handler)+ : stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ delim_(delim),+ start_(0),+ search_position_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_until_delim_string_op_v1(const read_until_delim_string_op_v1& other)+ : stream_(other.stream_),+ buffers_(other.buffers_),+ delim_(other.delim_),+ start_(other.start_),+ search_position_(other.search_position_),+ handler_(other.handler_)+ {+ }++ read_until_delim_string_op_v1(read_until_delim_string_op_v1&& other)+ : stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),+ delim_(ASIO_MOVE_CAST(std::string)(other.delim_)),+ start_(other.start_),+ search_position_(other.search_position_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();+ std::size_t bytes_to_read;+ switch (start_ = start)+ {+ case 1:+ for (;;)+ {+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v1::const_buffers_type+ buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers = buffers_.data();+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position_;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ std::pair<iterator, bool> result = detail::partial_search(+ start_pos, end, delim_.begin(), delim_.end());+ if (result.first != end && result.second)+ {+ // Full match. We're done.+ search_position_ = result.first - begin + delim_.length();+ bytes_to_read = 0;+ }++ // No match yet. Check if buffer is full.+ else if (buffers_.size() == buffers_.max_size())+ {+ search_position_ = not_found;+ bytes_to_read = 0;+ }++ // Need to read some more data.+ else+ {+ if (result.first != end)+ {+ // Partial match. Next search needs to start from beginning of+ // match.+ search_position_ = result.first - begin;+ }+ else+ {+ // Next search can start with the new data.+ search_position_ = end - begin;+ }++ bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(65536,+ buffers_.max_size() - buffers_.size()));+ }+ }++ // Check if we're done.+ if (!start && bytes_to_read == 0)+ break;++ // Start a new asynchronous read operation to obtain more data.+ {+ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, "async_read_until"));+ stream_.async_read_some(buffers_.prepare(bytes_to_read),+ ASIO_MOVE_CAST(read_until_delim_string_op_v1)(*this));+ }+ return; default:+ buffers_.commit(bytes_transferred);+ if (ec || bytes_transferred == 0)+ break;+ }++ const asio::error_code result_ec =+ (search_position_ == not_found)+ ? error::not_found : ec;++ const std::size_t result_n =+ (ec || search_position_ == not_found)+ ? 0 : search_position_;++ handler_(result_ec, result_n);+ }+ }++ //private:+ AsyncReadStream& stream_;+ DynamicBuffer_v1 buffers_;+ std::string delim_;+ int start_;+ std::size_t search_position_;+ ReadHandler handler_;+ };++ template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_until_delim_string_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_until_delim_string_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_until_delim_string_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_until_delim_string_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v1, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_until_delim_string_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream>+ class initiate_async_read_until_delim_string_v1+ {+ public:+ typedef typename AsyncReadStream::executor_type executor_type;++ explicit initiate_async_read_until_delim_string_v1(AsyncReadStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename ReadHandler, typename DynamicBuffer_v1>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ const std::string& delim) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ read_until_delim_string_op_v1<AsyncReadStream,+ typename decay<DynamicBuffer_v1>::type,+ typename decay<ReadHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ delim, handler2.value)(asio::error_code(), 0, 1);+ }++ private:+ AsyncReadStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_until_delim_string_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_until_delim_string_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_until_delim_string_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_until_delim_string_op_v1<AsyncReadStream,+ DynamicBuffer_v1, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_STRING_VIEW_PARAM delim,+ ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_until_delim_string_v1<AsyncReadStream>(s),+ handler, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ static_cast<std::string>(delim));+}++#if !defined(ASIO_NO_EXTENSIONS)+#if defined(ASIO_HAS_BOOST_REGEX)++namespace detail+{+ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename RegEx, typename ReadHandler>+ class read_until_expr_op_v1+ {+ public:+ template <typename BufferSequence>+ read_until_expr_op_v1(AsyncReadStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ const boost::regex& expr, ReadHandler& handler)+ : stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ expr_(expr),+ start_(0),+ search_position_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_until_expr_op_v1(const read_until_expr_op_v1& other)+ : stream_(other.stream_),+ buffers_(other.buffers_),+ expr_(other.expr_),+ start_(other.start_),+ search_position_(other.search_position_),+ handler_(other.handler_)+ {+ }++ read_until_expr_op_v1(read_until_expr_op_v1&& other)+ : stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),+ expr_(other.expr_),+ start_(other.start_),+ search_position_(other.search_position_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();+ std::size_t bytes_to_read;+ switch (start_ = start)+ {+ case 1:+ for (;;)+ {+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v1::const_buffers_type+ buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers = buffers_.data();+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position_;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ boost::match_results<iterator,+ typename std::vector<boost::sub_match<iterator> >::allocator_type>+ match_results;+ bool match = regex_search(start_pos, end, match_results, expr_,+ boost::match_default | boost::match_partial);+ if (match && match_results[0].matched)+ {+ // Full match. We're done.+ search_position_ = match_results[0].second - begin;+ bytes_to_read = 0;+ }++ // No match yet. Check if buffer is full.+ else if (buffers_.size() == buffers_.max_size())+ {+ search_position_ = not_found;+ bytes_to_read = 0;+ }++ // Need to read some more data.+ else+ {+ if (match)+ {+ // Partial match. Next search needs to start from beginning of+ // match.+ search_position_ = match_results[0].first - begin;+ }+ else+ {+ // Next search can start with the new data.+ search_position_ = end - begin;+ }++ bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(65536,+ buffers_.max_size() - buffers_.size()));+ }+ }++ // Check if we're done.+ if (!start && bytes_to_read == 0)+ break;++ // Start a new asynchronous read operation to obtain more data.+ {+ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, "async_read_until"));+ stream_.async_read_some(buffers_.prepare(bytes_to_read),+ ASIO_MOVE_CAST(read_until_expr_op_v1)(*this));+ }+ return; default:+ buffers_.commit(bytes_transferred);+ if (ec || bytes_transferred == 0)+ break;+ }++ const asio::error_code result_ec =+ (search_position_ == not_found)+ ? error::not_found : ec;++ const std::size_t result_n =+ (ec || search_position_ == not_found)+ ? 0 : search_position_;++ handler_(result_ec, result_n);+ }+ }++ //private:+ AsyncReadStream& stream_;+ DynamicBuffer_v1 buffers_;+ RegEx expr_;+ int start_;+ std::size_t search_position_;+ ReadHandler handler_;+ };++ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename RegEx, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_until_expr_op_v1<AsyncReadStream,+ DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename RegEx, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_until_expr_op_v1<AsyncReadStream,+ DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename RegEx, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_until_expr_op_v1<AsyncReadStream,+ DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v1, typename RegEx, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_until_expr_op_v1<AsyncReadStream,+ DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v1, typename RegEx, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_until_expr_op_v1<AsyncReadStream,+ DynamicBuffer_v1, RegEx, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream>+ class initiate_async_read_until_expr_v1+ {+ public:+ typedef typename AsyncReadStream::executor_type executor_type;++ explicit initiate_async_read_until_expr_v1(AsyncReadStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename ReadHandler, typename DynamicBuffer_v1, typename RegEx>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, const RegEx& expr) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ read_until_expr_op_v1<AsyncReadStream,+ typename decay<DynamicBuffer_v1>::type,+ RegEx, typename decay<ReadHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ expr, handler2.value)(asio::error_code(), 0, 1);+ }++ private:+ AsyncReadStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename RegEx, typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_until_expr_op_v1<AsyncReadStream,+ DynamicBuffer_v1, RegEx, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_until_expr_op_v1<AsyncReadStream,+ DynamicBuffer_v1, RegEx, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename RegEx, typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_until_expr_op_v1<AsyncReadStream,+ DynamicBuffer_v1, RegEx, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_until_expr_op_v1<AsyncReadStream,+ DynamicBuffer_v1, RegEx, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ const boost::regex& expr,+ ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_until_expr_v1<AsyncReadStream>(s),+ handler, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr);+}++#endif // defined(ASIO_HAS_BOOST_REGEX)++namespace detail+{+ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename MatchCondition, typename ReadHandler>+ class read_until_match_op_v1+ {+ public:+ template <typename BufferSequence>+ read_until_match_op_v1(AsyncReadStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ MatchCondition match_condition, ReadHandler& handler)+ : stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ match_condition_(match_condition),+ start_(0),+ search_position_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_until_match_op_v1(const read_until_match_op_v1& other)+ : stream_(other.stream_),+ buffers_(other.buffers_),+ match_condition_(other.match_condition_),+ start_(other.start_),+ search_position_(other.search_position_),+ handler_(other.handler_)+ {+ }++ read_until_match_op_v1(read_until_match_op_v1&& other)+ : stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),+ match_condition_(other.match_condition_),+ start_(other.start_),+ search_position_(other.search_position_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();+ std::size_t bytes_to_read;+ switch (start_ = start)+ {+ case 1:+ for (;;)+ {+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v1::const_buffers_type+ buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers = buffers_.data();+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position_;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ std::pair<iterator, bool> result = match_condition_(start_pos, end);+ if (result.second)+ {+ // Full match. We're done.+ search_position_ = result.first - begin;+ bytes_to_read = 0;+ }++ // No match yet. Check if buffer is full.+ else if (buffers_.size() == buffers_.max_size())+ {+ search_position_ = not_found;+ bytes_to_read = 0;+ }++ // Need to read some more data.+ else+ {+ if (result.first != end)+ {+ // Partial match. Next search needs to start from beginning of+ // match.+ search_position_ = result.first - begin;+ }+ else+ {+ // Next search can start with the new data.+ search_position_ = end - begin;+ }++ bytes_to_read = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(65536,+ buffers_.max_size() - buffers_.size()));+ }+ }++ // Check if we're done.+ if (!start && bytes_to_read == 0)+ break;++ // Start a new asynchronous read operation to obtain more data.+ {+ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, "async_read_until"));+ stream_.async_read_some(buffers_.prepare(bytes_to_read),+ ASIO_MOVE_CAST(read_until_match_op_v1)(*this));+ }+ return; default:+ buffers_.commit(bytes_transferred);+ if (ec || bytes_transferred == 0)+ break;+ }++ const asio::error_code result_ec =+ (search_position_ == not_found)+ ? error::not_found : ec;++ const std::size_t result_n =+ (ec || search_position_ == not_found)+ ? 0 : search_position_;++ handler_(result_ec, result_n);+ }+ }++ //private:+ AsyncReadStream& stream_;+ DynamicBuffer_v1 buffers_;+ MatchCondition match_condition_;+ int start_;+ std::size_t search_position_;+ ReadHandler handler_;+ };++ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename MatchCondition, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,+ MatchCondition, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename MatchCondition, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,+ MatchCondition, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename MatchCondition, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,+ MatchCondition, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v1, typename MatchCondition,+ typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,+ MatchCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v1, typename MatchCondition,+ typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1,+ MatchCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream>+ class initiate_async_read_until_match_v1+ {+ public:+ typedef typename AsyncReadStream::executor_type executor_type;++ explicit initiate_async_read_until_match_v1(AsyncReadStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename ReadHandler,+ typename DynamicBuffer_v1, typename MatchCondition>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ MatchCondition match_condition) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ read_until_match_op_v1<AsyncReadStream,+ typename decay<DynamicBuffer_v1>::type,+ MatchCondition, typename decay<ReadHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ match_condition, handler2.value)(asio::error_code(), 0, 1);+ }++ private:+ AsyncReadStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename MatchCondition, typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_until_match_op_v1<AsyncReadStream,+ DynamicBuffer_v1, MatchCondition, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_until_match_op_v1<AsyncReadStream,+ DynamicBuffer_v1, MatchCondition, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncReadStream, typename DynamicBuffer_v1,+ typename MatchCondition, typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_until_match_op_v1<AsyncReadStream,+ DynamicBuffer_v1, MatchCondition, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_until_match_op_v1<AsyncReadStream,+ DynamicBuffer_v1, MatchCondition, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename MatchCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_until_match_v1<AsyncReadStream>(s), handler,+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), match_condition);+}++#if !defined(ASIO_NO_IOSTREAM)++template <typename AsyncReadStream, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ char delim, ASIO_MOVE_ARG(ReadHandler) handler)+{+ return async_read_until(s, basic_streambuf_ref<Allocator>(b),+ delim, ASIO_MOVE_CAST(ReadHandler)(handler));+}++template <typename AsyncReadStream, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ ASIO_STRING_VIEW_PARAM delim,+ ASIO_MOVE_ARG(ReadHandler) handler)+{+ return async_read_until(s, basic_streambuf_ref<Allocator>(b),+ delim, ASIO_MOVE_CAST(ReadHandler)(handler));+}++#if defined(ASIO_HAS_BOOST_REGEX)++template <typename AsyncReadStream, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr,+ ASIO_MOVE_ARG(ReadHandler) handler)+{+ return async_read_until(s, basic_streambuf_ref<Allocator>(b),+ expr, ASIO_MOVE_CAST(ReadHandler)(handler));+}++#endif // defined(ASIO_HAS_BOOST_REGEX)++template <typename AsyncReadStream, typename Allocator, typename MatchCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<is_match_condition<MatchCondition>::value>::type*)+{+ return async_read_until(s, basic_streambuf_ref<Allocator>(b),+ match_condition, ASIO_MOVE_CAST(ReadHandler)(handler));+}++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++namespace detail+{+ template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ class read_until_delim_op_v2+ {+ public:+ template <typename BufferSequence>+ read_until_delim_op_v2(AsyncReadStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ char delim, ReadHandler& handler)+ : stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ delim_(delim),+ start_(0),+ search_position_(0),+ bytes_to_read_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_until_delim_op_v2(const read_until_delim_op_v2& other)+ : stream_(other.stream_),+ buffers_(other.buffers_),+ delim_(other.delim_),+ start_(other.start_),+ search_position_(other.search_position_),+ bytes_to_read_(other.bytes_to_read_),+ handler_(other.handler_)+ {+ }++ read_until_delim_op_v2(read_until_delim_op_v2&& other)+ : stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),+ delim_(other.delim_),+ start_(other.start_),+ search_position_(other.search_position_),+ bytes_to_read_(other.bytes_to_read_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();+ std::size_t pos;+ switch (start_ = start)+ {+ case 1:+ for (;;)+ {+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v2::const_buffers_type+ buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers =+ const_cast<const DynamicBuffer_v2&>(buffers_).data(+ 0, buffers_.size());+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position_;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ iterator iter = std::find(start_pos, end, delim_);+ if (iter != end)+ {+ // Found a match. We're done.+ search_position_ = iter - begin + 1;+ bytes_to_read_ = 0;+ }++ // No match yet. Check if buffer is full.+ else if (buffers_.size() == buffers_.max_size())+ {+ search_position_ = not_found;+ bytes_to_read_ = 0;+ }++ // Need to read some more data.+ else+ {+ // Next search can start with the new data.+ search_position_ = end - begin;+ bytes_to_read_ = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(65536,+ buffers_.max_size() - buffers_.size()));+ }+ }++ // Check if we're done.+ if (!start && bytes_to_read_ == 0)+ break;++ // Start a new asynchronous read operation to obtain more data.+ pos = buffers_.size();+ buffers_.grow(bytes_to_read_);+ {+ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, "async_read_until"));+ stream_.async_read_some(buffers_.data(pos, bytes_to_read_),+ ASIO_MOVE_CAST(read_until_delim_op_v2)(*this));+ }+ return; default:+ buffers_.shrink(bytes_to_read_ - bytes_transferred);+ if (ec || bytes_transferred == 0)+ break;+ }++ const asio::error_code result_ec =+ (search_position_ == not_found)+ ? error::not_found : ec;++ const std::size_t result_n =+ (ec || search_position_ == not_found)+ ? 0 : search_position_;++ handler_(result_ec, result_n);+ }+ }++ //private:+ AsyncReadStream& stream_;+ DynamicBuffer_v2 buffers_;+ char delim_;+ int start_;+ std::size_t search_position_;+ std::size_t bytes_to_read_;+ ReadHandler handler_;+ };++ template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_until_delim_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_until_delim_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_until_delim_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_until_delim_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_until_delim_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream>+ class initiate_async_read_until_delim_v2+ {+ public:+ typedef typename AsyncReadStream::executor_type executor_type;++ explicit initiate_async_read_until_delim_v2(AsyncReadStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename ReadHandler, typename DynamicBuffer_v2>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, char delim) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ read_until_delim_op_v2<AsyncReadStream,+ typename decay<DynamicBuffer_v2>::type,+ typename decay<ReadHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ delim, handler2.value)(asio::error_code(), 0, 1);+ }++ private:+ AsyncReadStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_until_delim_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_until_delim_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_until_delim_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_until_delim_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,+ char delim, ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_until_delim_v2<AsyncReadStream>(s),+ handler, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim);+}++namespace detail+{+ template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ class read_until_delim_string_op_v2+ {+ public:+ template <typename BufferSequence>+ read_until_delim_string_op_v2(AsyncReadStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ const std::string& delim, ReadHandler& handler)+ : stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ delim_(delim),+ start_(0),+ search_position_(0),+ bytes_to_read_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_until_delim_string_op_v2(const read_until_delim_string_op_v2& other)+ : stream_(other.stream_),+ buffers_(other.buffers_),+ delim_(other.delim_),+ start_(other.start_),+ search_position_(other.search_position_),+ bytes_to_read_(other.bytes_to_read_),+ handler_(other.handler_)+ {+ }++ read_until_delim_string_op_v2(read_until_delim_string_op_v2&& other)+ : stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),+ delim_(ASIO_MOVE_CAST(std::string)(other.delim_)),+ start_(other.start_),+ search_position_(other.search_position_),+ bytes_to_read_(other.bytes_to_read_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();+ std::size_t pos;+ switch (start_ = start)+ {+ case 1:+ for (;;)+ {+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v2::const_buffers_type+ buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers =+ const_cast<const DynamicBuffer_v2&>(buffers_).data(+ 0, buffers_.size());+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position_;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ std::pair<iterator, bool> result = detail::partial_search(+ start_pos, end, delim_.begin(), delim_.end());+ if (result.first != end && result.second)+ {+ // Full match. We're done.+ search_position_ = result.first - begin + delim_.length();+ bytes_to_read_ = 0;+ }++ // No match yet. Check if buffer is full.+ else if (buffers_.size() == buffers_.max_size())+ {+ search_position_ = not_found;+ bytes_to_read_ = 0;+ }++ // Need to read some more data.+ else+ {+ if (result.first != end)+ {+ // Partial match. Next search needs to start from beginning of+ // match.+ search_position_ = result.first - begin;+ }+ else+ {+ // Next search can start with the new data.+ search_position_ = end - begin;+ }++ bytes_to_read_ = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(65536,+ buffers_.max_size() - buffers_.size()));+ }+ }++ // Check if we're done.+ if (!start && bytes_to_read_ == 0)+ break;++ // Start a new asynchronous read operation to obtain more data.+ pos = buffers_.size();+ buffers_.grow(bytes_to_read_);+ {+ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, "async_read_until"));+ stream_.async_read_some(buffers_.data(pos, bytes_to_read_),+ ASIO_MOVE_CAST(read_until_delim_string_op_v2)(*this));+ }+ return; default:+ buffers_.shrink(bytes_to_read_ - bytes_transferred);+ if (ec || bytes_transferred == 0)+ break;+ }++ const asio::error_code result_ec =+ (search_position_ == not_found)+ ? error::not_found : ec;++ const std::size_t result_n =+ (ec || search_position_ == not_found)+ ? 0 : search_position_;++ handler_(result_ec, result_n);+ }+ }++ //private:+ AsyncReadStream& stream_;+ DynamicBuffer_v2 buffers_;+ std::string delim_;+ int start_;+ std::size_t search_position_;+ std::size_t bytes_to_read_;+ ReadHandler handler_;+ };++ template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_until_delim_string_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_until_delim_string_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_until_delim_string_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_until_delim_string_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v2, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_until_delim_string_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream>+ class initiate_async_read_until_delim_string_v2+ {+ public:+ typedef typename AsyncReadStream::executor_type executor_type;++ explicit initiate_async_read_until_delim_string_v2(AsyncReadStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename ReadHandler, typename DynamicBuffer_v2>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,+ const std::string& delim) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ read_until_delim_string_op_v2<AsyncReadStream,+ typename decay<DynamicBuffer_v2>::type,+ typename decay<ReadHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ delim, handler2.value)(asio::error_code(), 0, 1);+ }++ private:+ AsyncReadStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_until_delim_string_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_until_delim_string_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_until_delim_string_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_until_delim_string_op_v2<AsyncReadStream,+ DynamicBuffer_v2, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream,+ typename DynamicBuffer_v2,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ DynamicBuffer_v2 buffers, ASIO_STRING_VIEW_PARAM delim,+ ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_until_delim_string_v2<AsyncReadStream>(s),+ handler, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ static_cast<std::string>(delim));+}++#if !defined(ASIO_NO_EXTENSIONS)+#if defined(ASIO_HAS_BOOST_REGEX)++namespace detail+{+ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename RegEx, typename ReadHandler>+ class read_until_expr_op_v2+ {+ public:+ template <typename BufferSequence>+ read_until_expr_op_v2(AsyncReadStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ const boost::regex& expr, ReadHandler& handler)+ : stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ expr_(expr),+ start_(0),+ search_position_(0),+ bytes_to_read_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_until_expr_op_v2(const read_until_expr_op_v2& other)+ : stream_(other.stream_),+ buffers_(other.buffers_),+ expr_(other.expr_),+ start_(other.start_),+ search_position_(other.search_position_),+ bytes_to_read_(other.bytes_to_read_),+ handler_(other.handler_)+ {+ }++ read_until_expr_op_v2(read_until_expr_op_v2&& other)+ : stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),+ expr_(other.expr_),+ start_(other.start_),+ search_position_(other.search_position_),+ bytes_to_read_(other.bytes_to_read_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();+ std::size_t pos;+ switch (start_ = start)+ {+ case 1:+ for (;;)+ {+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v2::const_buffers_type+ buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers =+ const_cast<const DynamicBuffer_v2&>(buffers_).data(+ 0, buffers_.size());+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position_;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ boost::match_results<iterator,+ typename std::vector<boost::sub_match<iterator> >::allocator_type>+ match_results;+ bool match = regex_search(start_pos, end, match_results, expr_,+ boost::match_default | boost::match_partial);+ if (match && match_results[0].matched)+ {+ // Full match. We're done.+ search_position_ = match_results[0].second - begin;+ bytes_to_read_ = 0;+ }++ // No match yet. Check if buffer is full.+ else if (buffers_.size() == buffers_.max_size())+ {+ search_position_ = not_found;+ bytes_to_read_ = 0;+ }++ // Need to read some more data.+ else+ {+ if (match)+ {+ // Partial match. Next search needs to start from beginning of+ // match.+ search_position_ = match_results[0].first - begin;+ }+ else+ {+ // Next search can start with the new data.+ search_position_ = end - begin;+ }++ bytes_to_read_ = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(65536,+ buffers_.max_size() - buffers_.size()));+ }+ }++ // Check if we're done.+ if (!start && bytes_to_read_ == 0)+ break;++ // Start a new asynchronous read operation to obtain more data.+ pos = buffers_.size();+ buffers_.grow(bytes_to_read_);+ {+ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, "async_read_until"));+ stream_.async_read_some(buffers_.data(pos, bytes_to_read_),+ ASIO_MOVE_CAST(read_until_expr_op_v2)(*this));+ }+ return; default:+ buffers_.shrink(bytes_to_read_ - bytes_transferred);+ if (ec || bytes_transferred == 0)+ break;+ }++ const asio::error_code result_ec =+ (search_position_ == not_found)+ ? error::not_found : ec;++ const std::size_t result_n =+ (ec || search_position_ == not_found)+ ? 0 : search_position_;++ handler_(result_ec, result_n);+ }+ }++ //private:+ AsyncReadStream& stream_;+ DynamicBuffer_v2 buffers_;+ RegEx expr_;+ int start_;+ std::size_t search_position_;+ std::size_t bytes_to_read_;+ ReadHandler handler_;+ };++ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename RegEx, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_until_expr_op_v2<AsyncReadStream,+ DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename RegEx, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_until_expr_op_v2<AsyncReadStream,+ DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename RegEx, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_until_expr_op_v2<AsyncReadStream,+ DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v2, typename RegEx, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_until_expr_op_v2<AsyncReadStream,+ DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v2, typename RegEx, typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_until_expr_op_v2<AsyncReadStream,+ DynamicBuffer_v2, RegEx, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream>+ class initiate_async_read_until_expr_v2+ {+ public:+ typedef typename AsyncReadStream::executor_type executor_type;++ explicit initiate_async_read_until_expr_v2(AsyncReadStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename ReadHandler, typename DynamicBuffer_v2, typename RegEx>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,+ const RegEx& expr) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ read_until_expr_op_v2<AsyncReadStream,+ typename decay<DynamicBuffer_v2>::type,+ RegEx, typename decay<ReadHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ expr, handler2.value)(asio::error_code(), 0, 1);+ }++ private:+ AsyncReadStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename RegEx, typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_until_expr_op_v2<AsyncReadStream,+ DynamicBuffer_v2, RegEx, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_until_expr_op_v2<AsyncReadStream,+ DynamicBuffer_v2, RegEx, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename RegEx, typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_until_expr_op_v2<AsyncReadStream,+ DynamicBuffer_v2, RegEx, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_until_expr_op_v2<AsyncReadStream,+ DynamicBuffer_v2, RegEx, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,+ const boost::regex& expr, ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_until_expr_v2<AsyncReadStream>(s),+ handler, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr);+}++#endif // defined(ASIO_HAS_BOOST_REGEX)++namespace detail+{+ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename MatchCondition, typename ReadHandler>+ class read_until_match_op_v2+ {+ public:+ template <typename BufferSequence>+ read_until_match_op_v2(AsyncReadStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ MatchCondition match_condition, ReadHandler& handler)+ : stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ match_condition_(match_condition),+ start_(0),+ search_position_(0),+ bytes_to_read_(0),+ handler_(ASIO_MOVE_CAST(ReadHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ read_until_match_op_v2(const read_until_match_op_v2& other)+ : stream_(other.stream_),+ buffers_(other.buffers_),+ match_condition_(other.match_condition_),+ start_(other.start_),+ search_position_(other.search_position_),+ bytes_to_read_(other.bytes_to_read_),+ handler_(other.handler_)+ {+ }++ read_until_match_op_v2(read_until_match_op_v2&& other)+ : stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),+ match_condition_(other.match_condition_),+ start_(other.start_),+ search_position_(other.search_position_),+ bytes_to_read_(other.bytes_to_read_),+ handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ const std::size_t not_found = (std::numeric_limits<std::size_t>::max)();+ std::size_t pos;+ switch (start_ = start)+ {+ case 1:+ for (;;)+ {+ {+ // Determine the range of the data to be searched.+ typedef typename DynamicBuffer_v2::const_buffers_type+ buffers_type;+ typedef buffers_iterator<buffers_type> iterator;+ buffers_type data_buffers =+ const_cast<const DynamicBuffer_v2&>(buffers_).data(+ 0, buffers_.size());+ iterator begin = iterator::begin(data_buffers);+ iterator start_pos = begin + search_position_;+ iterator end = iterator::end(data_buffers);++ // Look for a match.+ std::pair<iterator, bool> result = match_condition_(start_pos, end);+ if (result.second)+ {+ // Full match. We're done.+ search_position_ = result.first - begin;+ bytes_to_read_ = 0;+ }++ // No match yet. Check if buffer is full.+ else if (buffers_.size() == buffers_.max_size())+ {+ search_position_ = not_found;+ bytes_to_read_ = 0;+ }++ // Need to read some more data.+ else+ {+ if (result.first != end)+ {+ // Partial match. Next search needs to start from beginning of+ // match.+ search_position_ = result.first - begin;+ }+ else+ {+ // Next search can start with the new data.+ search_position_ = end - begin;+ }++ bytes_to_read_ = std::min<std::size_t>(+ std::max<std::size_t>(512,+ buffers_.capacity() - buffers_.size()),+ std::min<std::size_t>(65536,+ buffers_.max_size() - buffers_.size()));+ }+ }++ // Check if we're done.+ if (!start && bytes_to_read_ == 0)+ break;++ // Start a new asynchronous read operation to obtain more data.+ pos = buffers_.size();+ buffers_.grow(bytes_to_read_);+ {+ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, "async_read_until"));+ stream_.async_read_some(buffers_.data(pos, bytes_to_read_),+ ASIO_MOVE_CAST(read_until_match_op_v2)(*this));+ }+ return; default:+ buffers_.shrink(bytes_to_read_ - bytes_transferred);+ if (ec || bytes_transferred == 0)+ break;+ }++ const asio::error_code result_ec =+ (search_position_ == not_found)+ ? error::not_found : ec;++ const std::size_t result_n =+ (ec || search_position_ == not_found)+ ? 0 : search_position_;++ handler_(result_ec, result_n);+ }+ }++ //private:+ AsyncReadStream& stream_;+ DynamicBuffer_v2 buffers_;+ MatchCondition match_condition_;+ int start_;+ std::size_t search_position_;+ std::size_t bytes_to_read_;+ ReadHandler handler_;+ };++ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename MatchCondition, typename ReadHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,+ MatchCondition, ReadHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename MatchCondition, typename ReadHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,+ MatchCondition, ReadHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename MatchCondition, typename ReadHandler>+ inline bool asio_handler_is_continuation(+ read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,+ MatchCondition, ReadHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v2, typename MatchCondition,+ typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,+ MatchCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncReadStream,+ typename DynamicBuffer_v2, typename MatchCondition,+ typename ReadHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2,+ MatchCondition, ReadHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncReadStream>+ class initiate_async_read_until_match_v2+ {+ public:+ typedef typename AsyncReadStream::executor_type executor_type;++ explicit initiate_async_read_until_match_v2(AsyncReadStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename ReadHandler,+ typename DynamicBuffer_v2, typename MatchCondition>+ void operator()(ASIO_MOVE_ARG(ReadHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,+ MatchCondition match_condition) 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;++ non_const_lvalue<ReadHandler> handler2(handler);+ read_until_match_op_v2<AsyncReadStream,+ typename decay<DynamicBuffer_v2>::type,+ MatchCondition, typename decay<ReadHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ match_condition, handler2.value)(asio::error_code(), 0, 1);+ }++ private:+ AsyncReadStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename MatchCondition, typename ReadHandler, typename Allocator>+struct associated_allocator<+ detail::read_until_match_op_v2<AsyncReadStream,+ DynamicBuffer_v2, MatchCondition, ReadHandler>,+ Allocator>+{+ typedef typename associated_allocator<ReadHandler, Allocator>::type type;++ static type get(+ const detail::read_until_match_op_v2<AsyncReadStream,+ DynamicBuffer_v2, MatchCondition, ReadHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncReadStream, typename DynamicBuffer_v2,+ typename MatchCondition, typename ReadHandler, typename Executor>+struct associated_executor<+ detail::read_until_match_op_v2<AsyncReadStream,+ DynamicBuffer_v2, MatchCondition, ReadHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<ReadHandler, Executor>+{+ typedef typename associated_executor<ReadHandler, Executor>::type type;++ static type get(+ const detail::read_until_match_op_v2<AsyncReadStream,+ DynamicBuffer_v2, MatchCondition, ReadHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename MatchCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,+ MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler,+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_read_until_match_v2<AsyncReadStream>(s), handler,+ ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), match_condition);+}++#endif // !defined(ASIO_NO_EXTENSIONS)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_READ_UNTIL_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/redirect_error.hpp view
@@ -0,0 +1,390 @@++// impl/redirect_error.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_REDIRECT_ERROR_HPP+#define ASIO_IMPL_REDIRECT_ERROR_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/associated_allocator.hpp"+#include "asio/async_result.hpp"+#include "asio/detail/handler_alloc_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/variadic_templates.hpp"+#include "asio/system_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++// Class to adapt a redirect_error_t as a completion handler.+template <typename Handler>+class redirect_error_handler+{+public:+ typedef void result_type;++ template <typename CompletionToken>+ redirect_error_handler(redirect_error_t<CompletionToken> e)+ : ec_(e.ec_),+ handler_(ASIO_MOVE_CAST(CompletionToken)(e.token_))+ {+ }++ template <typename RedirectedHandler>+ redirect_error_handler(asio::error_code& ec,+ ASIO_MOVE_ARG(RedirectedHandler) h)+ : ec_(ec),+ handler_(ASIO_MOVE_CAST(RedirectedHandler)(h))+ {+ }++ void operator()()+ {+ handler_();+ }++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Arg, typename... Args>+ typename enable_if<+ !is_same<typename decay<Arg>::type, asio::error_code>::value+ >::type+ operator()(ASIO_MOVE_ARG(Arg) arg, ASIO_MOVE_ARG(Args)... args)+ {+ handler_(ASIO_MOVE_CAST(Arg)(arg),+ ASIO_MOVE_CAST(Args)(args)...);+ }++ template <typename... Args>+ void operator()(const asio::error_code& ec,+ ASIO_MOVE_ARG(Args)... args)+ {+ ec_ = ec;+ handler_(ASIO_MOVE_CAST(Args)(args)...);+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Arg>+ typename enable_if<+ !is_same<typename decay<Arg>::type, asio::error_code>::value+ >::type+ operator()(ASIO_MOVE_ARG(Arg) arg)+ {+ handler_(ASIO_MOVE_CAST(Arg)(arg));+ }++ void operator()(const asio::error_code& ec)+ {+ ec_ = ec;+ handler_();+ }++#define ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \+ template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \+ typename enable_if< \+ !is_same<typename decay<Arg>::type, asio::error_code>::value \+ >::type \+ operator()(ASIO_MOVE_ARG(Arg) arg, ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ handler_(ASIO_MOVE_CAST(Arg)(arg), \+ ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ void operator()(const asio::error_code& ec, \+ ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ ec_ = ec; \+ handler_(ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_REDIRECT_ERROR_DEF)+#undef ASIO_PRIVATE_REDIRECT_ERROR_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++//private:+ asio::error_code& ec_;+ Handler handler_;+};++template <typename Handler>+inline asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size,+ redirect_error_handler<Handler>* this_handler)+{+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler>+inline asio_handler_deallocate_is_deprecated+asio_handler_deallocate(void* pointer, std::size_t size,+ redirect_error_handler<Handler>* this_handler)+{+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Handler>+inline bool asio_handler_is_continuation(+ redirect_error_handler<Handler>* this_handler)+{+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+}++template <typename Function, typename Handler>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(Function& function,+ redirect_error_handler<Handler>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Function, typename Handler>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(const Function& function,+ redirect_error_handler<Handler>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Signature>+struct redirect_error_signature+{+ typedef Signature type;+};++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename R, typename... Args>+struct redirect_error_signature<R(asio::error_code, Args...)>+{+ typedef R type(Args...);+};++template <typename R, typename... Args>+struct redirect_error_signature<R(const asio::error_code&, Args...)>+{+ typedef R type(Args...);+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename R>+struct redirect_error_signature<R(asio::error_code)>+{+ typedef R type();+};++template <typename R>+struct redirect_error_signature<R(const asio::error_code&)>+{+ typedef R type();+};++#define ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \+ template <typename R, ASIO_VARIADIC_TPARAMS(n)> \+ struct redirect_error_signature< \+ R(asio::error_code, ASIO_VARIADIC_TARGS(n))> \+ { \+ typedef R type(ASIO_VARIADIC_TARGS(n)); \+ }; \+ \+ template <typename R, ASIO_VARIADIC_TPARAMS(n)> \+ struct redirect_error_signature< \+ R(const asio::error_code&, ASIO_VARIADIC_TARGS(n))> \+ { \+ typedef R type(ASIO_VARIADIC_TARGS(n)); \+ }; \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_REDIRECT_ERROR_DEF)+#undef ASIO_PRIVATE_REDIRECT_ERROR_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename CompletionToken, typename Signature>+struct async_result<redirect_error_t<CompletionToken>, Signature>+{+ typedef typename async_result<CompletionToken,+ typename detail::redirect_error_signature<Signature>::type>+ ::return_type return_type;++ template <typename Initiation>+ struct init_wrapper+ {+ template <typename Init>+ init_wrapper(asio::error_code& ec, ASIO_MOVE_ARG(Init) init)+ : ec_(ec),+ initiation_(ASIO_MOVE_CAST(Init)(init))+ {+ }++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Handler, typename... Args>+ void operator()(+ ASIO_MOVE_ARG(Handler) handler,+ ASIO_MOVE_ARG(Args)... args)+ {+ ASIO_MOVE_CAST(Initiation)(initiation_)(+ detail::redirect_error_handler<+ typename decay<Handler>::type>(+ ec_, ASIO_MOVE_CAST(Handler)(handler)),+ ASIO_MOVE_CAST(Args)(args)...);+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Handler>+ void operator()(+ ASIO_MOVE_ARG(Handler) handler)+ {+ ASIO_MOVE_CAST(Initiation)(initiation_)(+ detail::redirect_error_handler<+ typename decay<Handler>::type>(+ ec_, ASIO_MOVE_CAST(Handler)(handler)));+ }++#define ASIO_PRIVATE_INIT_WRAPPER_DEF(n) \+ template <typename Handler, ASIO_VARIADIC_TPARAMS(n)> \+ void operator()( \+ ASIO_MOVE_ARG(Handler) handler, \+ ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ ASIO_MOVE_CAST(Initiation)(initiation_)( \+ detail::redirect_error_handler< \+ typename decay<Handler>::type>( \+ ec_, ASIO_MOVE_CAST(Handler)(handler)), \+ ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INIT_WRAPPER_DEF)+#undef ASIO_PRIVATE_INIT_WRAPPER_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ asio::error_code& ec_;+ Initiation initiation_;+ };++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Initiation, typename RawCompletionToken, typename... Args>+ static return_type initiate(+ ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_MOVE_ARG(RawCompletionToken) token,+ ASIO_MOVE_ARG(Args)... args)+ {+ return async_initiate<CompletionToken,+ typename detail::redirect_error_signature<Signature>::type>(+ init_wrapper<typename decay<Initiation>::type>(+ token.ec_, ASIO_MOVE_CAST(Initiation)(initiation)),+ token.token_, ASIO_MOVE_CAST(Args)(args)...);+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename Initiation, typename RawCompletionToken>+ static return_type initiate(+ ASIO_MOVE_ARG(Initiation) initiation,+ ASIO_MOVE_ARG(RawCompletionToken) token)+ {+ return async_initiate<CompletionToken,+ typename detail::redirect_error_signature<Signature>::type>(+ init_wrapper<typename decay<Initiation>::type>(+ token.ec_, ASIO_MOVE_CAST(Initiation)(initiation)),+ token.token_);+ }++#define ASIO_PRIVATE_INITIATE_DEF(n) \+ template <typename Initiation, typename RawCompletionToken, \+ ASIO_VARIADIC_TPARAMS(n)> \+ static return_type initiate( \+ ASIO_MOVE_ARG(Initiation) initiation, \+ ASIO_MOVE_ARG(RawCompletionToken) token, \+ ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ return async_initiate<CompletionToken, \+ typename detail::redirect_error_signature<Signature>::type>( \+ init_wrapper<typename decay<Initiation>::type>( \+ token.ec_, ASIO_MOVE_CAST(Initiation)(initiation)), \+ token.token_, ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)+#undef ASIO_PRIVATE_INITIATE_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+};++template <typename Handler, typename Executor>+struct associated_executor<detail::redirect_error_handler<Handler>, Executor>+{+ typedef typename associated_executor<Handler, Executor>::type type;++ static type get(+ const detail::redirect_error_handler<Handler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<Handler, Executor>::get(h.handler_, ex);+ }+};++template <typename Handler, typename Allocator>+struct associated_allocator<detail::redirect_error_handler<Handler>, Allocator>+{+ typedef typename associated_allocator<Handler, Allocator>::type type;++ static type get(+ const detail::redirect_error_handler<Handler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<Handler, Allocator>::get(h.handler_, a);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_REDIRECT_ERROR_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/serial_port_base.hpp view
@@ -0,0 +1,59 @@+//+// impl/serial_port_base.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_IMPL_SERIAL_PORT_BASE_HPP+#define ASIO_IMPL_SERIAL_PORT_BASE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/push_options.hpp"++namespace asio {++inline serial_port_base::baud_rate::baud_rate(unsigned int rate)+ : value_(rate)+{+}++inline unsigned int serial_port_base::baud_rate::value() const+{+ return value_;+}++inline serial_port_base::flow_control::type+serial_port_base::flow_control::value() const+{+ return value_;+}++inline serial_port_base::parity::type serial_port_base::parity::value() const+{+ return value_;+}++inline serial_port_base::stop_bits::type+serial_port_base::stop_bits::value() const+{+ return value_;+}++inline unsigned int serial_port_base::character_size::value() const+{+ return value_;+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_SERIAL_PORT_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/serial_port_base.ipp view
@@ -0,0 +1,554 @@+//+// impl/serial_port_base.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_IMPL_SERIAL_PORT_BASE_IPP+#define ASIO_IMPL_SERIAL_PORT_BASE_IPP++#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_SERIAL_PORT)++#include <stdexcept>+#include "asio/error.hpp"+#include "asio/serial_port_base.hpp"+#include "asio/detail/throw_exception.hpp"++#if defined(GENERATING_DOCUMENTATION)+# define ASIO_OPTION_STORAGE implementation_defined+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# define ASIO_OPTION_STORAGE DCB+#else+# define ASIO_OPTION_STORAGE termios+#endif++#include "asio/detail/push_options.hpp"++namespace asio {++ASIO_SYNC_OP_VOID serial_port_base::baud_rate::store(+ ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ storage.BaudRate = value_;+#else+ speed_t baud;+ switch (value_)+ {+ // Do POSIX-specified rates first.+ case 0: baud = B0; break;+ case 50: baud = B50; break;+ case 75: baud = B75; break;+ case 110: baud = B110; break;+ case 134: baud = B134; break;+ case 150: baud = B150; break;+ case 200: baud = B200; break;+ case 300: baud = B300; break;+ case 600: baud = B600; break;+ case 1200: baud = B1200; break;+ case 1800: baud = B1800; break;+ case 2400: baud = B2400; break;+ case 4800: baud = B4800; break;+ case 9600: baud = B9600; break;+ case 19200: baud = B19200; break;+ case 38400: baud = B38400; break;+ // And now the extended ones conditionally.+# ifdef B7200+ case 7200: baud = B7200; break;+# endif+# ifdef B14400+ case 14400: baud = B14400; break;+# endif+# ifdef B57600+ case 57600: baud = B57600; break;+# endif+# ifdef B115200+ case 115200: baud = B115200; break;+# endif+# ifdef B230400+ case 230400: baud = B230400; break;+# endif+# ifdef B460800+ case 460800: baud = B460800; break;+# endif+# ifdef B500000+ case 500000: baud = B500000; break;+# endif+# ifdef B576000+ case 576000: baud = B576000; break;+# endif+# ifdef B921600+ case 921600: baud = B921600; break;+# endif+# ifdef B1000000+ case 1000000: baud = B1000000; break;+# endif+# ifdef B1152000+ case 1152000: baud = B1152000; break;+# endif+# ifdef B2000000+ case 2000000: baud = B2000000; break;+# endif+# ifdef B3000000+ case 3000000: baud = B3000000; break;+# endif+# ifdef B3500000+ case 3500000: baud = B3500000; break;+# endif+# ifdef B4000000+ case 4000000: baud = B4000000; break;+# endif+ default:+ ec = asio::error::invalid_argument;+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)+ ::cfsetspeed(&storage, baud);+# else+ ::cfsetispeed(&storage, baud);+ ::cfsetospeed(&storage, baud);+# endif+#endif+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++ASIO_SYNC_OP_VOID serial_port_base::baud_rate::load(+ const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ value_ = storage.BaudRate;+#else+ speed_t baud = ::cfgetospeed(&storage);+ switch (baud)+ {+ // First do those specified by POSIX.+ case B0: value_ = 0; break;+ case B50: value_ = 50; break;+ case B75: value_ = 75; break;+ case B110: value_ = 110; break;+ case B134: value_ = 134; break;+ case B150: value_ = 150; break;+ case B200: value_ = 200; break;+ case B300: value_ = 300; break;+ case B600: value_ = 600; break;+ case B1200: value_ = 1200; break;+ case B1800: value_ = 1800; break;+ case B2400: value_ = 2400; break;+ case B4800: value_ = 4800; break;+ case B9600: value_ = 9600; break;+ case B19200: value_ = 19200; break;+ case B38400: value_ = 38400; break;+ // Now conditionally handle a bunch of extended rates.+# ifdef B7200+ case B7200: value_ = 7200; break;+# endif+# ifdef B14400+ case B14400: value_ = 14400; break;+# endif+# ifdef B57600+ case B57600: value_ = 57600; break;+# endif+# ifdef B115200+ case B115200: value_ = 115200; break;+# endif+# ifdef B230400+ case B230400: value_ = 230400; break;+# endif+# ifdef B460800+ case B460800: value_ = 460800; break;+# endif+# ifdef B500000+ case B500000: value_ = 500000; break;+# endif+# ifdef B576000+ case B576000: value_ = 576000; break;+# endif+# ifdef B921600+ case B921600: value_ = 921600; break;+# endif+# ifdef B1000000+ case B1000000: value_ = 1000000; break;+# endif+# ifdef B1152000+ case B1152000: value_ = 1152000; break;+# endif+# ifdef B2000000+ case B2000000: value_ = 2000000; break;+# endif+# ifdef B3000000+ case B3000000: value_ = 3000000; break;+# endif+# ifdef B3500000+ case B3500000: value_ = 3500000; break;+# endif+# ifdef B4000000+ case B4000000: value_ = 4000000; break;+# endif+ default:+ value_ = 0;+ ec = asio::error::invalid_argument;+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+#endif+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++serial_port_base::flow_control::flow_control(+ serial_port_base::flow_control::type t)+ : value_(t)+{+ if (t != none && t != software && t != hardware)+ {+ std::out_of_range ex("invalid flow_control value");+ asio::detail::throw_exception(ex);+ }+}++ASIO_SYNC_OP_VOID serial_port_base::flow_control::store(+ ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ storage.fOutxCtsFlow = FALSE;+ storage.fOutxDsrFlow = FALSE;+ storage.fTXContinueOnXoff = TRUE;+ storage.fDtrControl = DTR_CONTROL_ENABLE;+ storage.fDsrSensitivity = FALSE;+ storage.fOutX = FALSE;+ storage.fInX = FALSE;+ storage.fRtsControl = RTS_CONTROL_ENABLE;+ switch (value_)+ {+ case none:+ break;+ case software:+ storage.fOutX = TRUE;+ storage.fInX = TRUE;+ break;+ case hardware:+ storage.fOutxCtsFlow = TRUE;+ storage.fRtsControl = RTS_CONTROL_HANDSHAKE;+ break;+ default:+ break;+ }+#else+ switch (value_)+ {+ case none:+ storage.c_iflag &= ~(IXOFF | IXON);+# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)+ storage.c_cflag &= ~CRTSCTS;+# elif defined(__QNXNTO__)+ storage.c_cflag &= ~(IHFLOW | OHFLOW);+# endif+ break;+ case software:+ storage.c_iflag |= IXOFF | IXON;+# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)+ storage.c_cflag &= ~CRTSCTS;+# elif defined(__QNXNTO__)+ storage.c_cflag &= ~(IHFLOW | OHFLOW);+# endif+ break;+ case hardware:+# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)+ storage.c_iflag &= ~(IXOFF | IXON);+ storage.c_cflag |= CRTSCTS;+ break;+# elif defined(__QNXNTO__)+ storage.c_iflag &= ~(IXOFF | IXON);+ storage.c_cflag |= (IHFLOW | OHFLOW);+ break;+# else+ ec = asio::error::operation_not_supported;+ ASIO_SYNC_OP_VOID_RETURN(ec);+# endif+ default:+ break;+ }+#endif+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++ASIO_SYNC_OP_VOID serial_port_base::flow_control::load(+ const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ if (storage.fOutX && storage.fInX)+ {+ value_ = software;+ }+ else if (storage.fOutxCtsFlow && storage.fRtsControl == RTS_CONTROL_HANDSHAKE)+ {+ value_ = hardware;+ }+ else+ {+ value_ = none;+ }+#else+ if (storage.c_iflag & (IXOFF | IXON))+ {+ value_ = software;+ }+# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)+ else if (storage.c_cflag & CRTSCTS)+ {+ value_ = hardware;+ }+# elif defined(__QNXNTO__)+ else if (storage.c_cflag & IHFLOW && storage.c_cflag & OHFLOW)+ {+ value_ = hardware;+ }+# endif+ else+ {+ value_ = none;+ }+#endif+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++serial_port_base::parity::parity(serial_port_base::parity::type t)+ : value_(t)+{+ if (t != none && t != odd && t != even)+ {+ std::out_of_range ex("invalid parity value");+ asio::detail::throw_exception(ex);+ }+}++ASIO_SYNC_OP_VOID serial_port_base::parity::store(+ ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ switch (value_)+ {+ case none:+ storage.fParity = FALSE;+ storage.Parity = NOPARITY;+ break;+ case odd:+ storage.fParity = TRUE;+ storage.Parity = ODDPARITY;+ break;+ case even:+ storage.fParity = TRUE;+ storage.Parity = EVENPARITY;+ break;+ default:+ break;+ }+#else+ switch (value_)+ {+ case none:+ storage.c_iflag |= IGNPAR;+ storage.c_cflag &= ~(PARENB | PARODD);+ break;+ case even:+ storage.c_iflag &= ~(IGNPAR | PARMRK);+ storage.c_iflag |= INPCK;+ storage.c_cflag |= PARENB;+ storage.c_cflag &= ~PARODD;+ break;+ case odd:+ storage.c_iflag &= ~(IGNPAR | PARMRK);+ storage.c_iflag |= INPCK;+ storage.c_cflag |= (PARENB | PARODD);+ break;+ default:+ break;+ }+#endif+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++ASIO_SYNC_OP_VOID serial_port_base::parity::load(+ const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ if (storage.Parity == EVENPARITY)+ {+ value_ = even;+ }+ else if (storage.Parity == ODDPARITY)+ {+ value_ = odd;+ }+ else+ {+ value_ = none;+ }+#else+ if (storage.c_cflag & PARENB)+ {+ if (storage.c_cflag & PARODD)+ {+ value_ = odd;+ }+ else+ {+ value_ = even;+ }+ }+ else+ {+ value_ = none;+ }+#endif+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++serial_port_base::stop_bits::stop_bits(+ serial_port_base::stop_bits::type t)+ : value_(t)+{+ if (t != one && t != onepointfive && t != two)+ {+ std::out_of_range ex("invalid stop_bits value");+ asio::detail::throw_exception(ex);+ }+}++ASIO_SYNC_OP_VOID serial_port_base::stop_bits::store(+ ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ switch (value_)+ {+ case one:+ storage.StopBits = ONESTOPBIT;+ break;+ case onepointfive:+ storage.StopBits = ONE5STOPBITS;+ break;+ case two:+ storage.StopBits = TWOSTOPBITS;+ break;+ default:+ break;+ }+#else+ switch (value_)+ {+ case one:+ storage.c_cflag &= ~CSTOPB;+ break;+ case two:+ storage.c_cflag |= CSTOPB;+ break;+ default:+ ec = asio::error::operation_not_supported;+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+#endif+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++ASIO_SYNC_OP_VOID serial_port_base::stop_bits::load(+ const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ if (storage.StopBits == ONESTOPBIT)+ {+ value_ = one;+ }+ else if (storage.StopBits == ONE5STOPBITS)+ {+ value_ = onepointfive;+ }+ else if (storage.StopBits == TWOSTOPBITS)+ {+ value_ = two;+ }+ else+ {+ value_ = one;+ }+#else+ value_ = (storage.c_cflag & CSTOPB) ? two : one;+#endif+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++serial_port_base::character_size::character_size(unsigned int t)+ : value_(t)+{+ if (t < 5 || t > 8)+ {+ std::out_of_range ex("invalid character_size value");+ asio::detail::throw_exception(ex);+ }+}++ASIO_SYNC_OP_VOID serial_port_base::character_size::store(+ ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ storage.ByteSize = value_;+#else+ storage.c_cflag &= ~CSIZE;+ switch (value_)+ {+ case 5: storage.c_cflag |= CS5; break;+ case 6: storage.c_cflag |= CS6; break;+ case 7: storage.c_cflag |= CS7; break;+ case 8: storage.c_cflag |= CS8; break;+ default: break;+ }+#endif+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++ASIO_SYNC_OP_VOID serial_port_base::character_size::load(+ const ASIO_OPTION_STORAGE& storage, asio::error_code& ec)+{+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ value_ = storage.ByteSize;+#else+ if ((storage.c_cflag & CSIZE) == CS5) { value_ = 5; }+ else if ((storage.c_cflag & CSIZE) == CS6) { value_ = 6; }+ else if ((storage.c_cflag & CSIZE) == CS7) { value_ = 7; }+ else if ((storage.c_cflag & CSIZE) == CS8) { value_ = 8; }+ else+ {+ // Hmmm, use 8 for now.+ value_ = 8;+ }+#endif+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#undef ASIO_OPTION_STORAGE++#endif // defined(ASIO_HAS_SERIAL_PORT)++#endif // ASIO_IMPL_SERIAL_PORT_BASE_IPP
+ link/modules/asio-standalone/asio/include/asio/impl/spawn.hpp view
@@ -0,0 +1,526 @@+//+// impl/spawn.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SPAWN_HPP+#define ASIO_IMPL_SPAWN_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_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/async_result.hpp"+#include "asio/bind_executor.hpp"+#include "asio/detail/atomic_count.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_cont_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/system_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++ template <typename Handler, typename T>+ class coro_handler+ {+ public:+ coro_handler(basic_yield_context<Handler> ctx)+ : coro_(ctx.coro_.lock()),+ ca_(ctx.ca_),+ handler_(ctx.handler_),+ ready_(0),+ ec_(ctx.ec_),+ value_(0)+ {+ }++ void operator()(T value)+ {+ *ec_ = asio::error_code();+ *value_ = ASIO_MOVE_CAST(T)(value);+ if (--*ready_ == 0)+ (*coro_)();+ }++ void operator()(asio::error_code ec, T value)+ {+ *ec_ = ec;+ *value_ = ASIO_MOVE_CAST(T)(value);+ if (--*ready_ == 0)+ (*coro_)();+ }++ //private:+ shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;+ typename basic_yield_context<Handler>::caller_type& ca_;+ Handler handler_;+ atomic_count* ready_;+ asio::error_code* ec_;+ T* value_;+ };++ template <typename Handler>+ class coro_handler<Handler, void>+ {+ public:+ coro_handler(basic_yield_context<Handler> ctx)+ : coro_(ctx.coro_.lock()),+ ca_(ctx.ca_),+ handler_(ctx.handler_),+ ready_(0),+ ec_(ctx.ec_)+ {+ }++ void operator()()+ {+ *ec_ = asio::error_code();+ if (--*ready_ == 0)+ (*coro_)();+ }++ void operator()(asio::error_code ec)+ {+ *ec_ = ec;+ if (--*ready_ == 0)+ (*coro_)();+ }++ //private:+ shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;+ typename basic_yield_context<Handler>::caller_type& ca_;+ Handler handler_;+ atomic_count* ready_;+ asio::error_code* ec_;+ };++ template <typename Handler, typename T>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ coro_handler<Handler, T>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Handler, typename T>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ coro_handler<Handler, T>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Handler, typename T>+ inline bool asio_handler_is_continuation(coro_handler<Handler, T>*)+ {+ return true;+ }++ template <typename Function, typename Handler, typename T>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ coro_handler<Handler, T>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename Handler, typename T>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ coro_handler<Handler, T>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Handler, typename T>+ class coro_async_result+ {+ public:+ typedef coro_handler<Handler, T> completion_handler_type;+ typedef T return_type;++ explicit coro_async_result(completion_handler_type& h)+ : handler_(h),+ ca_(h.ca_),+ ready_(2)+ {+ h.ready_ = &ready_;+ out_ec_ = h.ec_;+ if (!out_ec_) h.ec_ = &ec_;+ h.value_ = &value_;+ }++ return_type get()+ {+ // Must not hold shared_ptr to coro while suspended.+ handler_.coro_.reset();++ if (--ready_ != 0)+ ca_();+ if (!out_ec_ && ec_) throw asio::system_error(ec_);+ return ASIO_MOVE_CAST(return_type)(value_);+ }++ private:+ completion_handler_type& handler_;+ typename basic_yield_context<Handler>::caller_type& ca_;+ atomic_count ready_;+ asio::error_code* out_ec_;+ asio::error_code ec_;+ return_type value_;+ };++ template <typename Handler>+ class coro_async_result<Handler, void>+ {+ public:+ typedef coro_handler<Handler, void> completion_handler_type;+ typedef void return_type;++ explicit coro_async_result(completion_handler_type& h)+ : handler_(h),+ ca_(h.ca_),+ ready_(2)+ {+ h.ready_ = &ready_;+ out_ec_ = h.ec_;+ if (!out_ec_) h.ec_ = &ec_;+ }++ void get()+ {+ // Must not hold shared_ptr to coro while suspended.+ handler_.coro_.reset();++ if (--ready_ != 0)+ ca_();+ if (!out_ec_ && ec_) throw asio::system_error(ec_);+ }++ private:+ completion_handler_type& handler_;+ typename basic_yield_context<Handler>::caller_type& ca_;+ atomic_count ready_;+ asio::error_code* out_ec_;+ asio::error_code ec_;+ };++} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename Handler, typename ReturnType>+class async_result<basic_yield_context<Handler>, ReturnType()>+ : public detail::coro_async_result<Handler, void>+{+public:+ explicit async_result(+ typename detail::coro_async_result<Handler,+ void>::completion_handler_type& h)+ : detail::coro_async_result<Handler, void>(h)+ {+ }+};++template <typename Handler, typename ReturnType, typename Arg1>+class async_result<basic_yield_context<Handler>, ReturnType(Arg1)>+ : public detail::coro_async_result<Handler, typename decay<Arg1>::type>+{+public:+ explicit async_result(+ typename detail::coro_async_result<Handler,+ typename decay<Arg1>::type>::completion_handler_type& h)+ : detail::coro_async_result<Handler, typename decay<Arg1>::type>(h)+ {+ }+};++template <typename Handler, typename ReturnType>+class async_result<basic_yield_context<Handler>,+ ReturnType(asio::error_code)>+ : public detail::coro_async_result<Handler, void>+{+public:+ explicit async_result(+ typename detail::coro_async_result<Handler,+ void>::completion_handler_type& h)+ : detail::coro_async_result<Handler, void>(h)+ {+ }+};++template <typename Handler, typename ReturnType, typename Arg2>+class async_result<basic_yield_context<Handler>,+ ReturnType(asio::error_code, Arg2)>+ : public detail::coro_async_result<Handler, typename decay<Arg2>::type>+{+public:+ explicit async_result(+ typename detail::coro_async_result<Handler,+ typename decay<Arg2>::type>::completion_handler_type& h)+ : detail::coro_async_result<Handler, typename decay<Arg2>::type>(h)+ {+ }+};++template <typename Handler, typename T, typename Allocator>+struct associated_allocator<detail::coro_handler<Handler, T>, Allocator>+{+ typedef typename associated_allocator<Handler, Allocator>::type type;++ static type get(const detail::coro_handler<Handler, T>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<Handler, Allocator>::get(h.handler_, a);+ }+};++template <typename Handler, typename T, typename Executor>+struct associated_executor<detail::coro_handler<Handler, T>, Executor>+{+ typedef typename associated_executor<Handler, Executor>::type type;++ static type get(const detail::coro_handler<Handler, T>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<Handler, Executor>::get(h.handler_, ex);+ }+};++namespace detail {++ template <typename Handler, typename Function>+ struct spawn_data : private noncopyable+ {+ template <typename Hand, typename Func>+ spawn_data(ASIO_MOVE_ARG(Hand) handler,+ bool call_handler, ASIO_MOVE_ARG(Func) function)+ : handler_(ASIO_MOVE_CAST(Hand)(handler)),+ call_handler_(call_handler),+ function_(ASIO_MOVE_CAST(Func)(function))+ {+ }++ weak_ptr<typename basic_yield_context<Handler>::callee_type> coro_;+ Handler handler_;+ bool call_handler_;+ Function function_;+ };++ template <typename Handler, typename Function>+ struct coro_entry_point+ {+ void operator()(typename basic_yield_context<Handler>::caller_type& ca)+ {+ shared_ptr<spawn_data<Handler, Function> > data(data_);+#if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)+ ca(); // Yield until coroutine pointer has been initialised.+#endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)+ const basic_yield_context<Handler> yield(+ data->coro_, ca, data->handler_);++ (data->function_)(yield);+ if (data->call_handler_)+ (data->handler_)();+ }++ shared_ptr<spawn_data<Handler, Function> > data_;+ };++ template <typename Handler, typename Function>+ struct spawn_helper+ {+ typedef typename associated_allocator<Handler>::type allocator_type;++ allocator_type get_allocator() const ASIO_NOEXCEPT+ {+ return (get_associated_allocator)(data_->handler_);+ }++ typedef typename associated_executor<Handler>::type executor_type;++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return (get_associated_executor)(data_->handler_);+ }++ void operator()()+ {+ typedef typename basic_yield_context<Handler>::callee_type callee_type;+ coro_entry_point<Handler, Function> entry_point = { data_ };+ shared_ptr<callee_type> coro(new callee_type(entry_point, attributes_));+ data_->coro_ = coro;+ (*coro)();+ }++ shared_ptr<spawn_data<Handler, Function> > data_;+ boost::coroutines::attributes attributes_;+ };++ template <typename Function, typename Handler, typename Function1>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ spawn_helper<Handler, Function1>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->data_->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename Handler, typename Function1>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ spawn_helper<Handler, Function1>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->data_->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ inline void default_spawn_handler() {}++} // namespace detail++template <typename Function>+inline void spawn(ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes)+{+ typedef typename decay<Function>::type function_type;++ typename associated_executor<function_type>::type ex(+ (get_associated_executor)(function));++ asio::spawn(ex, ASIO_MOVE_CAST(Function)(function), attributes);+}++template <typename Handler, typename Function>+void spawn(ASIO_MOVE_ARG(Handler) handler,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes,+ typename enable_if<+ !is_executor<typename decay<Handler>::type>::value &&+ !execution::is_executor<typename decay<Handler>::type>::value &&+ !is_convertible<Handler&, execution_context&>::value>::type*)+{+ typedef typename decay<Handler>::type handler_type;+ typedef typename decay<Function>::type function_type;++ detail::spawn_helper<handler_type, function_type> helper;+ helper.data_.reset(+ new detail::spawn_data<handler_type, function_type>(+ ASIO_MOVE_CAST(Handler)(handler), true,+ ASIO_MOVE_CAST(Function)(function)));+ helper.attributes_ = attributes;++ asio::dispatch(helper);+}++template <typename Handler, typename Function>+void spawn(basic_yield_context<Handler> ctx,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes)+{+ typedef typename decay<Function>::type function_type;++ Handler handler(ctx.handler_); // Explicit copy that might be moved from.++ detail::spawn_helper<Handler, function_type> helper;+ helper.data_.reset(+ new detail::spawn_data<Handler, function_type>(+ ASIO_MOVE_CAST(Handler)(handler), false,+ ASIO_MOVE_CAST(Function)(function)));+ helper.attributes_ = attributes;++ asio::dispatch(helper);+}++template <typename Function, typename Executor>+inline void spawn(const Executor& ex,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes,+ typename enable_if<+ is_executor<Executor>::value || execution::is_executor<Executor>::value+ >::type*)+{+ asio::spawn(asio::strand<Executor>(ex),+ ASIO_MOVE_CAST(Function)(function), attributes);+}++template <typename Function, typename Executor>+inline void spawn(const strand<Executor>& ex,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes)+{+ asio::spawn(asio::bind_executor(+ ex, &detail::default_spawn_handler),+ ASIO_MOVE_CAST(Function)(function), attributes);+}++#if !defined(ASIO_NO_TS_EXECUTORS)++template <typename Function>+inline void spawn(const asio::io_context::strand& s,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes)+{+ asio::spawn(asio::bind_executor(+ s, &detail::default_spawn_handler),+ ASIO_MOVE_CAST(Function)(function), attributes);+}++#endif // !defined(ASIO_NO_TS_EXECUTORS)++template <typename Function, typename ExecutionContext>+inline void spawn(ExecutionContext& ctx,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes,+ typename enable_if<is_convertible<+ ExecutionContext&, execution_context&>::value>::type*)+{+ asio::spawn(ctx.get_executor(),+ ASIO_MOVE_CAST(Function)(function), attributes);+}++#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_SPAWN_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/src.hpp view
@@ -0,0 +1,85 @@+//+// impl/src.hpp+// ~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SRC_HPP+#define ASIO_IMPL_SRC_HPP++#define ASIO_SOURCE++#include "asio/detail/config.hpp"++#if defined(ASIO_HEADER_ONLY)+# error Do not compile Asio library source with ASIO_HEADER_ONLY defined+#endif++#include "asio/impl/error.ipp"+#include "asio/impl/error_code.ipp"+#include "asio/impl/execution_context.ipp"+#include "asio/impl/executor.ipp"+#include "asio/impl/handler_alloc_hook.ipp"+#include "asio/impl/io_context.ipp"+#include "asio/impl/multiple_exceptions.ipp"+#include "asio/impl/serial_port_base.ipp"+#include "asio/impl/system_context.ipp"+#include "asio/impl/thread_pool.ipp"+#include "asio/detail/impl/buffer_sequence_adapter.ipp"+#include "asio/detail/impl/descriptor_ops.ipp"+#include "asio/detail/impl/dev_poll_reactor.ipp"+#include "asio/detail/impl/epoll_reactor.ipp"+#include "asio/detail/impl/eventfd_select_interrupter.ipp"+#include "asio/detail/impl/handler_tracking.ipp"+#include "asio/detail/impl/kqueue_reactor.ipp"+#include "asio/detail/impl/null_event.ipp"+#include "asio/detail/impl/pipe_select_interrupter.ipp"+#include "asio/detail/impl/posix_event.ipp"+#include "asio/detail/impl/posix_mutex.ipp"+#include "asio/detail/impl/posix_thread.ipp"+#include "asio/detail/impl/posix_tss_ptr.ipp"+#include "asio/detail/impl/reactive_descriptor_service.ipp"+#include "asio/detail/impl/reactive_serial_port_service.ipp"+#include "asio/detail/impl/reactive_socket_service_base.ipp"+#include "asio/detail/impl/resolver_service_base.ipp"+#include "asio/detail/impl/scheduler.ipp"+#include "asio/detail/impl/select_reactor.ipp"+#include "asio/detail/impl/service_registry.ipp"+#include "asio/detail/impl/signal_set_service.ipp"+#include "asio/detail/impl/socket_ops.ipp"+#include "asio/detail/impl/socket_select_interrupter.ipp"+#include "asio/detail/impl/strand_executor_service.ipp"+#include "asio/detail/impl/strand_service.ipp"+#include "asio/detail/impl/throw_error.ipp"+#include "asio/detail/impl/timer_queue_ptime.ipp"+#include "asio/detail/impl/timer_queue_set.ipp"+#include "asio/detail/impl/win_iocp_handle_service.ipp"+#include "asio/detail/impl/win_iocp_io_context.ipp"+#include "asio/detail/impl/win_iocp_serial_port_service.ipp"+#include "asio/detail/impl/win_iocp_socket_service_base.ipp"+#include "asio/detail/impl/win_event.ipp"+#include "asio/detail/impl/win_mutex.ipp"+#include "asio/detail/impl/win_object_handle_service.ipp"+#include "asio/detail/impl/win_static_mutex.ipp"+#include "asio/detail/impl/win_thread.ipp"+#include "asio/detail/impl/win_tss_ptr.ipp"+#include "asio/detail/impl/winrt_ssocket_service_base.ipp"+#include "asio/detail/impl/winrt_timer_scheduler.ipp"+#include "asio/detail/impl/winsock_init.ipp"+#include "asio/execution/impl/bad_executor.ipp"+#include "asio/execution/impl/receiver_invocation_error.ipp"+#include "asio/generic/detail/impl/endpoint.ipp"+#include "asio/ip/impl/address.ipp"+#include "asio/ip/impl/address_v4.ipp"+#include "asio/ip/impl/address_v6.ipp"+#include "asio/ip/impl/host_name.ipp"+#include "asio/ip/impl/network_v4.ipp"+#include "asio/ip/impl/network_v6.ipp"+#include "asio/ip/detail/impl/endpoint.ipp"+#include "asio/local/detail/impl/endpoint.ipp"++#endif // ASIO_IMPL_SRC_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/system_context.hpp view
@@ -0,0 +1,34 @@+//+// impl/system_context.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SYSTEM_CONTEXT_HPP+#define ASIO_IMPL_SYSTEM_CONTEXT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/system_executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++inline system_context::executor_type+system_context::get_executor() ASIO_NOEXCEPT+{+ return system_executor();+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_SYSTEM_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/system_context.ipp view
@@ -0,0 +1,92 @@+//+// impl/system_context.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SYSTEM_CONTEXT_IPP+#define ASIO_IMPL_SYSTEM_CONTEXT_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/system_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++struct system_context::thread_function+{+ detail::scheduler* scheduler_;++ void operator()()+ {+#if !defined(ASIO_NO_EXCEPTIONS)+ try+ {+#endif// !defined(ASIO_NO_EXCEPTIONS)+ asio::error_code ec;+ scheduler_->run(ec);+#if !defined(ASIO_NO_EXCEPTIONS)+ }+ catch (...)+ {+ std::terminate();+ }+#endif// !defined(ASIO_NO_EXCEPTIONS)+ }+};++system_context::system_context()+ : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false)))+{+ scheduler_.work_started();++ thread_function f = { &scheduler_ };+ num_threads_ = detail::thread::hardware_concurrency() * 2;+ num_threads_ = num_threads_ ? num_threads_ : 2;+ threads_.create_threads(f, num_threads_);+}++system_context::~system_context()+{+ scheduler_.work_finished();+ scheduler_.stop();+ threads_.join();+}++void system_context::stop()+{+ scheduler_.stop();+}++bool system_context::stopped() const ASIO_NOEXCEPT+{+ return scheduler_.stopped();+}++void system_context::join()+{+ scheduler_.work_finished();+ threads_.join();+}++detail::scheduler& system_context::add_scheduler(detail::scheduler* s)+{+ detail::scoped_ptr<detail::scheduler> scoped_impl(s);+ asio::add_service<detail::scheduler>(*this, scoped_impl.get());+ return *scoped_impl.release();+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_SYSTEM_CONTEXT_IPP
+ link/modules/asio-standalone/asio/include/asio/impl/system_executor.hpp view
@@ -0,0 +1,186 @@+//+// impl/system_executor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_SYSTEM_EXECUTOR_HPP+#define ASIO_IMPL_SYSTEM_EXECUTOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/executor_op.hpp"+#include "asio/detail/global.hpp"+#include "asio/detail/recycling_allocator.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/system_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++template <typename Blocking, typename Relationship, typename Allocator>+inline system_context&+basic_system_executor<Blocking, Relationship, Allocator>::query(+ execution::context_t) ASIO_NOEXCEPT+{+ return detail::global<system_context>();+}++template <typename Blocking, typename Relationship, typename Allocator>+inline std::size_t+basic_system_executor<Blocking, Relationship, Allocator>::query(+ execution::occupancy_t) const ASIO_NOEXCEPT+{+ return detail::global<system_context>().num_threads_;+}++template <typename Blocking, typename Relationship, typename Allocator>+template <typename Function>+inline void+basic_system_executor<Blocking, Relationship, Allocator>::do_execute(+ ASIO_MOVE_ARG(Function) f, execution::blocking_t::possibly_t) const+{+ // Obtain a non-const instance of the function.+ detail::non_const_lvalue<Function> f2(f);++#if !defined(ASIO_NO_EXCEPTIONS)+ try+ {+#endif// !defined(ASIO_NO_EXCEPTIONS)+ detail::fenced_block b(detail::fenced_block::full);+ asio_handler_invoke_helpers::invoke(f2.value, f2.value);+#if !defined(ASIO_NO_EXCEPTIONS)+ }+ catch (...)+ {+ std::terminate();+ }+#endif// !defined(ASIO_NO_EXCEPTIONS)+}++template <typename Blocking, typename Relationship, typename Allocator>+template <typename Function>+inline void+basic_system_executor<Blocking, Relationship, Allocator>::do_execute(+ ASIO_MOVE_ARG(Function) f, execution::blocking_t::always_t) const+{+ // Obtain a non-const instance of the function.+ detail::non_const_lvalue<Function> f2(f);++#if !defined(ASIO_NO_EXCEPTIONS)+ try+ {+#endif// !defined(ASIO_NO_EXCEPTIONS)+ detail::fenced_block b(detail::fenced_block::full);+ asio_handler_invoke_helpers::invoke(f2.value, f2.value);+#if !defined(ASIO_NO_EXCEPTIONS)+ }+ catch (...)+ {+ std::terminate();+ }+#endif// !defined(ASIO_NO_EXCEPTIONS)+}++template <typename Blocking, typename Relationship, typename Allocator>+template <typename Function>+void basic_system_executor<Blocking, Relationship, Allocator>::do_execute(+ ASIO_MOVE_ARG(Function) f, execution::blocking_t::never_t) const+{+ system_context& ctx = detail::global<system_context>();++ // Allocate and construct an operation to wrap the function.+ typedef typename decay<Function>::type function_type;+ typedef detail::executor_op<function_type, Allocator> op;+ typename op::ptr p = { detail::addressof(allocator_),+ op::ptr::allocate(allocator_), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), allocator_);++ if (is_same<Relationship, execution::relationship_t::continuation_t>::value)+ {+ ASIO_HANDLER_CREATION((ctx, *p.p,+ "system_executor", &ctx, 0, "execute(blk=never,rel=cont)"));+ }+ else+ {+ ASIO_HANDLER_CREATION((ctx, *p.p,+ "system_executor", &ctx, 0, "execute(blk=never,rel=fork)"));+ }++ ctx.scheduler_.post_immediate_completion(p.p,+ is_same<Relationship, execution::relationship_t::continuation_t>::value);+ p.v = p.p = 0;+}++#if !defined(ASIO_NO_TS_EXECUTORS)+template <typename Blocking, typename Relationship, typename Allocator>+inline system_context& basic_system_executor<+ Blocking, Relationship, Allocator>::context() const ASIO_NOEXCEPT+{+ return detail::global<system_context>();+}++template <typename Blocking, typename Relationship, typename Allocator>+template <typename Function, typename OtherAllocator>+void basic_system_executor<Blocking, Relationship, Allocator>::dispatch(+ ASIO_MOVE_ARG(Function) f, const OtherAllocator&) const+{+ typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f));+ asio_handler_invoke_helpers::invoke(tmp, tmp);+}++template <typename Blocking, typename Relationship, typename Allocator>+template <typename Function, typename OtherAllocator>+void basic_system_executor<Blocking, Relationship, Allocator>::post(+ ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const+{+ typedef typename decay<Function>::type function_type;++ system_context& ctx = detail::global<system_context>();++ // Allocate and construct an operation to wrap the function.+ typedef detail::executor_op<function_type, OtherAllocator> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);++ ASIO_HANDLER_CREATION((ctx, *p.p,+ "system_executor", &this->context(), 0, "post"));++ ctx.scheduler_.post_immediate_completion(p.p, false);+ p.v = p.p = 0;+}++template <typename Blocking, typename Relationship, typename Allocator>+template <typename Function, typename OtherAllocator>+void basic_system_executor<Blocking, Relationship, Allocator>::defer(+ ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const+{+ typedef typename decay<Function>::type function_type;++ system_context& ctx = detail::global<system_context>();++ // Allocate and construct an operation to wrap the function.+ typedef detail::executor_op<function_type, OtherAllocator> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);++ ASIO_HANDLER_CREATION((ctx, *p.p,+ "system_executor", &this->context(), 0, "defer"));++ ctx.scheduler_.post_immediate_completion(p.p, true);+ p.v = p.p = 0;+}+#endif // !defined(ASIO_NO_TS_EXECUTORS)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_SYSTEM_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/thread_pool.hpp view
@@ -0,0 +1,350 @@+//+// impl/thread_pool.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_THREAD_POOL_HPP+#define ASIO_IMPL_THREAD_POOL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/blocking_executor_op.hpp"+#include "asio/detail/bulk_executor_op.hpp"+#include "asio/detail/executor_op.hpp"+#include "asio/detail/fenced_block.hpp"+#include "asio/detail/non_const_lvalue.hpp"+#include "asio/detail/recycling_allocator.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++inline thread_pool::executor_type+thread_pool::get_executor() ASIO_NOEXCEPT+{+ return executor_type(*this);+}++inline thread_pool::executor_type+thread_pool::executor() ASIO_NOEXCEPT+{+ return executor_type(*this);+}++inline thread_pool::scheduler_type+thread_pool::scheduler() ASIO_NOEXCEPT+{+ return scheduler_type(*this);+}++template <typename Allocator, unsigned int Bits>+thread_pool::basic_executor_type<Allocator, Bits>&+thread_pool::basic_executor_type<Allocator, Bits>::operator=(+ const basic_executor_type& other) ASIO_NOEXCEPT+{+ if (this != &other)+ {+ thread_pool* old_thread_pool = pool_;+ pool_ = other.pool_;+ allocator_ = other.allocator_;+ bits_ = other.bits_;+ if (Bits & outstanding_work_tracked)+ {+ if (pool_)+ pool_->scheduler_.work_started();+ if (old_thread_pool)+ old_thread_pool->scheduler_.work_finished();+ }+ }+ return *this;+}++#if defined(ASIO_HAS_MOVE)+template <typename Allocator, unsigned int Bits>+thread_pool::basic_executor_type<Allocator, Bits>&+thread_pool::basic_executor_type<Allocator, Bits>::operator=(+ basic_executor_type&& other) ASIO_NOEXCEPT+{+ if (this != &other)+ {+ pool_ = other.pool_;+ allocator_ = std::move(other.allocator_);+ bits_ = other.bits_;+ if (Bits & outstanding_work_tracked)+ other.pool_ = 0;+ }+ return *this;+}+#endif // defined(ASIO_HAS_MOVE)++template <typename Allocator, unsigned int Bits>+inline bool thread_pool::basic_executor_type<Allocator,+ Bits>::running_in_this_thread() const ASIO_NOEXCEPT+{+ return pool_->scheduler_.can_dispatch();+}++template <typename Allocator, unsigned int Bits>+template <typename Function>+void thread_pool::basic_executor_type<Allocator,+ Bits>::do_execute(ASIO_MOVE_ARG(Function) f, false_type) const+{+ typedef typename decay<Function>::type function_type;++ // Invoke immediately if the blocking.possibly property is enabled and we are+ // already inside the thread pool.+ if ((bits_ & blocking_never) == 0 && pool_->scheduler_.can_dispatch())+ {+ // Make a local, non-const copy of the function.+ function_type tmp(ASIO_MOVE_CAST(Function)(f));++#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \+ && !defined(ASIO_NO_EXCEPTIONS)+ try+ {+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ // && !defined(ASIO_NO_EXCEPTIONS)+ detail::fenced_block b(detail::fenced_block::full);+ asio_handler_invoke_helpers::invoke(tmp, tmp);+ return;+#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \+ && !defined(ASIO_NO_EXCEPTIONS)+ }+ catch (...)+ {+ pool_->scheduler_.capture_current_exception();+ return;+ }+#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ // && !defined(ASIO_NO_EXCEPTIONS)+ }++ // Allocate and construct an operation to wrap the function.+ typedef detail::executor_op<function_type, Allocator> op;+ typename op::ptr p = { detail::addressof(allocator_),+ op::ptr::allocate(allocator_), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), allocator_);++ if ((bits_ & relationship_continuation) != 0)+ {+ ASIO_HANDLER_CREATION((*pool_, *p.p,+ "thread_pool", pool_, 0, "execute(blk=never,rel=cont)"));+ }+ else+ {+ ASIO_HANDLER_CREATION((*pool_, *p.p,+ "thread_pool", pool_, 0, "execute(blk=never,rel=fork)"));+ }++ pool_->scheduler_.post_immediate_completion(p.p,+ (bits_ & relationship_continuation) != 0);+ p.v = p.p = 0;+}++template <typename Allocator, unsigned int Bits>+template <typename Function>+void thread_pool::basic_executor_type<Allocator,+ Bits>::do_execute(ASIO_MOVE_ARG(Function) f, true_type) const+{+ // Obtain a non-const instance of the function.+ detail::non_const_lvalue<Function> f2(f);++ // Invoke immediately if we are already inside the thread pool.+ if (pool_->scheduler_.can_dispatch())+ {+#if !defined(ASIO_NO_EXCEPTIONS)+ try+ {+#endif // !defined(ASIO_NO_EXCEPTIONS)+ detail::fenced_block b(detail::fenced_block::full);+ asio_handler_invoke_helpers::invoke(f2.value, f2.value);+ return;+#if !defined(ASIO_NO_EXCEPTIONS)+ }+ catch (...)+ {+ std::terminate();+ }+#endif // !defined(ASIO_NO_EXCEPTIONS)+ }++ // Construct an operation to wrap the function.+ typedef typename decay<Function>::type function_type;+ detail::blocking_executor_op<function_type> op(f2.value);++ ASIO_HANDLER_CREATION((*pool_, op,+ "thread_pool", pool_, 0, "execute(blk=always)"));++ pool_->scheduler_.post_immediate_completion(&op, false);+ op.wait();+}++template <typename Allocator, unsigned int Bits>+template <typename Function>+void thread_pool::basic_executor_type<Allocator, Bits>::do_bulk_execute(+ ASIO_MOVE_ARG(Function) f, std::size_t n, false_type) const+{+ typedef typename decay<Function>::type function_type;+ typedef detail::bulk_executor_op<function_type, Allocator> op;++ // Allocate and construct operations to wrap the function.+ detail::op_queue<detail::scheduler_operation> ops;+ for (std::size_t i = 0; i < n; ++i)+ {+ typename op::ptr p = { detail::addressof(allocator_),+ op::ptr::allocate(allocator_), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), allocator_, i);+ ops.push(p.p);++ if ((bits_ & relationship_continuation) != 0)+ {+ ASIO_HANDLER_CREATION((*pool_, *p.p,+ "thread_pool", pool_, 0, "bulk_execute(blk=never,rel=cont)"));+ }+ else+ {+ ASIO_HANDLER_CREATION((*pool_, *p.p,+ "thread_pool", pool_, 0, "bulk)execute(blk=never,rel=fork)"));+ }++ p.v = p.p = 0;+ }++ pool_->scheduler_.post_immediate_completions(n,+ ops, (bits_ & relationship_continuation) != 0);+}++template <typename Function>+struct thread_pool_always_blocking_function_adapter+{+ typename decay<Function>::type* f;+ std::size_t n;++ void operator()()+ {+ for (std::size_t i = 0; i < n; ++i)+ {+ (*f)(i);+ }+ }+};++template <typename Allocator, unsigned int Bits>+template <typename Function>+void thread_pool::basic_executor_type<Allocator, Bits>::do_bulk_execute(+ ASIO_MOVE_ARG(Function) f, std::size_t n, true_type) const+{+ // Obtain a non-const instance of the function.+ detail::non_const_lvalue<Function> f2(f);++ thread_pool_always_blocking_function_adapter<Function>+ adapter = { detail::addressof(f2.value), n };++ this->do_execute(adapter, true_type());+}++#if !defined(ASIO_NO_TS_EXECUTORS)+template <typename Allocator, unsigned int Bits>+inline thread_pool& thread_pool::basic_executor_type<+ Allocator, Bits>::context() const ASIO_NOEXCEPT+{+ return *pool_;+}++template <typename Allocator, unsigned int Bits>+inline void thread_pool::basic_executor_type<Allocator,+ Bits>::on_work_started() const ASIO_NOEXCEPT+{+ pool_->scheduler_.work_started();+}++template <typename Allocator, unsigned int Bits>+inline void thread_pool::basic_executor_type<Allocator,+ Bits>::on_work_finished() const ASIO_NOEXCEPT+{+ pool_->scheduler_.work_finished();+}++template <typename Allocator, unsigned int Bits>+template <typename Function, typename OtherAllocator>+void thread_pool::basic_executor_type<Allocator, Bits>::dispatch(+ ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const+{+ typedef typename decay<Function>::type function_type;++ // Invoke immediately if we are already inside the thread pool.+ if (pool_->scheduler_.can_dispatch())+ {+ // Make a local, non-const copy of the function.+ function_type tmp(ASIO_MOVE_CAST(Function)(f));++ detail::fenced_block b(detail::fenced_block::full);+ asio_handler_invoke_helpers::invoke(tmp, tmp);+ return;+ }++ // Allocate and construct an operation to wrap the function.+ typedef detail::executor_op<function_type, OtherAllocator> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);++ ASIO_HANDLER_CREATION((*pool_, *p.p,+ "thread_pool", pool_, 0, "dispatch"));++ pool_->scheduler_.post_immediate_completion(p.p, false);+ p.v = p.p = 0;+}++template <typename Allocator, unsigned int Bits>+template <typename Function, typename OtherAllocator>+void thread_pool::basic_executor_type<Allocator, Bits>::post(+ ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const+{+ typedef typename decay<Function>::type function_type;++ // Allocate and construct an operation to wrap the function.+ typedef detail::executor_op<function_type, OtherAllocator> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);++ ASIO_HANDLER_CREATION((*pool_, *p.p,+ "thread_pool", pool_, 0, "post"));++ pool_->scheduler_.post_immediate_completion(p.p, false);+ p.v = p.p = 0;+}++template <typename Allocator, unsigned int Bits>+template <typename Function, typename OtherAllocator>+void thread_pool::basic_executor_type<Allocator, Bits>::defer(+ ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const+{+ typedef typename decay<Function>::type function_type;++ // Allocate and construct an operation to wrap the function.+ typedef detail::executor_op<function_type, OtherAllocator> op;+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);++ ASIO_HANDLER_CREATION((*pool_, *p.p,+ "thread_pool", pool_, 0, "defer"));++ pool_->scheduler_.post_immediate_completion(p.p, true);+ p.v = p.p = 0;+}+#endif // !defined(ASIO_NO_TS_EXECUTORS)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_THREAD_POOL_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/thread_pool.ipp view
@@ -0,0 +1,141 @@+//+// impl/thread_pool.ipp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_THREAD_POOL_IPP+#define ASIO_IMPL_THREAD_POOL_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <stdexcept>+#include "asio/thread_pool.hpp"+#include "asio/detail/throw_exception.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++struct thread_pool::thread_function+{+ detail::scheduler* scheduler_;++ void operator()()+ {+#if !defined(ASIO_NO_EXCEPTIONS)+ try+ {+#endif// !defined(ASIO_NO_EXCEPTIONS)+ asio::error_code ec;+ scheduler_->run(ec);+#if !defined(ASIO_NO_EXCEPTIONS)+ }+ catch (...)+ {+ std::terminate();+ }+#endif// !defined(ASIO_NO_EXCEPTIONS)+ }+};++#if !defined(ASIO_NO_TS_EXECUTORS)+namespace detail {++inline long default_thread_pool_size()+{+ std::size_t num_threads = thread::hardware_concurrency() * 2;+ num_threads = num_threads == 0 ? 2 : num_threads;+ return static_cast<long>(num_threads);+}++} // namespace detail++thread_pool::thread_pool()+ : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))),+ num_threads_(detail::default_thread_pool_size())+{+ scheduler_.work_started();++ thread_function f = { &scheduler_ };+ threads_.create_threads(f, static_cast<std::size_t>(num_threads_));+}+#endif // !defined(ASIO_NO_TS_EXECUTORS)++namespace detail {++inline long clamp_thread_pool_size(std::size_t n)+{+ if (n > 0x7FFFFFFF)+ {+ std::out_of_range ex("thread pool size");+ asio::detail::throw_exception(ex);+ }+ return static_cast<long>(n & 0x7FFFFFFF);+}++} // namespace detail++thread_pool::thread_pool(std::size_t num_threads)+ : scheduler_(add_scheduler(new detail::scheduler(+ *this, num_threads == 1 ? 1 : 0, false))),+ num_threads_(detail::clamp_thread_pool_size(num_threads))+{+ scheduler_.work_started();++ thread_function f = { &scheduler_ };+ threads_.create_threads(f, static_cast<std::size_t>(num_threads_));+}++thread_pool::~thread_pool()+{+ stop();+ join();+}++void thread_pool::stop()+{+ scheduler_.stop();+}++void thread_pool::attach()+{+ ++num_threads_;+ thread_function f = { &scheduler_ };+ f();+}++void thread_pool::join()+{+ if (!threads_.empty())+ {+ scheduler_.work_finished();+ threads_.join();+ }+}++detail::scheduler& thread_pool::add_scheduler(detail::scheduler* s)+{+ detail::scoped_ptr<detail::scheduler> scoped_impl(s);+ asio::add_service<detail::scheduler>(*this, scoped_impl.get());+ return *scoped_impl.release();+}++void thread_pool::wait()+{+ scheduler_.work_finished();+ threads_.join();+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_THREAD_POOL_IPP
+ link/modules/asio-standalone/asio/include/asio/impl/use_awaitable.hpp view
@@ -0,0 +1,279 @@+//+// impl/use_awaitable.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_USE_AWAITABLE_HPP+#define ASIO_IMPL_USE_AWAITABLE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/async_result.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Executor, typename T>+class awaitable_handler_base+ : public awaitable_thread<Executor>+{+public:+ typedef void result_type;+ typedef awaitable<T, Executor> awaitable_type;++ // Construct from the entry point of a new thread of execution.+ awaitable_handler_base(awaitable<void, Executor> a, const Executor& ex)+ : awaitable_thread<Executor>(std::move(a), ex)+ {+ }++ // Transfer ownership from another awaitable_thread.+ explicit awaitable_handler_base(awaitable_thread<Executor>* h)+ : awaitable_thread<Executor>(std::move(*h))+ {+ }++protected:+ awaitable_frame<T, Executor>* frame() noexcept+ {+ return static_cast<awaitable_frame<T, Executor>*>(this->top_of_stack_);+ }+};++template <typename, typename...>+class awaitable_handler;++template <typename Executor>+class awaitable_handler<Executor>+ : public awaitable_handler_base<Executor, void>+{+public:+ using awaitable_handler_base<Executor, void>::awaitable_handler_base;++ void operator()()+ {+ this->frame()->attach_thread(this);+ this->frame()->return_void();+ this->frame()->pop_frame();+ this->pump();+ }+};++template <typename Executor>+class awaitable_handler<Executor, asio::error_code>+ : public awaitable_handler_base<Executor, void>+{+public:+ using awaitable_handler_base<Executor, void>::awaitable_handler_base;++ void operator()(const asio::error_code& ec)+ {+ this->frame()->attach_thread(this);+ if (ec)+ this->frame()->set_error(ec);+ else+ this->frame()->return_void();+ this->frame()->pop_frame();+ this->pump();+ }+};++template <typename Executor>+class awaitable_handler<Executor, std::exception_ptr>+ : public awaitable_handler_base<Executor, void>+{+public:+ using awaitable_handler_base<Executor, void>::awaitable_handler_base;++ void operator()(std::exception_ptr ex)+ {+ this->frame()->attach_thread(this);+ if (ex)+ this->frame()->set_except(ex);+ else+ this->frame()->return_void();+ this->frame()->pop_frame();+ this->pump();+ }+};++template <typename Executor, typename T>+class awaitable_handler<Executor, T>+ : public awaitable_handler_base<Executor, T>+{+public:+ using awaitable_handler_base<Executor, T>::awaitable_handler_base;++ template <typename Arg>+ void operator()(Arg&& arg)+ {+ this->frame()->attach_thread(this);+ this->frame()->return_value(std::forward<Arg>(arg));+ this->frame()->pop_frame();+ this->pump();+ }+};++template <typename Executor, typename T>+class awaitable_handler<Executor, asio::error_code, T>+ : public awaitable_handler_base<Executor, T>+{+public:+ using awaitable_handler_base<Executor, T>::awaitable_handler_base;++ template <typename Arg>+ void operator()(const asio::error_code& ec, Arg&& arg)+ {+ this->frame()->attach_thread(this);+ if (ec)+ this->frame()->set_error(ec);+ else+ this->frame()->return_value(std::forward<Arg>(arg));+ this->frame()->pop_frame();+ this->pump();+ }+};++template <typename Executor, typename T>+class awaitable_handler<Executor, std::exception_ptr, T>+ : public awaitable_handler_base<Executor, T>+{+public:+ using awaitable_handler_base<Executor, T>::awaitable_handler_base;++ template <typename Arg>+ void operator()(std::exception_ptr ex, Arg&& arg)+ {+ this->frame()->attach_thread(this);+ if (ex)+ this->frame()->set_except(ex);+ else+ this->frame()->return_value(std::forward<Arg>(arg));+ this->frame()->pop_frame();+ this->pump();+ }+};++template <typename Executor, typename... Ts>+class awaitable_handler+ : public awaitable_handler_base<Executor, std::tuple<Ts...>>+{+public:+ using awaitable_handler_base<Executor,+ std::tuple<Ts...>>::awaitable_handler_base;++ template <typename... Args>+ void operator()(Args&&... args)+ {+ this->frame()->attach_thread(this);+ this->frame()->return_values(std::forward<Args>(args)...);+ this->frame()->pop_frame();+ this->pump();+ }+};++template <typename Executor, typename... Ts>+class awaitable_handler<Executor, asio::error_code, Ts...>+ : public awaitable_handler_base<Executor, std::tuple<Ts...>>+{+public:+ using awaitable_handler_base<Executor,+ std::tuple<Ts...>>::awaitable_handler_base;++ template <typename... Args>+ void operator()(const asio::error_code& ec, Args&&... args)+ {+ this->frame()->attach_thread(this);+ if (ec)+ this->frame()->set_error(ec);+ else+ this->frame()->return_values(std::forward<Args>(args)...);+ this->frame()->pop_frame();+ this->pump();+ }+};++template <typename Executor, typename... Ts>+class awaitable_handler<Executor, std::exception_ptr, Ts...>+ : public awaitable_handler_base<Executor, std::tuple<Ts...>>+{+public:+ using awaitable_handler_base<Executor,+ std::tuple<Ts...>>::awaitable_handler_base;++ template <typename... Args>+ void operator()(std::exception_ptr ex, Args&&... args)+ {+ this->frame()->attach_thread(this);+ if (ex)+ this->frame()->set_except(ex);+ else+ this->frame()->return_values(std::forward<Args>(args)...);+ this->frame()->pop_frame();+ this->pump();+ }+};++} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename Executor, typename R, typename... Args>+class async_result<use_awaitable_t<Executor>, R(Args...)>+{+public:+ typedef typename detail::awaitable_handler<+ Executor, typename decay<Args>::type...> handler_type;+ typedef typename handler_type::awaitable_type return_type;++#if defined(_MSC_VER)+ template <typename T>+ static T dummy_return()+ {+ return std::move(*static_cast<T*>(nullptr));+ }++ template <>+ static void dummy_return()+ {+ }+#endif // defined(_MSC_VER)++ template <typename Initiation, typename... InitArgs>+ static return_type initiate(Initiation initiation,+ use_awaitable_t<Executor> u, InitArgs... args)+ {+ (void)u;++ co_await [&](auto* frame)+ {+ ASIO_HANDLER_LOCATION((u.file_name_, u.line_, u.function_name_));+ handler_type handler(frame->detach_thread());+ std::move(initiation)(std::move(handler), std::move(args)...);+ return static_cast<handler_type*>(nullptr);+ };++ for (;;) {} // Never reached.+#if defined(_MSC_VER)+ co_return dummy_return<typename return_type::value_type>();+#endif // defined(_MSC_VER)+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_USE_AWAITABLE_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/use_future.hpp view
@@ -0,0 +1,1028 @@+//+// impl/use_future.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_USE_FUTURE_HPP+#define ASIO_IMPL_USE_FUTURE_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/async_result.hpp"+#include "asio/detail/memory.hpp"+#include "asio/dispatch.hpp"+#include "asio/error_code.hpp"+#include "asio/execution.hpp"+#include "asio/packaged_task.hpp"+#include "asio/system_error.hpp"+#include "asio/system_executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename F, typename... Args>+inline void promise_invoke_and_set(std::promise<T>& p,+ F& f, ASIO_MOVE_ARG(Args)... args)+{+#if !defined(ASIO_NO_EXCEPTIONS)+ try+#endif // !defined(ASIO_NO_EXCEPTIONS)+ {+ p.set_value(f(ASIO_MOVE_CAST(Args)(args)...));+ }+#if !defined(ASIO_NO_EXCEPTIONS)+ catch (...)+ {+ p.set_exception(std::current_exception());+ }+#endif // !defined(ASIO_NO_EXCEPTIONS)+}++template <typename F, typename... Args>+inline void promise_invoke_and_set(std::promise<void>& p,+ F& f, ASIO_MOVE_ARG(Args)... args)+{+#if !defined(ASIO_NO_EXCEPTIONS)+ try+#endif // !defined(ASIO_NO_EXCEPTIONS)+ {+ f(ASIO_MOVE_CAST(Args)(args)...);+ p.set_value();+ }+#if !defined(ASIO_NO_EXCEPTIONS)+ catch (...)+ {+ p.set_exception(std::current_exception());+ }+#endif // !defined(ASIO_NO_EXCEPTIONS)+}++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename F>+inline void promise_invoke_and_set(std::promise<T>& p, F& f)+{+#if !defined(ASIO_NO_EXCEPTIONS)+ try+#endif // !defined(ASIO_NO_EXCEPTIONS)+ {+ p.set_value(f());+ }+#if !defined(ASIO_NO_EXCEPTIONS)+ catch (...)+ {+ p.set_exception(std::current_exception());+ }+#endif // !defined(ASIO_NO_EXCEPTIONS)+}++template <typename F, typename Args>+inline void promise_invoke_and_set(std::promise<void>& p, F& f)+{+#if !defined(ASIO_NO_EXCEPTIONS)+ try+#endif // !defined(ASIO_NO_EXCEPTIONS)+ {+ f();+ p.set_value();+#if !defined(ASIO_NO_EXCEPTIONS)+ }+ catch (...)+ {+ p.set_exception(std::current_exception());+ }+#endif // !defined(ASIO_NO_EXCEPTIONS)+}++#if defined(ASIO_NO_EXCEPTIONS)++#define ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \+ template <typename T, typename F, ASIO_VARIADIC_TPARAMS(n)> \+ inline void promise_invoke_and_set(std::promise<T>& p, \+ F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ p.set_value(f(ASIO_VARIADIC_MOVE_ARGS(n))); \+ } \+ \+ template <typename F, ASIO_VARIADIC_TPARAMS(n)> \+ inline void promise_invoke_and_set(std::promise<void>& p, \+ F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ f(ASIO_VARIADIC_MOVE_ARGS(n)); \+ p.set_value(); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_PROMISE_INVOKE_DEF)+#undef ASIO_PRIVATE_PROMISE_INVOKE_DEF++#else // defined(ASIO_NO_EXCEPTIONS)++#define ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \+ template <typename T, typename F, ASIO_VARIADIC_TPARAMS(n)> \+ inline void promise_invoke_and_set(std::promise<T>& p, \+ F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ try \+ { \+ p.set_value(f(ASIO_VARIADIC_MOVE_ARGS(n))); \+ } \+ catch (...) \+ { \+ p.set_exception(std::current_exception()); \+ } \+ } \+ \+ template <typename F, ASIO_VARIADIC_TPARAMS(n)> \+ inline void promise_invoke_and_set(std::promise<void>& p, \+ F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \+ { \+ try \+ { \+ f(ASIO_VARIADIC_MOVE_ARGS(n)); \+ p.set_value(); \+ } \+ catch (...) \+ { \+ p.set_exception(std::current_exception()); \+ } \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_PROMISE_INVOKE_DEF)+#undef ASIO_PRIVATE_PROMISE_INVOKE_DEF++#endif // defined(ASIO_NO_EXCEPTIONS)++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++// A function object adapter to invoke a nullary function object and capture+// any exception thrown into a promise.+template <typename T, typename F>+class promise_invoker+{+public:+ promise_invoker(const shared_ptr<std::promise<T> >& p,+ ASIO_MOVE_ARG(F) f)+ : p_(p), f_(ASIO_MOVE_CAST(F)(f))+ {+ }++ void operator()()+ {+#if !defined(ASIO_NO_EXCEPTIONS)+ try+#endif // !defined(ASIO_NO_EXCEPTIONS)+ {+ f_();+ }+#if !defined(ASIO_NO_EXCEPTIONS)+ catch (...)+ {+ p_->set_exception(std::current_exception());+ }+#endif // !defined(ASIO_NO_EXCEPTIONS)+ }++private:+ shared_ptr<std::promise<T> > p_;+ typename decay<F>::type f_;+};++// An executor that adapts the system_executor to capture any exeption thrown+// by a submitted function object and save it into a promise.+template <typename T, typename Blocking = execution::blocking_t::possibly_t>+class promise_executor+{+public:+ explicit promise_executor(const shared_ptr<std::promise<T> >& p)+ : p_(p)+ {+ }++ static ASIO_CONSTEXPR Blocking query(execution::blocking_t)+ {+ return Blocking();+ }++ promise_executor<T, execution::blocking_t::possibly_t>+ require(execution::blocking_t::possibly_t) const+ {+ return promise_executor<T, execution::blocking_t::possibly_t>(p_);+ }++ promise_executor<T, execution::blocking_t::never_t>+ require(execution::blocking_t::never_t) const+ {+ return promise_executor<T, execution::blocking_t::never_t>(p_);+ }++ template <typename F>+ void execute(ASIO_MOVE_ARG(F) f) const+ {+ execution::execute(+ asio::require(system_executor(), Blocking()),+ promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f)));+ }++#if !defined(ASIO_NO_TS_EXECUTORS)+ execution_context& context() const ASIO_NOEXCEPT+ {+ return system_executor().context();+ }++ void on_work_started() const ASIO_NOEXCEPT {}+ void on_work_finished() const ASIO_NOEXCEPT {}++ template <typename F, typename A>+ void dispatch(ASIO_MOVE_ARG(F) f, const A&) const+ {+ promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f))();+ }++ template <typename F, typename A>+ void post(ASIO_MOVE_ARG(F) f, const A& a) const+ {+ system_executor().post(+ promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f)), a);+ }++ template <typename F, typename A>+ void defer(ASIO_MOVE_ARG(F) f, const A& a) const+ {+ system_executor().defer(+ promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f)), a);+ }+#endif // !defined(ASIO_NO_TS_EXECUTORS)++ friend bool operator==(const promise_executor& a,+ const promise_executor& b) ASIO_NOEXCEPT+ {+ return a.p_ == b.p_;+ }++ friend bool operator!=(const promise_executor& a,+ const promise_executor& b) ASIO_NOEXCEPT+ {+ return a.p_ != b.p_;+ }++private:+ shared_ptr<std::promise<T> > p_;+};++// The base class for all completion handlers that create promises.+template <typename T>+class promise_creator+{+public:+ typedef promise_executor<T> executor_type;++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return executor_type(p_);+ }++ typedef std::future<T> future_type;++ future_type get_future()+ {+ return p_->get_future();+ }++protected:+ template <typename Allocator>+ void create_promise(const Allocator& a)+ {+ ASIO_REBIND_ALLOC(Allocator, char) b(a);+ p_ = std::allocate_shared<std::promise<T>>(b, std::allocator_arg, b);+ }++ shared_ptr<std::promise<T> > p_;+};++// For completion signature void().+class promise_handler_0+ : public promise_creator<void>+{+public:+ void operator()()+ {+ this->p_->set_value();+ }+};++// For completion signature void(error_code).+class promise_handler_ec_0+ : public promise_creator<void>+{+public:+ void operator()(const asio::error_code& ec)+ {+ if (ec)+ {+ this->p_->set_exception(+ std::make_exception_ptr(+ asio::system_error(ec)));+ }+ else+ {+ this->p_->set_value();+ }+ }+};++// For completion signature void(exception_ptr).+class promise_handler_ex_0+ : public promise_creator<void>+{+public:+ void operator()(const std::exception_ptr& ex)+ {+ if (ex)+ {+ this->p_->set_exception(ex);+ }+ else+ {+ this->p_->set_value();+ }+ }+};++// For completion signature void(T).+template <typename T>+class promise_handler_1+ : public promise_creator<T>+{+public:+ template <typename Arg>+ void operator()(ASIO_MOVE_ARG(Arg) arg)+ {+ this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg));+ }+};++// For completion signature void(error_code, T).+template <typename T>+class promise_handler_ec_1+ : public promise_creator<T>+{+public:+ template <typename Arg>+ void operator()(const asio::error_code& ec,+ ASIO_MOVE_ARG(Arg) arg)+ {+ if (ec)+ {+ this->p_->set_exception(+ std::make_exception_ptr(+ asio::system_error(ec)));+ }+ else+ this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg));+ }+};++// For completion signature void(exception_ptr, T).+template <typename T>+class promise_handler_ex_1+ : public promise_creator<T>+{+public:+ template <typename Arg>+ void operator()(const std::exception_ptr& ex,+ ASIO_MOVE_ARG(Arg) arg)+ {+ if (ex)+ this->p_->set_exception(ex);+ else+ this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg));+ }+};++// For completion signature void(T1, ..., Tn);+template <typename T>+class promise_handler_n+ : public promise_creator<T>+{+public:+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename... Args>+ void operator()(ASIO_MOVE_ARG(Args)... args)+ {+ this->p_->set_value(+ std::forward_as_tuple(+ ASIO_MOVE_CAST(Args)(args)...));+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#define ASIO_PRIVATE_CALL_OP_DEF(n) \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \+ {\+ this->p_->set_value( \+ std::forward_as_tuple( \+ ASIO_VARIADIC_MOVE_ARGS(n))); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF)+#undef ASIO_PRIVATE_CALL_OP_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+};++// For completion signature void(error_code, T1, ..., Tn);+template <typename T>+class promise_handler_ec_n+ : public promise_creator<T>+{+public:+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename... Args>+ void operator()(const asio::error_code& ec,+ ASIO_MOVE_ARG(Args)... args)+ {+ if (ec)+ {+ this->p_->set_exception(+ std::make_exception_ptr(+ asio::system_error(ec)));+ }+ else+ {+ this->p_->set_value(+ std::forward_as_tuple(+ ASIO_MOVE_CAST(Args)(args)...));+ }+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#define ASIO_PRIVATE_CALL_OP_DEF(n) \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ void operator()(const asio::error_code& ec, \+ ASIO_VARIADIC_MOVE_PARAMS(n)) \+ {\+ if (ec) \+ { \+ this->p_->set_exception( \+ std::make_exception_ptr( \+ asio::system_error(ec))); \+ } \+ else \+ { \+ this->p_->set_value( \+ std::forward_as_tuple( \+ ASIO_VARIADIC_MOVE_ARGS(n))); \+ } \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF)+#undef ASIO_PRIVATE_CALL_OP_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+};++// For completion signature void(exception_ptr, T1, ..., Tn);+template <typename T>+class promise_handler_ex_n+ : public promise_creator<T>+{+public:+#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename... Args>+ void operator()(const std::exception_ptr& ex,+ ASIO_MOVE_ARG(Args)... args)+ {+ if (ex)+ this->p_->set_exception(ex);+ else+ {+ this->p_->set_value(+ std::forward_as_tuple(+ ASIO_MOVE_CAST(Args)(args)...));+ }+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#define ASIO_PRIVATE_CALL_OP_DEF(n) \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ void operator()(const std::exception_ptr& ex, \+ ASIO_VARIADIC_MOVE_PARAMS(n)) \+ {\+ if (ex) \+ this->p_->set_exception(ex); \+ else \+ { \+ this->p_->set_value( \+ std::forward_as_tuple( \+ ASIO_VARIADIC_MOVE_ARGS(n))); \+ } \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF)+#undef ASIO_PRIVATE_CALL_OP_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+};++// Helper template to choose the appropriate concrete promise handler+// implementation based on the supplied completion signature.+template <typename> class promise_handler_selector;++template <>+class promise_handler_selector<void()>+ : public promise_handler_0 {};++template <>+class promise_handler_selector<void(asio::error_code)>+ : public promise_handler_ec_0 {};++template <>+class promise_handler_selector<void(std::exception_ptr)>+ : public promise_handler_ex_0 {};++template <typename Arg>+class promise_handler_selector<void(Arg)>+ : public promise_handler_1<Arg> {};++template <typename Arg>+class promise_handler_selector<void(asio::error_code, Arg)>+ : public promise_handler_ec_1<Arg> {};++template <typename Arg>+class promise_handler_selector<void(std::exception_ptr, Arg)>+ : public promise_handler_ex_1<Arg> {};++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename... Arg>+class promise_handler_selector<void(Arg...)>+ : public promise_handler_n<std::tuple<Arg...> > {};++template <typename... Arg>+class promise_handler_selector<void(asio::error_code, Arg...)>+ : public promise_handler_ec_n<std::tuple<Arg...> > {};++template <typename... Arg>+class promise_handler_selector<void(std::exception_ptr, Arg...)>+ : public promise_handler_ex_n<std::tuple<Arg...> > {};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#define ASIO_PRIVATE_PROMISE_SELECTOR_DEF(n) \+ template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \+ class promise_handler_selector< \+ void(Arg, ASIO_VARIADIC_TARGS(n))> \+ : public promise_handler_n< \+ std::tuple<Arg, ASIO_VARIADIC_TARGS(n)> > {}; \+ \+ template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \+ class promise_handler_selector< \+ void(asio::error_code, Arg, ASIO_VARIADIC_TARGS(n))> \+ : public promise_handler_ec_n< \+ std::tuple<Arg, ASIO_VARIADIC_TARGS(n)> > {}; \+ \+ template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \+ class promise_handler_selector< \+ void(std::exception_ptr, Arg, ASIO_VARIADIC_TARGS(n))> \+ : public promise_handler_ex_n< \+ std::tuple<Arg, ASIO_VARIADIC_TARGS(n)> > {}; \+ /**/+ ASIO_VARIADIC_GENERATE_5(ASIO_PRIVATE_PROMISE_SELECTOR_DEF)+#undef ASIO_PRIVATE_PROMISE_SELECTOR_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++// Completion handlers produced from the use_future completion token, when not+// using use_future::operator().+template <typename Signature, typename Allocator>+class promise_handler+ : public promise_handler_selector<Signature>+{+public:+ typedef Allocator allocator_type;+ typedef void result_type;++ promise_handler(use_future_t<Allocator> u)+ : allocator_(u.get_allocator())+ {+ this->create_promise(allocator_);+ }++ allocator_type get_allocator() const ASIO_NOEXCEPT+ {+ return allocator_;+ }++private:+ Allocator allocator_;+};++template <typename Function>+struct promise_function_wrapper+{+ explicit promise_function_wrapper(Function& f)+ : function_(ASIO_MOVE_CAST(Function)(f))+ {+ }++ explicit promise_function_wrapper(const Function& f)+ : function_(f)+ {+ }++ void operator()()+ {+ function_();+ }++ Function function_;+};++#if !defined(ASIO_NO_DEPRECATED)++template <typename Function, typename Signature, typename Allocator>+inline void asio_handler_invoke(Function& f,+ promise_handler<Signature, Allocator>* h)+{+ typename promise_handler<Signature, Allocator>::executor_type+ ex(h->get_executor());+ asio::dispatch(ex, promise_function_wrapper<Function>(f));+}++template <typename Function, typename Signature, typename Allocator>+inline void asio_handler_invoke(const Function& f,+ promise_handler<Signature, Allocator>* h)+{+ typename promise_handler<Signature, Allocator>::executor_type+ ex(h->get_executor());+ asio::dispatch(ex, promise_function_wrapper<Function>(f));+}++#endif // !defined(ASIO_NO_DEPRECATED)++// Helper base class for async_result specialisation.+template <typename Signature, typename Allocator>+class promise_async_result+{+public:+ typedef promise_handler<Signature, Allocator> completion_handler_type;+ typedef typename completion_handler_type::future_type return_type;++ explicit promise_async_result(completion_handler_type& h)+ : future_(h.get_future())+ {+ }++ return_type get()+ {+ return ASIO_MOVE_CAST(return_type)(future_);+ }++private:+ return_type future_;+};++// Return value from use_future::operator().+template <typename Function, typename Allocator>+class packaged_token+{+public:+ packaged_token(Function f, const Allocator& a)+ : function_(ASIO_MOVE_CAST(Function)(f)),+ allocator_(a)+ {+ }++//private:+ Function function_;+ Allocator allocator_;+};++// Completion handlers produced from the use_future completion token, when+// using use_future::operator().+template <typename Function, typename Allocator, typename Result>+class packaged_handler+ : public promise_creator<Result>+{+public:+ typedef Allocator allocator_type;+ typedef void result_type;++ packaged_handler(packaged_token<Function, Allocator> t)+ : function_(ASIO_MOVE_CAST(Function)(t.function_)),+ allocator_(t.allocator_)+ {+ this->create_promise(allocator_);+ }++ allocator_type get_allocator() const ASIO_NOEXCEPT+ {+ return allocator_;+ }++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++ template <typename... Args>+ void operator()(ASIO_MOVE_ARG(Args)... args)+ {+ (promise_invoke_and_set)(*this->p_,+ function_, ASIO_MOVE_CAST(Args)(args)...);+ }++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++ void operator()()+ {+ (promise_invoke_and_set)(*this->p_, function_);+ }++#define ASIO_PRIVATE_CALL_OP_DEF(n) \+ template <ASIO_VARIADIC_TPARAMS(n)> \+ void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \+ {\+ (promise_invoke_and_set)(*this->p_, \+ function_, ASIO_VARIADIC_MOVE_ARGS(n)); \+ } \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF)+#undef ASIO_PRIVATE_CALL_OP_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++private:+ Function function_;+ Allocator allocator_;+};++#if !defined(ASIO_NO_DEPRECATED)++template <typename Function,+ typename Function1, typename Allocator, typename Result>+inline void asio_handler_invoke(Function& f,+ packaged_handler<Function1, Allocator, Result>* h)+{+ typename packaged_handler<Function1, Allocator, Result>::executor_type+ ex(h->get_executor());+ asio::dispatch(ex, promise_function_wrapper<Function>(f));+}++template <typename Function,+ typename Function1, typename Allocator, typename Result>+inline void asio_handler_invoke(const Function& f,+ packaged_handler<Function1, Allocator, Result>* h)+{+ typename packaged_handler<Function1, Allocator, Result>::executor_type+ ex(h->get_executor());+ asio::dispatch(ex, promise_function_wrapper<Function>(f));+}++#endif // !defined(ASIO_NO_DEPRECATED)++// Helper base class for async_result specialisation.+template <typename Function, typename Allocator, typename Result>+class packaged_async_result+{+public:+ typedef packaged_handler<Function, Allocator, Result> completion_handler_type;+ typedef typename completion_handler_type::future_type return_type;++ explicit packaged_async_result(completion_handler_type& h)+ : future_(h.get_future())+ {+ }++ return_type get()+ {+ return ASIO_MOVE_CAST(return_type)(future_);+ }++private:+ return_type future_;+};++} // namespace detail++template <typename Allocator> template <typename Function>+inline detail::packaged_token<typename decay<Function>::type, Allocator>+use_future_t<Allocator>::operator()(ASIO_MOVE_ARG(Function) f) const+{+ return detail::packaged_token<typename decay<Function>::type, Allocator>(+ ASIO_MOVE_CAST(Function)(f), allocator_);+}++#if !defined(GENERATING_DOCUMENTATION)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename Allocator, typename Result, typename... Args>+class async_result<use_future_t<Allocator>, Result(Args...)>+ : public detail::promise_async_result<+ void(typename decay<Args>::type...), Allocator>+{+public:+ explicit async_result(+ typename detail::promise_async_result<void(typename decay<Args>::type...),+ Allocator>::completion_handler_type& h)+ : detail::promise_async_result<+ void(typename decay<Args>::type...), Allocator>(h)+ {+ }+};++template <typename Function, typename Allocator,+ typename Result, typename... Args>+class async_result<detail::packaged_token<Function, Allocator>, Result(Args...)>+ : public detail::packaged_async_result<Function, Allocator,+ typename result_of<Function(Args...)>::type>+{+public:+ explicit async_result(+ typename detail::packaged_async_result<Function, Allocator,+ typename result_of<Function(Args...)>::type>::completion_handler_type& h)+ : detail::packaged_async_result<Function, Allocator,+ typename result_of<Function(Args...)>::type>(h)+ {+ }+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename Allocator, typename Result>+class async_result<use_future_t<Allocator>, Result()>+ : public detail::promise_async_result<void(), Allocator>+{+public:+ explicit async_result(+ typename detail::promise_async_result<+ void(), Allocator>::completion_handler_type& h)+ : detail::promise_async_result<void(), Allocator>(h)+ {+ }+};++template <typename Function, typename Allocator, typename Result>+class async_result<detail::packaged_token<Function, Allocator>, Result()>+ : public detail::packaged_async_result<Function, Allocator,+ typename result_of<Function()>::type>+{+public:+ explicit async_result(+ typename detail::packaged_async_result<Function, Allocator,+ typename result_of<Function()>::type>::completion_handler_type& h)+ : detail::packaged_async_result<Function, Allocator,+ typename result_of<Function()>::type>(h)+ {+ }+};++#define ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \+ template <typename Allocator, \+ typename Result, ASIO_VARIADIC_TPARAMS(n)> \+ class async_result<use_future_t<Allocator>, \+ Result(ASIO_VARIADIC_TARGS(n))> \+ : public detail::promise_async_result< \+ void(ASIO_VARIADIC_DECAY(n)), Allocator> \+ { \+ public: \+ explicit async_result( \+ typename detail::promise_async_result< \+ void(ASIO_VARIADIC_DECAY(n)), \+ Allocator>::completion_handler_type& h) \+ : detail::promise_async_result< \+ void(ASIO_VARIADIC_DECAY(n)), Allocator>(h) \+ { \+ } \+ }; \+ \+ template <typename Function, typename Allocator, \+ typename Result, ASIO_VARIADIC_TPARAMS(n)> \+ class async_result<detail::packaged_token<Function, Allocator>, \+ Result(ASIO_VARIADIC_TARGS(n))> \+ : public detail::packaged_async_result<Function, Allocator, \+ typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type> \+ { \+ public: \+ explicit async_result( \+ typename detail::packaged_async_result<Function, Allocator, \+ typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type \+ >::completion_handler_type& h) \+ : detail::packaged_async_result<Function, Allocator, \+ typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type>(h) \+ { \+ } \+ }; \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_RESULT_DEF)+#undef ASIO_PRIVATE_ASYNC_RESULT_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++template <typename T, typename Blocking>+struct equality_comparable<+ asio::detail::promise_executor<T, Blocking> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+};++#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++template <typename T, typename Blocking, typename Function>+struct execute_member<+ asio::detail::promise_executor<T, Blocking>, Function>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_TRAIT)++template <typename T, typename Blocking, typename Property>+struct query_static_constexpr_member<+ asio::detail::promise_executor<T, Blocking>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::blocking_t+ >::value+ >::type+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef Blocking result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return Blocking();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++template <typename T, typename Blocking>+struct require_member<+ asio::detail::promise_executor<T, Blocking>,+ execution::blocking_t::possibly_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::detail::promise_executor<T,+ execution::blocking_t::possibly_t> result_type;+};++template <typename T, typename Blocking>+struct require_member<+ asio::detail::promise_executor<T, Blocking>,+ execution::blocking_t::never_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::detail::promise_executor<T,+ execution::blocking_t::never_t> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++} // namespace traits++#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_USE_FUTURE_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/write.hpp view
@@ -0,0 +1,1104 @@+//+// impl/write.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WRITE_HPP+#define ASIO_IMPL_WRITE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/associated_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/buffer.hpp"+#include "asio/completion_condition.hpp"+#include "asio/detail/array_fwd.hpp"+#include "asio/detail/base_from_completion_cond.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/consuming_buffers.hpp"+#include "asio/detail/dependent_type.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_cont_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_tracking.hpp"+#include "asio/detail/handler_type_requirements.hpp"+#include "asio/detail/non_const_lvalue.hpp"+#include "asio/detail/throw_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++namespace detail+{+ template <typename SyncWriteStream, typename ConstBufferSequence,+ typename ConstBufferIterator, typename CompletionCondition>+ std::size_t write_buffer_sequence(SyncWriteStream& s,+ const ConstBufferSequence& buffers, const ConstBufferIterator&,+ CompletionCondition completion_condition, asio::error_code& ec)+ {+ ec = asio::error_code();+ asio::detail::consuming_buffers<const_buffer,+ ConstBufferSequence, ConstBufferIterator> tmp(buffers);+ while (!tmp.empty())+ {+ if (std::size_t max_size = detail::adapt_completion_condition_result(+ completion_condition(ec, tmp.total_consumed())))+ tmp.consume(s.write_some(tmp.prepare(max_size), ec));+ else+ break;+ }+ return tmp.total_consumed();;+ }+} // namespace detail++template <typename SyncWriteStream, typename ConstBufferSequence,+ typename CompletionCondition>+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type*)+{+ return detail::write_buffer_sequence(s, buffers,+ asio::buffer_sequence_begin(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+}++template <typename SyncWriteStream, typename ConstBufferSequence>+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec);+ asio::detail::throw_error(ec, "write");+ return bytes_transferred;+}++template <typename SyncWriteStream, typename ConstBufferSequence>+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,+ asio::error_code& ec,+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type*)+{+ return write(s, buffers, transfer_all(), ec);+}++template <typename SyncWriteStream, typename ConstBufferSequence,+ typename CompletionCondition>+inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = write(s, buffers,+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ asio::detail::throw_error(ec, "write");+ return bytes_transferred;+}++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++template <typename SyncWriteStream, typename DynamicBuffer_v1,+ typename CompletionCondition>+std::size_t write(SyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ typename decay<DynamicBuffer_v1>::type b(+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers));++ std::size_t bytes_transferred = write(s, b.data(),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ b.consume(bytes_transferred);+ return bytes_transferred;+}++template <typename SyncWriteStream, typename DynamicBuffer_v1>+inline std::size_t write(SyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = write(s,+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ transfer_all(), ec);+ asio::detail::throw_error(ec, "write");+ return bytes_transferred;+}++template <typename SyncWriteStream, typename DynamicBuffer_v1>+inline std::size_t write(SyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ return write(s, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ transfer_all(), ec);+}++template <typename SyncWriteStream, typename DynamicBuffer_v1,+ typename CompletionCondition>+inline std::size_t write(SyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = write(s,+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ asio::detail::throw_error(ec, "write");+ return bytes_transferred;+}++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++template <typename SyncWriteStream, typename Allocator,+ typename CompletionCondition>+inline std::size_t write(SyncWriteStream& s,+ asio::basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition, asio::error_code& ec)+{+ return write(s, basic_streambuf_ref<Allocator>(b),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+}++template <typename SyncWriteStream, typename Allocator>+inline std::size_t write(SyncWriteStream& s,+ asio::basic_streambuf<Allocator>& b)+{+ return write(s, basic_streambuf_ref<Allocator>(b));+}++template <typename SyncWriteStream, typename Allocator>+inline std::size_t write(SyncWriteStream& s,+ asio::basic_streambuf<Allocator>& b,+ asio::error_code& ec)+{+ return write(s, basic_streambuf_ref<Allocator>(b), ec);+}++template <typename SyncWriteStream, typename Allocator,+ typename CompletionCondition>+inline std::size_t write(SyncWriteStream& s,+ asio::basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition)+{+ return write(s, basic_streambuf_ref<Allocator>(b),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++template <typename SyncWriteStream, typename DynamicBuffer_v2,+ typename CompletionCondition>+std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ std::size_t bytes_transferred = write(s, buffers.data(0, buffers.size()),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ buffers.consume(bytes_transferred);+ return bytes_transferred;+}++template <typename SyncWriteStream, typename DynamicBuffer_v2>+inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = write(s,+ ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ transfer_all(), ec);+ asio::detail::throw_error(ec, "write");+ return bytes_transferred;+}++template <typename SyncWriteStream, typename DynamicBuffer_v2>+inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,+ asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ return write(s, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ transfer_all(), ec);+}++template <typename SyncWriteStream, typename DynamicBuffer_v2,+ typename CompletionCondition>+inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ asio::error_code ec;+ std::size_t bytes_transferred = write(s,+ ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ asio::detail::throw_error(ec, "write");+ return bytes_transferred;+}++namespace detail+{+ template <typename AsyncWriteStream, typename ConstBufferSequence,+ typename ConstBufferIterator, typename CompletionCondition,+ typename WriteHandler>+ class write_op+ : detail::base_from_completion_cond<CompletionCondition>+ {+ public:+ write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers,+ CompletionCondition& completion_condition, WriteHandler& handler)+ : detail::base_from_completion_cond<+ CompletionCondition>(completion_condition),+ stream_(stream),+ buffers_(buffers),+ start_(0),+ handler_(ASIO_MOVE_CAST(WriteHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ write_op(const write_op& other)+ : detail::base_from_completion_cond<CompletionCondition>(other),+ stream_(other.stream_),+ buffers_(other.buffers_),+ start_(other.start_),+ handler_(other.handler_)+ {+ }++ write_op(write_op&& other)+ : detail::base_from_completion_cond<CompletionCondition>(+ ASIO_MOVE_CAST(detail::base_from_completion_cond<+ CompletionCondition>)(other)),+ stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(buffers_type)(other.buffers_)),+ start_(other.start_),+ handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ std::size_t max_size;+ switch (start_ = start)+ {+ case 1:+ max_size = this->check_for_completion(ec, buffers_.total_consumed());+ do+ {+ {+ ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_write"));+ stream_.async_write_some(buffers_.prepare(max_size),+ ASIO_MOVE_CAST(write_op)(*this));+ }+ return; default:+ buffers_.consume(bytes_transferred);+ if ((!ec && bytes_transferred == 0) || buffers_.empty())+ break;+ max_size = this->check_for_completion(ec, buffers_.total_consumed());+ } while (max_size > 0);++ handler_(ec, buffers_.total_consumed());+ }+ }++ //private:+ typedef asio::detail::consuming_buffers<const_buffer,+ ConstBufferSequence, ConstBufferIterator> buffers_type;++ AsyncWriteStream& stream_;+ buffers_type buffers_;+ int start_;+ WriteHandler handler_;+ };++ template <typename AsyncWriteStream, typename ConstBufferSequence,+ typename ConstBufferIterator, typename CompletionCondition,+ typename WriteHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator,+ CompletionCondition, WriteHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncWriteStream, typename ConstBufferSequence,+ typename ConstBufferIterator, typename CompletionCondition,+ typename WriteHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator,+ CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncWriteStream, typename ConstBufferSequence,+ typename ConstBufferIterator, typename CompletionCondition,+ typename WriteHandler>+ inline bool asio_handler_is_continuation(+ write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator,+ CompletionCondition, WriteHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncWriteStream,+ typename ConstBufferSequence, typename ConstBufferIterator,+ typename CompletionCondition, typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator,+ CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncWriteStream,+ typename ConstBufferSequence, typename ConstBufferIterator,+ typename CompletionCondition, typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator,+ CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncWriteStream, typename ConstBufferSequence,+ typename ConstBufferIterator, typename CompletionCondition,+ typename WriteHandler>+ inline void start_write_buffer_sequence_op(AsyncWriteStream& stream,+ const ConstBufferSequence& buffers, const ConstBufferIterator&,+ CompletionCondition& completion_condition, WriteHandler& handler)+ {+ detail::write_op<AsyncWriteStream, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>(+ stream, buffers, completion_condition, handler)(+ asio::error_code(), 0, 1);+ }++ template <typename AsyncWriteStream>+ class initiate_async_write_buffer_sequence+ {+ public:+ typedef typename AsyncWriteStream::executor_type executor_type;++ explicit initiate_async_write_buffer_sequence(AsyncWriteStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence,+ typename CompletionCondition>+ void operator()(ASIO_MOVE_ARG(WriteHandler) handler,+ const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(CompletionCondition) completion_cond) 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;++ non_const_lvalue<WriteHandler> handler2(handler);+ non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);+ start_write_buffer_sequence_op(stream_, buffers,+ asio::buffer_sequence_begin(buffers),+ completion_cond2.value, handler2.value);+ }++ private:+ AsyncWriteStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncWriteStream, typename ConstBufferSequence,+ typename ConstBufferIterator, typename CompletionCondition,+ typename WriteHandler, typename Allocator>+struct associated_allocator<+ detail::write_op<AsyncWriteStream, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>,+ Allocator>+{+ typedef typename associated_allocator<WriteHandler, Allocator>::type type;++ static type get(+ const detail::write_op<AsyncWriteStream, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncWriteStream, typename ConstBufferSequence,+ typename ConstBufferIterator, typename CompletionCondition,+ typename WriteHandler, typename Executor>+struct associated_executor<+ detail::write_op<AsyncWriteStream, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<WriteHandler, Executor>+{+ typedef typename associated_executor<WriteHandler, Executor>::type type;++ static type get(+ const detail::write_op<AsyncWriteStream, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncWriteStream,+ typename ConstBufferSequence, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler,+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type*)+{+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_write_buffer_sequence<AsyncWriteStream>(s),+ handler, buffers,+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++template <typename AsyncWriteStream, typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler,+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type*)+{+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_write_buffer_sequence<AsyncWriteStream>(s),+ handler, buffers, transfer_all());+}++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++namespace detail+{+ template <typename AsyncWriteStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename WriteHandler>+ class write_dynbuf_v1_op+ {+ public:+ template <typename BufferSequence>+ write_dynbuf_v1_op(AsyncWriteStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ CompletionCondition& completion_condition, WriteHandler& handler)+ : stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ completion_condition_(+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition)),+ handler_(ASIO_MOVE_CAST(WriteHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ write_dynbuf_v1_op(const write_dynbuf_v1_op& other)+ : stream_(other.stream_),+ buffers_(other.buffers_),+ completion_condition_(other.completion_condition_),+ handler_(other.handler_)+ {+ }++ write_dynbuf_v1_op(write_dynbuf_v1_op&& other)+ : stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)),+ completion_condition_(+ ASIO_MOVE_CAST(CompletionCondition)(+ other.completion_condition_)),+ handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ switch (start)+ {+ case 1:+ async_write(stream_, buffers_.data(),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition_),+ ASIO_MOVE_CAST(write_dynbuf_v1_op)(*this));+ return; default:+ buffers_.consume(bytes_transferred);+ handler_(ec, static_cast<const std::size_t&>(bytes_transferred));+ }+ }++ //private:+ AsyncWriteStream& stream_;+ DynamicBuffer_v1 buffers_;+ CompletionCondition completion_condition_;+ WriteHandler handler_;+ };++ template <typename AsyncWriteStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename WriteHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,+ CompletionCondition, WriteHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncWriteStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename WriteHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,+ CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncWriteStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename WriteHandler>+ inline bool asio_handler_is_continuation(+ write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,+ CompletionCondition, WriteHandler>* this_handler)+ {+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncWriteStream,+ typename DynamicBuffer_v1, typename CompletionCondition,+ typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,+ CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncWriteStream,+ typename DynamicBuffer_v1, typename CompletionCondition,+ typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1,+ CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncWriteStream>+ class initiate_async_write_dynbuf_v1+ {+ public:+ typedef typename AsyncWriteStream::executor_type executor_type;++ explicit initiate_async_write_dynbuf_v1(AsyncWriteStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename WriteHandler, typename DynamicBuffer_v1,+ typename CompletionCondition>+ void operator()(ASIO_MOVE_ARG(WriteHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_MOVE_ARG(CompletionCondition) completion_cond) 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;++ non_const_lvalue<WriteHandler> handler2(handler);+ non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);+ write_dynbuf_v1_op<AsyncWriteStream,+ typename decay<DynamicBuffer_v1>::type,+ CompletionCondition, typename decay<WriteHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ completion_cond2.value, handler2.value)(+ asio::error_code(), 0, 1);+ }++ private:+ AsyncWriteStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncWriteStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename WriteHandler, typename Allocator>+struct associated_allocator<+ detail::write_dynbuf_v1_op<AsyncWriteStream,+ DynamicBuffer_v1, CompletionCondition, WriteHandler>,+ Allocator>+{+ typedef typename associated_allocator<WriteHandler, Allocator>::type type;++ static type get(+ const detail::write_dynbuf_v1_op<AsyncWriteStream,+ DynamicBuffer_v1, CompletionCondition, WriteHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncWriteStream, typename DynamicBuffer_v1,+ typename CompletionCondition, typename WriteHandler, typename Executor>+struct associated_executor<+ detail::write_dynbuf_v1_op<AsyncWriteStream,+ DynamicBuffer_v1, CompletionCondition, WriteHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<WriteHandler, Executor>+{+ typedef typename associated_executor<WriteHandler, Executor>::type type;++ static type get(+ const detail::write_dynbuf_v1_op<AsyncWriteStream,+ DynamicBuffer_v1, CompletionCondition, WriteHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncWriteStream, typename DynamicBuffer_v1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_MOVE_ARG(WriteHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ return async_write(s,+ ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ transfer_all(), ASIO_MOVE_CAST(WriteHandler)(handler));+}++template <typename AsyncWriteStream,+ typename DynamicBuffer_v1, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type*)+{+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>(s),+ handler, ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++template <typename AsyncWriteStream, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s,+ asio::basic_streambuf<Allocator>& b,+ ASIO_MOVE_ARG(WriteHandler) handler)+{+ return async_write(s, basic_streambuf_ref<Allocator>(b),+ ASIO_MOVE_CAST(WriteHandler)(handler));+}++template <typename AsyncWriteStream,+ typename Allocator, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s,+ asio::basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler)+{+ return async_write(s, basic_streambuf_ref<Allocator>(b),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition),+ ASIO_MOVE_CAST(WriteHandler)(handler));+}++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++namespace detail+{+ template <typename AsyncWriteStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename WriteHandler>+ class write_dynbuf_v2_op+ {+ public:+ template <typename BufferSequence>+ write_dynbuf_v2_op(AsyncWriteStream& stream,+ ASIO_MOVE_ARG(BufferSequence) buffers,+ CompletionCondition& completion_condition, WriteHandler& handler)+ : stream_(stream),+ buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)),+ completion_condition_(+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition)),+ handler_(ASIO_MOVE_CAST(WriteHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ write_dynbuf_v2_op(const write_dynbuf_v2_op& other)+ : stream_(other.stream_),+ buffers_(other.buffers_),+ completion_condition_(other.completion_condition_),+ handler_(other.handler_)+ {+ }++ write_dynbuf_v2_op(write_dynbuf_v2_op&& other)+ : stream_(other.stream_),+ buffers_(ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)),+ completion_condition_(+ ASIO_MOVE_CAST(CompletionCondition)(+ other.completion_condition_)),+ handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ switch (start)+ {+ case 1:+ async_write(stream_, buffers_.data(0, buffers_.size()),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition_),+ ASIO_MOVE_CAST(write_dynbuf_v2_op)(*this));+ return; default:+ buffers_.consume(bytes_transferred);+ handler_(ec, static_cast<const std::size_t&>(bytes_transferred));+ }+ }++ //private:+ AsyncWriteStream& stream_;+ DynamicBuffer_v2 buffers_;+ CompletionCondition completion_condition_;+ WriteHandler handler_;+ };++ template <typename AsyncWriteStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename WriteHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2,+ CompletionCondition, WriteHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncWriteStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename WriteHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2,+ CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncWriteStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename WriteHandler>+ inline bool asio_handler_is_continuation(+ write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2,+ CompletionCondition, WriteHandler>* this_handler)+ {+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncWriteStream,+ typename DynamicBuffer_v2, typename CompletionCondition,+ typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2,+ CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncWriteStream,+ typename DynamicBuffer_v2, typename CompletionCondition,+ typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2,+ CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncWriteStream>+ class initiate_async_write_dynbuf_v2+ {+ public:+ typedef typename AsyncWriteStream::executor_type executor_type;++ explicit initiate_async_write_dynbuf_v2(AsyncWriteStream& stream)+ : stream_(stream)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return stream_.get_executor();+ }++ template <typename WriteHandler, typename DynamicBuffer_v2,+ typename CompletionCondition>+ void operator()(ASIO_MOVE_ARG(WriteHandler) handler,+ ASIO_MOVE_ARG(DynamicBuffer_v2) buffers,+ ASIO_MOVE_ARG(CompletionCondition) completion_cond) 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;++ non_const_lvalue<WriteHandler> handler2(handler);+ non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);+ write_dynbuf_v2_op<AsyncWriteStream,+ typename decay<DynamicBuffer_v2>::type,+ CompletionCondition, typename decay<WriteHandler>::type>(+ stream_, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ completion_cond2.value, handler2.value)(+ asio::error_code(), 0, 1);+ }++ private:+ AsyncWriteStream& stream_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncWriteStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename WriteHandler, typename Allocator>+struct associated_allocator<+ detail::write_dynbuf_v2_op<AsyncWriteStream,+ DynamicBuffer_v2, CompletionCondition, WriteHandler>,+ Allocator>+{+ typedef typename associated_allocator<WriteHandler, Allocator>::type type;++ static type get(+ const detail::write_dynbuf_v2_op<AsyncWriteStream,+ DynamicBuffer_v2, CompletionCondition, WriteHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncWriteStream, typename DynamicBuffer_v2,+ typename CompletionCondition, typename WriteHandler, typename Executor>+struct associated_executor<+ detail::write_dynbuf_v2_op<AsyncWriteStream,+ DynamicBuffer_v2, CompletionCondition, WriteHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<WriteHandler, Executor>+{+ typedef typename associated_executor<WriteHandler, Executor>::type type;++ static type get(+ const detail::write_dynbuf_v2_op<AsyncWriteStream,+ DynamicBuffer_v2, CompletionCondition, WriteHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncWriteStream, typename DynamicBuffer_v2,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers,+ ASIO_MOVE_ARG(WriteHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ return async_write(s,+ ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ transfer_all(), ASIO_MOVE_CAST(WriteHandler)(handler));+}++template <typename AsyncWriteStream,+ typename DynamicBuffer_v2, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type*)+{+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>(s),+ handler, ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_WRITE_HPP
+ link/modules/asio-standalone/asio/include/asio/impl/write_at.hpp view
@@ -0,0 +1,666 @@+//+// impl/write_at.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IMPL_WRITE_AT_HPP+#define ASIO_IMPL_WRITE_AT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/associated_allocator.hpp"+#include "asio/associated_executor.hpp"+#include "asio/buffer.hpp"+#include "asio/completion_condition.hpp"+#include "asio/detail/array_fwd.hpp"+#include "asio/detail/base_from_completion_cond.hpp"+#include "asio/detail/bind_handler.hpp"+#include "asio/detail/consuming_buffers.hpp"+#include "asio/detail/dependent_type.hpp"+#include "asio/detail/handler_alloc_helpers.hpp"+#include "asio/detail/handler_cont_helpers.hpp"+#include "asio/detail/handler_invoke_helpers.hpp"+#include "asio/detail/handler_tracking.hpp"+#include "asio/detail/handler_type_requirements.hpp"+#include "asio/detail/non_const_lvalue.hpp"+#include "asio/detail/throw_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++namespace detail+{+ template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,+ typename ConstBufferIterator, typename CompletionCondition>+ std::size_t write_at_buffer_sequence(SyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers,+ const ConstBufferIterator&, CompletionCondition completion_condition,+ asio::error_code& ec)+ {+ ec = asio::error_code();+ asio::detail::consuming_buffers<const_buffer,+ ConstBufferSequence, ConstBufferIterator> tmp(buffers);+ while (!tmp.empty())+ {+ if (std::size_t max_size = detail::adapt_completion_condition_result(+ completion_condition(ec, tmp.total_consumed())))+ {+ tmp.consume(d.write_some_at(offset + tmp.total_consumed(),+ tmp.prepare(max_size), ec));+ }+ else+ break;+ }+ return tmp.total_consumed();;+ }+} // namespace detail++template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,+ typename CompletionCondition>+std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition, asio::error_code& ec)+{+ return detail::write_at_buffer_sequence(d, offset, buffers,+ asio::buffer_sequence_begin(buffers),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+}++template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers)+{+ asio::error_code ec;+ std::size_t bytes_transferred = write_at(+ d, offset, buffers, transfer_all(), ec);+ asio::detail::throw_error(ec, "write_at");+ return bytes_transferred;+}++template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers,+ asio::error_code& ec)+{+ return write_at(d, offset, buffers, transfer_all(), ec);+}++template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,+ typename CompletionCondition>+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition)+{+ asio::error_code ec;+ std::size_t bytes_transferred = write_at(d, offset, buffers,+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ asio::detail::throw_error(ec, "write_at");+ return bytes_transferred;+}++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++template <typename SyncRandomAccessWriteDevice, typename Allocator,+ typename CompletionCondition>+std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition, asio::error_code& ec)+{+ std::size_t bytes_transferred = write_at(d, offset, b.data(),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ b.consume(bytes_transferred);+ return bytes_transferred;+}++template <typename SyncRandomAccessWriteDevice, typename Allocator>+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b)+{+ asio::error_code ec;+ std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec);+ asio::detail::throw_error(ec, "write_at");+ return bytes_transferred;+}++template <typename SyncRandomAccessWriteDevice, typename Allocator>+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b,+ asio::error_code& ec)+{+ return write_at(d, offset, b, transfer_all(), ec);+}++template <typename SyncRandomAccessWriteDevice, typename Allocator,+ typename CompletionCondition>+inline std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition)+{+ asio::error_code ec;+ std::size_t bytes_transferred = write_at(d, offset, b,+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);+ asio::detail::throw_error(ec, "write_at");+ return bytes_transferred;+}++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)++namespace detail+{+ template <typename AsyncRandomAccessWriteDevice,+ typename ConstBufferSequence, typename ConstBufferIterator,+ typename CompletionCondition, typename WriteHandler>+ class write_at_op+ : detail::base_from_completion_cond<CompletionCondition>+ {+ public:+ write_at_op(AsyncRandomAccessWriteDevice& device,+ uint64_t offset, const ConstBufferSequence& buffers,+ CompletionCondition& completion_condition, WriteHandler& handler)+ : detail::base_from_completion_cond<+ CompletionCondition>(completion_condition),+ device_(device),+ offset_(offset),+ buffers_(buffers),+ start_(0),+ handler_(ASIO_MOVE_CAST(WriteHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ write_at_op(const write_at_op& other)+ : detail::base_from_completion_cond<CompletionCondition>(other),+ device_(other.device_),+ offset_(other.offset_),+ buffers_(other.buffers_),+ start_(other.start_),+ handler_(other.handler_)+ {+ }++ write_at_op(write_at_op&& other)+ : detail::base_from_completion_cond<CompletionCondition>(+ ASIO_MOVE_CAST(detail::base_from_completion_cond<+ CompletionCondition>)(other)),+ device_(other.device_),+ offset_(other.offset_),+ buffers_(ASIO_MOVE_CAST(buffers_type)(other.buffers_)),+ start_(other.start_),+ handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ std::size_t bytes_transferred, int start = 0)+ {+ std::size_t max_size;+ switch (start_ = start)+ {+ case 1:+ max_size = this->check_for_completion(ec, buffers_.total_consumed());+ do+ {+ {+ ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_write_at"));+ device_.async_write_some_at(+ offset_ + buffers_.total_consumed(), buffers_.prepare(max_size),+ ASIO_MOVE_CAST(write_at_op)(*this));+ }+ return; default:+ buffers_.consume(bytes_transferred);+ if ((!ec && bytes_transferred == 0) || buffers_.empty())+ break;+ max_size = this->check_for_completion(ec, buffers_.total_consumed());+ } while (max_size > 0);++ handler_(ec, buffers_.total_consumed());+ }+ }++ //private:+ typedef asio::detail::consuming_buffers<const_buffer,+ ConstBufferSequence, ConstBufferIterator> buffers_type;++ AsyncRandomAccessWriteDevice& device_;+ uint64_t offset_;+ buffers_type buffers_;+ int start_;+ WriteHandler handler_;+ };++ template <typename AsyncRandomAccessWriteDevice,+ typename ConstBufferSequence, typename ConstBufferIterator,+ typename CompletionCondition, typename WriteHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncRandomAccessWriteDevice,+ typename ConstBufferSequence, typename ConstBufferIterator,+ typename CompletionCondition, typename WriteHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncRandomAccessWriteDevice,+ typename ConstBufferSequence, typename ConstBufferIterator,+ typename CompletionCondition, typename WriteHandler>+ inline bool asio_handler_is_continuation(+ write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)+ {+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename AsyncRandomAccessWriteDevice,+ typename ConstBufferSequence, typename ConstBufferIterator,+ typename CompletionCondition, typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename AsyncRandomAccessWriteDevice,+ typename ConstBufferSequence, typename ConstBufferIterator,+ typename CompletionCondition, typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncRandomAccessWriteDevice,+ typename ConstBufferSequence, typename ConstBufferIterator,+ typename CompletionCondition, typename WriteHandler>+ inline void start_write_at_buffer_sequence_op(AsyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers,+ const ConstBufferIterator&, CompletionCondition& completion_condition,+ WriteHandler& handler)+ {+ detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>(+ d, offset, buffers, completion_condition, handler)(+ asio::error_code(), 0, 1);+ }++ template <typename AsyncRandomAccessWriteDevice>+ class initiate_async_write_at_buffer_sequence+ {+ public:+ typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type;++ explicit initiate_async_write_at_buffer_sequence(+ AsyncRandomAccessWriteDevice& device)+ : device_(device)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return device_.get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence,+ typename CompletionCondition>+ void operator()(ASIO_MOVE_ARG(WriteHandler) handler,+ uint64_t offset, const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(CompletionCondition) completion_cond) 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;++ non_const_lvalue<WriteHandler> handler2(handler);+ non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);+ start_write_at_buffer_sequence_op(device_, offset, buffers,+ asio::buffer_sequence_begin(buffers),+ completion_cond2.value, handler2.value);+ }++ private:+ AsyncRandomAccessWriteDevice& device_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename AsyncRandomAccessWriteDevice,+ typename ConstBufferSequence, typename ConstBufferIterator,+ typename CompletionCondition, typename WriteHandler, typename Allocator>+struct associated_allocator<+ detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>,+ Allocator>+{+ typedef typename associated_allocator<WriteHandler, Allocator>::type type;++ static type get(+ const detail::write_at_op<AsyncRandomAccessWriteDevice,+ ConstBufferSequence, ConstBufferIterator,+ CompletionCondition, WriteHandler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);+ }+};++template <typename AsyncRandomAccessWriteDevice,+ typename ConstBufferSequence, typename ConstBufferIterator,+ typename CompletionCondition, typename WriteHandler, typename Executor>+struct associated_executor<+ detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,+ ConstBufferIterator, CompletionCondition, WriteHandler>,+ Executor>+ : detail::associated_executor_forwarding_base<WriteHandler, Executor>+{+ typedef typename associated_executor<WriteHandler, Executor>::type type;++ static type get(+ const detail::write_at_op<AsyncRandomAccessWriteDevice,+ ConstBufferSequence, ConstBufferIterator,+ CompletionCondition, WriteHandler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncRandomAccessWriteDevice,+ typename ConstBufferSequence, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write_at(AsyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler)+{+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_write_at_buffer_sequence<+ AsyncRandomAccessWriteDevice>(d),+ handler, offset, buffers,+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write_at(AsyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler)+{+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_write_at_buffer_sequence<+ AsyncRandomAccessWriteDevice>(d),+ handler, offset, buffers, transfer_all());+}++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++namespace detail+{+ template <typename Allocator, typename WriteHandler>+ class write_at_streambuf_op+ {+ public:+ write_at_streambuf_op(+ asio::basic_streambuf<Allocator>& streambuf,+ WriteHandler& handler)+ : streambuf_(streambuf),+ handler_(ASIO_MOVE_CAST(WriteHandler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ write_at_streambuf_op(const write_at_streambuf_op& other)+ : streambuf_(other.streambuf_),+ handler_(other.handler_)+ {+ }++ write_at_streambuf_op(write_at_streambuf_op&& other)+ : streambuf_(other.streambuf_),+ handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(const asio::error_code& ec,+ const std::size_t bytes_transferred)+ {+ streambuf_.consume(bytes_transferred);+ handler_(ec, bytes_transferred);+ }++ //private:+ asio::basic_streambuf<Allocator>& streambuf_;+ WriteHandler handler_;+ };++ template <typename Allocator, typename WriteHandler>+ inline asio_handler_allocate_is_deprecated+ asio_handler_allocate(std::size_t size,+ write_at_streambuf_op<Allocator, WriteHandler>* this_handler)+ {+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Allocator, typename WriteHandler>+ inline asio_handler_deallocate_is_deprecated+ asio_handler_deallocate(void* pointer, std::size_t size,+ write_at_streambuf_op<Allocator, WriteHandler>* this_handler)+ {+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Allocator, typename WriteHandler>+ inline bool asio_handler_is_continuation(+ write_at_streambuf_op<Allocator, WriteHandler>* this_handler)+ {+ return asio_handler_cont_helpers::is_continuation(+ this_handler->handler_);+ }++ template <typename Function, typename Allocator, typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(Function& function,+ write_at_streambuf_op<Allocator, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename Function, typename Allocator, typename WriteHandler>+ inline asio_handler_invoke_is_deprecated+ asio_handler_invoke(const Function& function,+ write_at_streambuf_op<Allocator, WriteHandler>* this_handler)+ {+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+ }++ template <typename AsyncRandomAccessWriteDevice>+ class initiate_async_write_at_streambuf+ {+ public:+ typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type;++ explicit initiate_async_write_at_streambuf(+ AsyncRandomAccessWriteDevice& device)+ : device_(device)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return device_.get_executor();+ }++ template <typename WriteHandler,+ typename Allocator, typename CompletionCondition>+ void operator()(ASIO_MOVE_ARG(WriteHandler) handler,+ uint64_t offset, basic_streambuf<Allocator>* b,+ ASIO_MOVE_ARG(CompletionCondition) completion_condition) 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;++ non_const_lvalue<WriteHandler> handler2(handler);+ async_write_at(device_, offset, b->data(),+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition),+ write_at_streambuf_op<Allocator, typename decay<WriteHandler>::type>(+ *b, handler2.value));+ }++ private:+ AsyncRandomAccessWriteDevice& device_;+ };+} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++template <typename Allocator, typename WriteHandler, typename Allocator1>+struct associated_allocator<+ detail::write_at_streambuf_op<Allocator, WriteHandler>,+ Allocator1>+{+ typedef typename associated_allocator<WriteHandler, Allocator1>::type type;++ static type get(+ const detail::write_at_streambuf_op<Allocator, WriteHandler>& h,+ const Allocator1& a = Allocator1()) ASIO_NOEXCEPT+ {+ return associated_allocator<WriteHandler, Allocator1>::get(h.handler_, a);+ }+};++template <typename Executor, typename WriteHandler, typename Executor1>+struct associated_executor<+ detail::write_at_streambuf_op<Executor, WriteHandler>,+ Executor1>+ : detail::associated_executor_forwarding_base<WriteHandler, Executor>+{+ typedef typename associated_executor<WriteHandler, Executor1>::type type;++ static type get(+ const detail::write_at_streambuf_op<Executor, WriteHandler>& h,+ const Executor1& ex = Executor1()) ASIO_NOEXCEPT+ {+ return associated_executor<WriteHandler, Executor1>::get(h.handler_, ex);+ }+};++#endif // !defined(GENERATING_DOCUMENTATION)++template <typename AsyncRandomAccessWriteDevice,+ typename Allocator, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write_at(AsyncRandomAccessWriteDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler)+{+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_write_at_streambuf<+ AsyncRandomAccessWriteDevice>(d),+ handler, offset, &b,+ ASIO_MOVE_CAST(CompletionCondition)(completion_condition));+}++template <typename AsyncRandomAccessWriteDevice, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+inline ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write_at(AsyncRandomAccessWriteDevice& d,+ uint64_t offset, asio::basic_streambuf<Allocator>& b,+ ASIO_MOVE_ARG(WriteHandler) handler)+{+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ detail::initiate_async_write_at_streambuf<+ AsyncRandomAccessWriteDevice>(d),+ handler, offset, &b, transfer_all());+}++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IMPL_WRITE_AT_HPP
+ link/modules/asio-standalone/asio/include/asio/io_context.hpp view
@@ -0,0 +1,1530 @@+//+// io_context.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IO_CONTEXT_HPP+#define ASIO_IO_CONTEXT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include <stdexcept>+#include <typeinfo>+#include "asio/async_result.hpp"+#include "asio/detail/wrapped_handler.hpp"+#include "asio/error_code.hpp"+#include "asio/execution.hpp"+#include "asio/execution_context.hpp"++#if defined(ASIO_HAS_CHRONO)+# include "asio/detail/chrono.hpp"+#endif // defined(ASIO_HAS_CHRONO)++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# include "asio/detail/winsock_init.hpp"+#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \+ || defined(__osf__)+# include "asio/detail/signal_init.hpp"+#endif++#if defined(ASIO_HAS_IOCP)+# include "asio/detail/win_iocp_io_context.hpp"+#else+# include "asio/detail/scheduler.hpp"+#endif++#include "asio/detail/push_options.hpp"++namespace asio {++namespace detail {+#if defined(ASIO_HAS_IOCP)+ typedef win_iocp_io_context io_context_impl;+ class win_iocp_overlapped_ptr;+#else+ typedef scheduler io_context_impl;+#endif++ struct io_context_bits+ {+ ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1);+ ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 2);+ ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 4);+ };+} // namespace detail++/// Provides core I/O functionality.+/**+ * The io_context class provides the core I/O functionality for users of the+ * asynchronous I/O objects, including:+ *+ * @li asio::ip::tcp::socket+ * @li asio::ip::tcp::acceptor+ * @li asio::ip::udp::socket+ * @li asio::deadline_timer.+ *+ * The io_context class also includes facilities intended for developers of+ * custom asynchronous services.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Safe, with the specific exceptions of the restart()+ * and notify_fork() functions. Calling restart() while there are unfinished+ * run(), run_one(), run_for(), run_until(), poll() or poll_one() calls results+ * in undefined behaviour. The notify_fork() function should not be called+ * while any io_context function, or any function on an I/O object that is+ * associated with the io_context, is being called in another thread.+ *+ * @par Concepts:+ * Dispatcher.+ *+ * @par Synchronous and asynchronous operations+ *+ * Synchronous operations on I/O objects implicitly run the io_context object+ * for an individual operation. The io_context functions run(), run_one(),+ * run_for(), run_until(), poll() or poll_one() must be called for the+ * io_context to perform asynchronous operations on behalf of a C++ program.+ * Notification that an asynchronous operation has completed is delivered by+ * invocation of the associated handler. Handlers are invoked only by a thread+ * that is currently calling any overload of run(), run_one(), run_for(),+ * run_until(), poll() or poll_one() for the io_context.+ *+ * @par Effect of exceptions thrown from handlers+ *+ * If an exception is thrown from a handler, the exception is allowed to+ * propagate through the throwing thread's invocation of run(), run_one(),+ * run_for(), run_until(), poll() or poll_one(). No other threads that are+ * calling any of these functions are affected. It is then the responsibility+ * of the application to catch the exception.+ *+ * After the exception has been caught, the run(), run_one(), run_for(),+ * run_until(), poll() or poll_one() call may be restarted @em without the need+ * for an intervening call to restart(). This allows the thread to rejoin the+ * io_context object's thread pool without impacting any other threads in the+ * pool.+ *+ * For example:+ *+ * @code+ * asio::io_context io_context;+ * ...+ * for (;;)+ * {+ * try+ * {+ * io_context.run();+ * break; // run() exited normally+ * }+ * catch (my_exception& e)+ * {+ * // Deal with exception as appropriate.+ * }+ * }+ * @endcode+ *+ * @par Submitting arbitrary tasks to the io_context+ *+ * To submit functions to the io_context, use the @ref asio::dispatch,+ * @ref asio::post or @ref asio::defer free functions.+ *+ * For example:+ *+ * @code void my_task()+ * {+ * ...+ * }+ *+ * ...+ *+ * asio::io_context io_context;+ *+ * // Submit a function to the io_context.+ * asio::post(io_context, my_task);+ *+ * // Submit a lambda object to the io_context.+ * asio::post(io_context,+ * []()+ * {+ * ...+ * });+ *+ * // Run the io_context until it runs out of work.+ * io_context.run(); @endcode+ *+ * @par Stopping the io_context from running out of work+ *+ * Some applications may need to prevent an io_context object's run() call from+ * returning when there is no more work to do. For example, the io_context may+ * be being run in a background thread that is launched prior to the+ * application's asynchronous operations. The run() call may be kept running by+ * creating an executor that tracks work against the io_context:+ *+ * @code asio::io_context io_context;+ * auto work = asio::require(io_context.get_executor(),+ * asio::execution::outstanding_work.tracked);+ * ... @endcode+ *+ * If using C++03, which lacks automatic variable type deduction, you may+ * compute the return type of the require call:+ *+ * @code asio::io_context io_context;+ * typename asio::require_result<+ * asio::io_context::executor_type,+ * asio::exeution::outstanding_work_t::tracked_t>+ * work = asio::require(io_context.get_executor(),+ * asio::execution::outstanding_work.tracked);+ * ... @endcode+ *+ * or store the result in the type-erasing executor wrapper, any_io_executor:+ *+ * @code asio::io_context io_context;+ * asio::any_io_executor work+ * = asio::require(io_context.get_executor(),+ * asio::execution::outstanding_work.tracked);+ * ... @endcode+ *+ * To effect a shutdown, the application will then need to call the io_context+ * object's stop() member function. This will cause the io_context run() call+ * to return as soon as possible, abandoning unfinished operations and without+ * permitting ready handlers to be dispatched.+ *+ * Alternatively, if the application requires that all operations and handlers+ * be allowed to finish normally, store the work-tracking executor in an+ * any_io_executor object, so that it may be explicitly reset.+ *+ * @code asio::io_context io_context;+ * asio::any_io_executor work+ * = asio::require(io_context.get_executor(),+ * asio::execution::outstanding_work.tracked);+ * ...+ * work = asio::any_io_executor(); // Allow run() to exit. @endcode+ */+class io_context+ : public execution_context+{+private:+ typedef detail::io_context_impl impl_type;+#if defined(ASIO_HAS_IOCP)+ friend class detail::win_iocp_overlapped_ptr;+#endif++public:+ template <typename Allocator, unsigned int Bits>+ class basic_executor_type;++ template <typename Allocator, unsigned int Bits>+ friend class basic_executor_type;++ /// Executor used to submit functions to an io_context.+ typedef basic_executor_type<std::allocator<void>, 0> executor_type;++#if !defined(ASIO_NO_DEPRECATED)+ class work;+ friend class work;+#endif // !defined(ASIO_NO_DEPRECATED)++ class service;++#if !defined(ASIO_NO_EXTENSIONS) \+ && !defined(ASIO_NO_TS_EXECUTORS)+ class strand;+#endif // !defined(ASIO_NO_EXTENSIONS)+ // && !defined(ASIO_NO_TS_EXECUTORS)++ /// The type used to count the number of handlers executed by the context.+ typedef std::size_t count_type;++ /// Constructor.+ ASIO_DECL io_context();++ /// Constructor.+ /**+ * Construct with a hint about the required level of concurrency.+ *+ * @param concurrency_hint A suggestion to the implementation on how many+ * threads it should allow to run simultaneously.+ */+ ASIO_DECL explicit io_context(int concurrency_hint);++ /// Destructor.+ /**+ * On destruction, the io_context performs the following sequence of+ * operations:+ *+ * @li For each service object @c svc in the io_context set, in reverse order+ * of the beginning of service object lifetime, performs+ * @c svc->shutdown().+ *+ * @li Uninvoked handler objects that were scheduled for deferred invocation+ * on the io_context, or any associated strand, are destroyed.+ *+ * @li For each service object @c svc in the io_context set, in reverse order+ * of the beginning of service object lifetime, performs+ * <tt>delete static_cast<io_context::service*>(svc)</tt>.+ *+ * @note The destruction sequence described above permits programs to+ * simplify their resource management by using @c shared_ptr<>. Where an+ * object's lifetime is tied to the lifetime of a connection (or some other+ * sequence of asynchronous operations), a @c shared_ptr to the object would+ * be bound into the handlers for all asynchronous operations associated with+ * it. This works as follows:+ *+ * @li When a single connection ends, all associated asynchronous operations+ * complete. The corresponding handler objects are destroyed, and all+ * @c shared_ptr references to the objects are destroyed.+ *+ * @li To shut down the whole program, the io_context function stop() is+ * called to terminate any run() calls as soon as possible. The io_context+ * destructor defined above destroys all handlers, causing all @c shared_ptr+ * references to all connection objects to be destroyed.+ */+ ASIO_DECL ~io_context();++ /// Obtains the executor associated with the io_context.+ executor_type get_executor() ASIO_NOEXCEPT;++ /// Run the io_context object's event processing loop.+ /**+ * The run() function blocks until all work has finished and there are no+ * more handlers to be dispatched, or until the io_context has been stopped.+ *+ * Multiple threads may call the run() function to set up a pool of threads+ * from which the io_context may execute handlers. All threads that are+ * waiting in the pool are equivalent and the io_context may choose any one+ * of them to invoke a handler.+ *+ * A normal exit from the run() function implies that the io_context object+ * is stopped (the stopped() function returns @c true). Subsequent calls to+ * run(), run_one(), poll() or poll_one() will return immediately unless there+ * is a prior call to restart().+ *+ * @return The number of handlers that were executed.+ *+ * @note Calling the run() function from a thread that is currently calling+ * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on+ * the same io_context object may introduce the potential for deadlock. It is+ * the caller's reponsibility to avoid this.+ *+ * The poll() function may also be used to dispatch ready handlers, but+ * without blocking.+ */+ ASIO_DECL count_type run();++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use non-error_code overload.) Run the io_context object's+ /// event processing loop.+ /**+ * The run() function blocks until all work has finished and there are no+ * more handlers to be dispatched, or until the io_context has been stopped.+ *+ * Multiple threads may call the run() function to set up a pool of threads+ * from which the io_context may execute handlers. All threads that are+ * waiting in the pool are equivalent and the io_context may choose any one+ * of them to invoke a handler.+ *+ * A normal exit from the run() function implies that the io_context object+ * is stopped (the stopped() function returns @c true). Subsequent calls to+ * run(), run_one(), poll() or poll_one() will return immediately unless there+ * is a prior call to restart().+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of handlers that were executed.+ *+ * @note Calling the run() function from a thread that is currently calling+ * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on+ * the same io_context object may introduce the potential for deadlock. It is+ * the caller's reponsibility to avoid this.+ *+ * The poll() function may also be used to dispatch ready handlers, but+ * without blocking.+ */+ ASIO_DECL count_type run(asio::error_code& ec);+#endif // !defined(ASIO_NO_DEPRECATED)++#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)+ /// Run the io_context object's event processing loop for a specified+ /// duration.+ /**+ * The run_for() function blocks until all work has finished and there are no+ * more handlers to be dispatched, until the io_context has been stopped, or+ * until the specified duration has elapsed.+ *+ * @param rel_time The duration for which the call may block.+ *+ * @return The number of handlers that were executed.+ */+ template <typename Rep, typename Period>+ std::size_t run_for(const chrono::duration<Rep, Period>& rel_time);++ /// Run the io_context object's event processing loop until a specified time.+ /**+ * The run_until() function blocks until all work has finished and there are+ * no more handlers to be dispatched, until the io_context has been stopped,+ * or until the specified time has been reached.+ *+ * @param abs_time The time point until which the call may block.+ *+ * @return The number of handlers that were executed.+ */+ template <typename Clock, typename Duration>+ std::size_t run_until(const chrono::time_point<Clock, Duration>& abs_time);+#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)++ /// Run the io_context object's event processing loop to execute at most one+ /// handler.+ /**+ * The run_one() function blocks until one handler has been dispatched, or+ * until the io_context has been stopped.+ *+ * @return The number of handlers that were executed. A zero return value+ * implies that the io_context object is stopped (the stopped() function+ * returns @c true). Subsequent calls to run(), run_one(), poll() or+ * poll_one() will return immediately unless there is a prior call to+ * restart().+ *+ * @note Calling the run_one() function from a thread that is currently+ * calling one of run(), run_one(), run_for(), run_until(), poll() or+ * poll_one() on the same io_context object may introduce the potential for+ * deadlock. It is the caller's reponsibility to avoid this.+ */+ ASIO_DECL count_type run_one();++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use non-error_code overlaod.) Run the io_context object's+ /// event processing loop to execute at most one handler.+ /**+ * The run_one() function blocks until one handler has been dispatched, or+ * until the io_context has been stopped.+ *+ * @return The number of handlers that were executed. A zero return value+ * implies that the io_context object is stopped (the stopped() function+ * returns @c true). Subsequent calls to run(), run_one(), poll() or+ * poll_one() will return immediately unless there is a prior call to+ * restart().+ *+ * @return The number of handlers that were executed.+ *+ * @note Calling the run_one() function from a thread that is currently+ * calling one of run(), run_one(), run_for(), run_until(), poll() or+ * poll_one() on the same io_context object may introduce the potential for+ * deadlock. It is the caller's reponsibility to avoid this.+ */+ ASIO_DECL count_type run_one(asio::error_code& ec);+#endif // !defined(ASIO_NO_DEPRECATED)++#if defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)+ /// Run the io_context object's event processing loop for a specified duration+ /// to execute at most one handler.+ /**+ * The run_one_for() function blocks until one handler has been dispatched,+ * until the io_context has been stopped, or until the specified duration has+ * elapsed.+ *+ * @param rel_time The duration for which the call may block.+ *+ * @return The number of handlers that were executed.+ */+ template <typename Rep, typename Period>+ std::size_t run_one_for(const chrono::duration<Rep, Period>& rel_time);++ /// Run the io_context object's event processing loop until a specified time+ /// to execute at most one handler.+ /**+ * The run_one_until() function blocks until one handler has been dispatched,+ * until the io_context has been stopped, or until the specified time has+ * been reached.+ *+ * @param abs_time The time point until which the call may block.+ *+ * @return The number of handlers that were executed.+ */+ template <typename Clock, typename Duration>+ std::size_t run_one_until(+ const chrono::time_point<Clock, Duration>& abs_time);+#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)++ /// Run the io_context object's event processing loop to execute ready+ /// handlers.+ /**+ * The poll() function runs handlers that are ready to run, without blocking,+ * until the io_context has been stopped or there are no more ready handlers.+ *+ * @return The number of handlers that were executed.+ */+ ASIO_DECL count_type poll();++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use non-error_code overload.) Run the io_context object's+ /// event processing loop to execute ready handlers.+ /**+ * The poll() function runs handlers that are ready to run, without blocking,+ * until the io_context has been stopped or there are no more ready handlers.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of handlers that were executed.+ */+ ASIO_DECL count_type poll(asio::error_code& ec);+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Run the io_context object's event processing loop to execute one ready+ /// handler.+ /**+ * The poll_one() function runs at most one handler that is ready to run,+ * without blocking.+ *+ * @return The number of handlers that were executed.+ */+ ASIO_DECL count_type poll_one();++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use non-error_code overload.) Run the io_context object's+ /// event processing loop to execute one ready handler.+ /**+ * The poll_one() function runs at most one handler that is ready to run,+ * without blocking.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @return The number of handlers that were executed.+ */+ ASIO_DECL count_type poll_one(asio::error_code& ec);+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Stop the io_context object's event processing loop.+ /**+ * This function does not block, but instead simply signals the io_context to+ * stop. All invocations of its run() or run_one() member functions should+ * return as soon as possible. Subsequent calls to run(), run_one(), poll()+ * or poll_one() will return immediately until restart() is called.+ */+ ASIO_DECL void stop();++ /// Determine whether the io_context object has been stopped.+ /**+ * This function is used to determine whether an io_context object has been+ * stopped, either through an explicit call to stop(), or due to running out+ * of work. When an io_context object is stopped, calls to run(), run_one(),+ * poll() or poll_one() will return immediately without invoking any+ * handlers.+ *+ * @return @c true if the io_context object is stopped, otherwise @c false.+ */+ ASIO_DECL bool stopped() const;++ /// Restart the io_context in preparation for a subsequent run() invocation.+ /**+ * This function must be called prior to any second or later set of+ * invocations of the run(), run_one(), poll() or poll_one() functions when a+ * previous invocation of these functions returned due to the io_context+ * being stopped or running out of work. After a call to restart(), the+ * io_context object's stopped() function will return @c false.+ *+ * This function must not be called while there are any unfinished calls to+ * the run(), run_one(), poll() or poll_one() functions.+ */+ ASIO_DECL void restart();++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use restart().) Reset the io_context in preparation for a+ /// subsequent run() invocation.+ /**+ * This function must be called prior to any second or later set of+ * invocations of the run(), run_one(), poll() or poll_one() functions when a+ * previous invocation of these functions returned due to the io_context+ * being stopped or running out of work. After a call to restart(), the+ * io_context object's stopped() function will return @c false.+ *+ * This function must not be called while there are any unfinished calls to+ * the run(), run_one(), poll() or poll_one() functions.+ */+ void reset();++ /// (Deprecated: Use asio::dispatch().) Request the io_context to+ /// invoke the given handler.+ /**+ * This function is used to ask the io_context to execute the given handler.+ *+ * The io_context guarantees that the handler will only be called in a thread+ * in which the run(), run_one(), poll() or poll_one() member functions is+ * currently being invoked. The handler may be executed inside this function+ * if the guarantee can be met.+ *+ * @param handler The handler to be called. The io_context will make+ * a copy of the handler object as required. The function signature of the+ * handler must be: @code void handler(); @endcode+ *+ * @note This function throws an exception only if:+ *+ * @li the handler's @c asio_handler_allocate function; or+ *+ * @li the handler's copy constructor+ *+ * throws an exception.+ */+ template <typename LegacyCompletionHandler>+ ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())+ dispatch(ASIO_MOVE_ARG(LegacyCompletionHandler) handler);++ /// (Deprecated: Use asio::post().) Request the io_context to invoke+ /// the given handler and return immediately.+ /**+ * This function is used to ask the io_context to execute the given handler,+ * but without allowing the io_context to call the handler from inside this+ * function.+ *+ * The io_context guarantees that the handler will only be called in a thread+ * in which the run(), run_one(), poll() or poll_one() member functions is+ * currently being invoked.+ *+ * @param handler The handler to be called. The io_context will make+ * a copy of the handler object as required. The function signature of the+ * handler must be: @code void handler(); @endcode+ *+ * @note This function throws an exception only if:+ *+ * @li the handler's @c asio_handler_allocate function; or+ *+ * @li the handler's copy constructor+ *+ * throws an exception.+ */+ template <typename LegacyCompletionHandler>+ ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())+ post(ASIO_MOVE_ARG(LegacyCompletionHandler) handler);++ /// (Deprecated: Use asio::bind_executor().) Create a new handler that+ /// automatically dispatches the wrapped handler on the io_context.+ /**+ * This function is used to create a new handler function object that, when+ * invoked, will automatically pass the wrapped handler to the io_context+ * object's dispatch function.+ *+ * @param handler The handler to be wrapped. The io_context will make a copy+ * of the handler object as required. The function signature of the handler+ * must be: @code void handler(A1 a1, ... An an); @endcode+ *+ * @return A function object that, when invoked, passes the wrapped handler to+ * the io_context object's dispatch function. Given a function object with the+ * signature:+ * @code R f(A1 a1, ... An an); @endcode+ * If this function object is passed to the wrap function like so:+ * @code io_context.wrap(f); @endcode+ * then the return value is a function object with the signature+ * @code void g(A1 a1, ... An an); @endcode+ * that, when invoked, executes code equivalent to:+ * @code io_context.dispatch(boost::bind(f, a1, ... an)); @endcode+ */+ template <typename Handler>+#if defined(GENERATING_DOCUMENTATION)+ unspecified+#else+ detail::wrapped_handler<io_context&, Handler>+#endif+ wrap(Handler handler);+#endif // !defined(ASIO_NO_DEPRECATED)++private:+ io_context(const io_context&) ASIO_DELETED;+ io_context& operator=(const io_context&) ASIO_DELETED;++#if !defined(ASIO_NO_DEPRECATED)+ struct initiate_dispatch;+ struct initiate_post;+#endif // !defined(ASIO_NO_DEPRECATED)++ // Helper function to add the implementation.+ ASIO_DECL impl_type& add_impl(impl_type* impl);++ // Backwards compatible overload for use with services derived from+ // io_context::service.+ template <typename Service>+ friend Service& use_service(io_context& ioc);++#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ detail::winsock_init<> init_;+#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \+ || defined(__osf__)+ detail::signal_init<> init_;+#endif++ // The implementation.+ impl_type& impl_;+};++namespace detail {++} // namespace detail++/// Executor implementation type used to submit functions to an io_context.+template <typename Allocator, unsigned int Bits>+class io_context::basic_executor_type : detail::io_context_bits+{+public:+ /// Copy constructor.+ basic_executor_type(+ const basic_executor_type& other) ASIO_NOEXCEPT+ : io_context_(other.io_context_),+ allocator_(other.allocator_),+ bits_(other.bits_)+ {+ if (Bits & outstanding_work_tracked)+ if (io_context_)+ io_context_->impl_.work_started();+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move constructor.+ basic_executor_type(basic_executor_type&& other) ASIO_NOEXCEPT+ : io_context_(other.io_context_),+ allocator_(ASIO_MOVE_CAST(Allocator)(other.allocator_)),+ bits_(other.bits_)+ {+ if (Bits & outstanding_work_tracked)+ other.io_context_ = 0;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destructor.+ ~basic_executor_type() ASIO_NOEXCEPT+ {+ if (Bits & outstanding_work_tracked)+ if (io_context_)+ io_context_->impl_.work_finished();+ }++ /// Assignment operator.+ basic_executor_type& operator=(+ const basic_executor_type& other) ASIO_NOEXCEPT;++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move assignment operator.+ basic_executor_type& operator=(+ basic_executor_type&& other) ASIO_NOEXCEPT;+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Obtain an executor with the @c blocking.possibly property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_io_context.get_executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::blocking.possibly); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type require(+ execution::blocking_t::possibly_t) const+ {+ return basic_executor_type(io_context_,+ allocator_, bits_ & ~blocking_never);+ }++ /// Obtain an executor with the @c blocking.never property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_io_context.get_executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::blocking.never); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type require(+ execution::blocking_t::never_t) const+ {+ return basic_executor_type(io_context_,+ allocator_, bits_ | blocking_never);+ }++ /// Obtain an executor with the @c relationship.fork property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_io_context.get_executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::relationship.fork); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type require(+ execution::relationship_t::fork_t) const+ {+ return basic_executor_type(io_context_,+ allocator_, bits_ & ~relationship_continuation);+ }++ /// Obtain an executor with the @c relationship.continuation property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_io_context.get_executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::relationship.continuation); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type require(+ execution::relationship_t::continuation_t) const+ {+ return basic_executor_type(io_context_,+ allocator_, bits_ | relationship_continuation);+ }++ /// Obtain an executor with the @c outstanding_work.tracked property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_io_context.get_executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::outstanding_work.tracked); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type<Allocator,+ ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)>+ require(execution::outstanding_work_t::tracked_t) const+ {+ return basic_executor_type<Allocator, Bits | outstanding_work_tracked>(+ io_context_, allocator_, bits_);+ }++ /// Obtain an executor with the @c outstanding_work.untracked property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_io_context.get_executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::outstanding_work.untracked); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type<Allocator,+ ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)>+ require(execution::outstanding_work_t::untracked_t) const+ {+ return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>(+ io_context_, allocator_, bits_);+ }++ /// Obtain an executor with the specified @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_io_context.get_executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::allocator(my_allocator)); @endcode+ */+ template <typename OtherAllocator>+ ASIO_CONSTEXPR basic_executor_type<OtherAllocator, Bits>+ require(execution::allocator_t<OtherAllocator> a) const+ {+ return basic_executor_type<OtherAllocator, Bits>(+ io_context_, a.value(), bits_);+ }++ /// Obtain an executor with the default @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_io_context.get_executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::allocator); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type<std::allocator<void>, Bits>+ require(execution::allocator_t<void>) const+ {+ return basic_executor_type<std::allocator<void>, Bits>(+ io_context_, std::allocator<void>(), bits_);+ }++ /// Query the current value of the @c mapping property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_io_context.get_executor();+ * if (asio::query(ex, asio::execution::mapping)+ * == asio::execution::mapping.thread)+ * ... @endcode+ */+ static ASIO_CONSTEXPR execution::mapping_t query(+ execution::mapping_t) ASIO_NOEXCEPT+ {+ return execution::mapping.thread;+ }++ /// Query the current value of the @c context property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_io_context.get_executor();+ * asio::io_context& ctx = asio::query(+ * ex, asio::execution::context); @endcode+ */+ io_context& query(execution::context_t) const ASIO_NOEXCEPT+ {+ return *io_context_;+ }++ /// Query the current value of the @c blocking property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_io_context.get_executor();+ * if (asio::query(ex, asio::execution::blocking)+ * == asio::execution::blocking.always)+ * ... @endcode+ */+ ASIO_CONSTEXPR execution::blocking_t query(+ execution::blocking_t) const ASIO_NOEXCEPT+ {+ return (bits_ & blocking_never)+ ? execution::blocking_t(execution::blocking.never)+ : execution::blocking_t(execution::blocking.possibly);+ }++ /// Query the current value of the @c relationship property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_io_context.get_executor();+ * if (asio::query(ex, asio::execution::relationship)+ * == asio::execution::relationship.continuation)+ * ... @endcode+ */+ ASIO_CONSTEXPR execution::relationship_t query(+ execution::relationship_t) const ASIO_NOEXCEPT+ {+ return (bits_ & relationship_continuation)+ ? execution::relationship_t(execution::relationship.continuation)+ : execution::relationship_t(execution::relationship.fork);+ }++ /// Query the current value of the @c outstanding_work property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_io_context.get_executor();+ * if (asio::query(ex, asio::execution::outstanding_work)+ * == asio::execution::outstanding_work.tracked)+ * ... @endcode+ */+ static ASIO_CONSTEXPR execution::outstanding_work_t query(+ execution::outstanding_work_t) ASIO_NOEXCEPT+ {+ return (Bits & outstanding_work_tracked)+ ? execution::outstanding_work_t(execution::outstanding_work.tracked)+ : execution::outstanding_work_t(execution::outstanding_work.untracked);+ }++ /// Query the current value of the @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_io_context.get_executor();+ * auto alloc = asio::query(ex,+ * asio::execution::allocator); @endcode+ */+ template <typename OtherAllocator>+ ASIO_CONSTEXPR Allocator query(+ execution::allocator_t<OtherAllocator>) const ASIO_NOEXCEPT+ {+ return allocator_;+ }++ /// Query the current value of the @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_io_context.get_executor();+ * auto alloc = asio::query(ex,+ * asio::execution::allocator); @endcode+ */+ ASIO_CONSTEXPR Allocator query(+ execution::allocator_t<void>) const ASIO_NOEXCEPT+ {+ return allocator_;+ }++ /// Determine whether the io_context is running in the current thread.+ /**+ * @return @c true if the current thread is running the io_context. Otherwise+ * returns @c false.+ */+ bool running_in_this_thread() const ASIO_NOEXCEPT;++ /// Compare two executors for equality.+ /**+ * Two executors are equal if they refer to the same underlying io_context.+ */+ friend bool operator==(const basic_executor_type& a,+ const basic_executor_type& b) ASIO_NOEXCEPT+ {+ return a.io_context_ == b.io_context_+ && a.allocator_ == b.allocator_+ && a.bits_ == b.bits_;+ }++ /// Compare two executors for inequality.+ /**+ * Two executors are equal if they refer to the same underlying io_context.+ */+ friend bool operator!=(const basic_executor_type& a,+ const basic_executor_type& b) ASIO_NOEXCEPT+ {+ return a.io_context_ != b.io_context_+ || a.allocator_ != b.allocator_+ || a.bits_ != b.bits_;+ }++ /// Execution function.+ /**+ * Do not call this function directly. It is intended for use with the+ * execution::execute customisation point.+ *+ * For example:+ * @code auto ex = my_io_context.get_executor();+ * execution::execute(ex, my_function_object); @endcode+ */+ template <typename Function>+ void execute(ASIO_MOVE_ARG(Function) f) const;++#if !defined(ASIO_NO_TS_EXECUTORS)+ /// Obtain the underlying execution context.+ io_context& context() const ASIO_NOEXCEPT;++ /// Inform the io_context that it has some outstanding work to do.+ /**+ * This function is used to inform the io_context that some work has begun.+ * This ensures that the io_context's run() and run_one() functions do not+ * exit while the work is underway.+ */+ void on_work_started() const ASIO_NOEXCEPT;++ /// Inform the io_context that some work is no longer outstanding.+ /**+ * This function is used to inform the io_context that some work has+ * finished. Once the count of unfinished work reaches zero, the io_context+ * is stopped and the run() and run_one() functions may exit.+ */+ void on_work_finished() const ASIO_NOEXCEPT;++ /// Request the io_context to invoke the given function object.+ /**+ * This function is used to ask the io_context to execute the given function+ * object. If the current thread is running the io_context, @c dispatch()+ * executes the function before returning. Otherwise, the function will be+ * scheduled to run on the io_context.+ *+ * @param f The function object to be called. The executor will make a copy+ * of the handler object as required. The function signature of the function+ * object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename OtherAllocator>+ void dispatch(ASIO_MOVE_ARG(Function) f,+ const OtherAllocator& a) const;++ /// Request the io_context to invoke the given function object.+ /**+ * This function is used to ask the io_context to execute the given function+ * object. The function object will never be executed inside @c post().+ * Instead, it will be scheduled to run on the io_context.+ *+ * @param f The function object to be called. The executor will make a copy+ * of the handler object as required. The function signature of the function+ * object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename OtherAllocator>+ void post(ASIO_MOVE_ARG(Function) f,+ const OtherAllocator& a) const;++ /// Request the io_context to invoke the given function object.+ /**+ * This function is used to ask the io_context to execute the given function+ * object. The function object will never be executed inside @c defer().+ * Instead, it will be scheduled to run on the io_context.+ *+ * If the current thread belongs to the io_context, @c defer() will delay+ * scheduling the function object until the current thread returns control to+ * the pool.+ *+ * @param f The function object to be called. The executor will make a copy+ * of the handler object as required. The function signature of the function+ * object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename OtherAllocator>+ void defer(ASIO_MOVE_ARG(Function) f,+ const OtherAllocator& a) const;+#endif // !defined(ASIO_NO_TS_EXECUTORS)++private:+ friend class io_context;+ template <typename, unsigned int> friend class basic_executor_type;++ // Constructor used by io_context::get_executor().+ explicit basic_executor_type(io_context& i) ASIO_NOEXCEPT+ : io_context_(&i),+ allocator_(),+ bits_(0)+ {+ if (Bits & outstanding_work_tracked)+ io_context_->impl_.work_started();+ }++ // Constructor used by require().+ basic_executor_type(io_context* i,+ const Allocator& a, unsigned int bits) ASIO_NOEXCEPT+ : io_context_(i),+ allocator_(a),+ bits_(bits)+ {+ if (Bits & outstanding_work_tracked)+ if (io_context_)+ io_context_->impl_.work_started();+ }++ // The underlying io_context.+ io_context* io_context_;++ // The allocator used for execution functions.+ Allocator allocator_;++ // The runtime-switched properties of the io_context executor.+ unsigned int bits_;+};++#if !defined(ASIO_NO_DEPRECATED)+/// (Deprecated: Use executor_work_guard.) Class to inform the io_context when+/// it has work to do.+/**+ * The work class is used to inform the io_context when work starts and+ * finishes. This ensures that the io_context object's run() function will not+ * exit while work is underway, and that it does exit when there is no+ * unfinished work remaining.+ *+ * The work class is copy-constructible so that it may be used as a data member+ * in a handler class. It is not assignable.+ */+class io_context::work+{+public:+ /// Constructor notifies the io_context that work is starting.+ /**+ * The constructor is used to inform the io_context that some work has begun.+ * This ensures that the io_context object's run() function will not exit+ * while the work is underway.+ */+ explicit work(asio::io_context& io_context);++ /// Copy constructor notifies the io_context that work is starting.+ /**+ * The constructor is used to inform the io_context that some work has begun.+ * This ensures that the io_context object's run() function will not exit+ * while the work is underway.+ */+ work(const work& other);++ /// Destructor notifies the io_context that the work is complete.+ /**+ * The destructor is used to inform the io_context that some work has+ * finished. Once the count of unfinished work reaches zero, the io_context+ * object's run() function is permitted to exit.+ */+ ~work();++ /// Get the io_context associated with the work.+ asio::io_context& get_io_context();++private:+ // Prevent assignment.+ void operator=(const work& other);++ // The io_context implementation.+ detail::io_context_impl& io_context_impl_;+};+#endif // !defined(ASIO_NO_DEPRECATED)++/// Base class for all io_context services.+class io_context::service+ : public execution_context::service+{+public:+ /// Get the io_context object that owns the service.+ asio::io_context& get_io_context();++private:+ /// Destroy all user-defined handler objects owned by the service.+ ASIO_DECL virtual void shutdown();++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use shutdown().) Destroy all user-defined handler objects+ /// owned by the service.+ ASIO_DECL virtual void shutdown_service();+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Handle notification of a fork-related event to perform any necessary+ /// housekeeping.+ /**+ * This function is not a pure virtual so that services only have to+ * implement it if necessary. The default implementation does nothing.+ */+ ASIO_DECL virtual void notify_fork(+ execution_context::fork_event event);++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use notify_fork().) Handle notification of a fork-related+ /// event to perform any necessary housekeeping.+ /**+ * This function is not a pure virtual so that services only have to+ * implement it if necessary. The default implementation does nothing.+ */+ ASIO_DECL virtual void fork_service(+ execution_context::fork_event event);+#endif // !defined(ASIO_NO_DEPRECATED)++protected:+ /// Constructor.+ /**+ * @param owner The io_context object that owns the service.+ */+ ASIO_DECL service(asio::io_context& owner);++ /// Destructor.+ ASIO_DECL virtual ~service();+};++namespace detail {++// Special service base class to keep classes header-file only.+template <typename Type>+class service_base+ : public asio::io_context::service+{+public:+ static asio::detail::service_id<Type> id;++ // Constructor.+ service_base(asio::io_context& io_context)+ : asio::io_context::service(io_context)+ {+ }+};++template <typename Type>+asio::detail::service_id<Type> service_base<Type>::id;++} // namespace detail++#if !defined(GENERATING_DOCUMENTATION)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++template <typename Allocator, unsigned int Bits>+struct equality_comparable<+ asio::io_context::basic_executor_type<Allocator, Bits>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+};++#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++template <typename Allocator, unsigned int Bits, typename Function>+struct execute_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ Function+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ asio::execution::blocking_t::possibly_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::io_context::basic_executor_type<+ Allocator, Bits> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ asio::execution::blocking_t::never_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::io_context::basic_executor_type<+ Allocator, Bits> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ asio::execution::relationship_t::fork_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::io_context::basic_executor_type<+ Allocator, Bits> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ asio::execution::relationship_t::continuation_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::io_context::basic_executor_type<+ Allocator, Bits> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ asio::execution::outstanding_work_t::tracked_t+ > : asio::detail::io_context_bits+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::io_context::basic_executor_type<+ Allocator, Bits | outstanding_work_tracked> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ asio::execution::outstanding_work_t::untracked_t+ > : asio::detail::io_context_bits+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::io_context::basic_executor_type<+ Allocator, Bits & ~outstanding_work_tracked> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ asio::execution::allocator_t<void>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::io_context::basic_executor_type<+ std::allocator<void>, Bits> result_type;+};++template <unsigned int Bits,+ typename Allocator, typename OtherAllocator>+struct require_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ asio::execution::allocator_t<OtherAllocator>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::io_context::basic_executor_type<+ OtherAllocator, Bits> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++template <typename Allocator, unsigned int Bits, typename Property>+struct query_static_constexpr_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::outstanding_work_t+ >::value+ >::type+ > : asio::detail::io_context_bits+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::outstanding_work_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return (Bits & outstanding_work_tracked)+ ? execution::outstanding_work_t(execution::outstanding_work.tracked)+ : execution::outstanding_work_t(execution::outstanding_work.untracked);+ }+};++template <typename Allocator, unsigned int Bits, typename Property>+struct query_static_constexpr_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::mapping_t+ >::value+ >::type+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::mapping_t::thread_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return result_type();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++template <typename Allocator, unsigned int Bits, typename Property>+struct query_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::blocking_t+ >::value+ >::type+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::blocking_t result_type;+};++template <typename Allocator, unsigned int Bits, typename Property>+struct query_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::relationship_t+ >::value+ >::type+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::relationship_t result_type;+};++template <typename Allocator, unsigned int Bits>+struct query_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ asio::execution::context_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::io_context& result_type;+};++template <typename Allocator, unsigned int Bits>+struct query_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ asio::execution::allocator_t<void>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef Allocator result_type;+};++template <typename Allocator, unsigned int Bits, typename OtherAllocator>+struct query_member<+ asio::io_context::basic_executor_type<Allocator, Bits>,+ asio::execution::allocator_t<OtherAllocator>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef Allocator result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++} // namespace traits++#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/io_context.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/impl/io_context.ipp"+#endif // defined(ASIO_HEADER_ONLY)++// If both io_context.hpp and strand.hpp have been included, automatically+// include the header file needed for the io_context::strand class.+#if !defined(ASIO_NO_EXTENSIONS)+# if defined(ASIO_STRAND_HPP)+# include "asio/io_context_strand.hpp"+# endif // defined(ASIO_STRAND_HPP)+#endif // !defined(ASIO_NO_EXTENSIONS)++#endif // ASIO_IO_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/io_context_strand.hpp view
@@ -0,0 +1,376 @@+//+// io_context_strand.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IO_CONTEXT_STRAND_HPP+#define ASIO_IO_CONTEXT_STRAND_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_NO_EXTENSIONS) \+ && !defined(ASIO_NO_TS_EXECUTORS)++#include "asio/async_result.hpp"+#include "asio/detail/handler_type_requirements.hpp"+#include "asio/detail/strand_service.hpp"+#include "asio/detail/wrapped_handler.hpp"+#include "asio/io_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Provides serialised handler execution.+/**+ * The io_context::strand class provides the ability to post and dispatch+ * handlers with the guarantee that none of those handlers will execute+ * concurrently.+ *+ * @par Order of handler invocation+ * Given:+ *+ * @li a strand object @c s+ *+ * @li an object @c a meeting completion handler requirements+ *+ * @li an object @c a1 which is an arbitrary copy of @c a made by the+ * implementation+ *+ * @li an object @c b meeting completion handler requirements+ *+ * @li an object @c b1 which is an arbitrary copy of @c b made by the+ * implementation+ *+ * if any of the following conditions are true:+ *+ * @li @c s.post(a) happens-before @c s.post(b)+ * + * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is+ * performed outside the strand+ * + * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is+ * performed outside the strand+ * + * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are+ * performed outside the strand+ * + * then @c asio_handler_invoke(a1, &a1) happens-before+ * @c asio_handler_invoke(b1, &b1).+ * + * Note that in the following case:+ * @code async_op_1(..., s.wrap(a));+ * async_op_2(..., s.wrap(b)); @endcode+ * the completion of the first async operation will perform @c s.dispatch(a),+ * and the second will perform @c s.dispatch(b), but the order in which those+ * are performed is unspecified. That is, you cannot state whether one+ * happens-before the other. Therefore none of the above conditions are met and+ * no ordering guarantee is made.+ *+ * @note The implementation makes no guarantee that handlers posted or+ * dispatched through different @c strand objects will be invoked concurrently.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Safe.+ *+ * @par Concepts:+ * Dispatcher.+ */+class io_context::strand+{+public:+ /// Constructor.+ /**+ * Constructs the strand.+ *+ * @param io_context The io_context object that the strand will use to+ * dispatch handlers that are ready to be run.+ */+ explicit strand(asio::io_context& io_context)+ : service_(asio::use_service<+ asio::detail::strand_service>(io_context))+ {+ service_.construct(impl_);+ }++ /// Destructor.+ /**+ * Destroys a strand.+ *+ * Handlers posted through the strand that have not yet been invoked will+ * still be dispatched in a way that meets the guarantee of non-concurrency.+ */+ ~strand()+ {+ }++ /// Obtain the underlying execution context.+ asio::io_context& context() const ASIO_NOEXCEPT+ {+ return service_.get_io_context();+ }++ /// Inform the strand that it has some outstanding work to do.+ /**+ * The strand delegates this call to its underlying io_context.+ */+ void on_work_started() const ASIO_NOEXCEPT+ {+ context().get_executor().on_work_started();+ }++ /// Inform the strand that some work is no longer outstanding.+ /**+ * The strand delegates this call to its underlying io_context.+ */+ void on_work_finished() const ASIO_NOEXCEPT+ {+ context().get_executor().on_work_finished();+ }++ /// Request the strand to invoke the given function object.+ /**+ * This function is used to ask the strand to execute the given function+ * object on its underlying io_context. The function object will be executed+ * inside this function if the strand is not otherwise busy and if the+ * underlying io_context's executor's @c dispatch() function is also able to+ * execute the function before returning.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename Allocator>+ void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const+ {+ typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f));+ service_.dispatch(impl_, tmp);+ (void)a;+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use asio::dispatch().) Request the strand to invoke+ /// the given handler.+ /**+ * This function is used to ask the strand to execute the given handler.+ *+ * The strand object guarantees that handlers posted or dispatched through+ * the strand will not be executed concurrently. The handler may be executed+ * inside this function if the guarantee can be met. If this function is+ * called from within a handler that was posted or dispatched through the same+ * strand, then the new handler will be executed immediately.+ *+ * The strand's guarantee is in addition to the guarantee provided by the+ * underlying io_context. The io_context guarantees that the handler will only+ * be called in a thread in which the io_context's run member function is+ * currently being invoked.+ *+ * @param handler The handler to be called. The strand will make a copy of the+ * handler object as required. The function signature of the handler must be:+ * @code void handler(); @endcode+ */+ template <typename LegacyCompletionHandler>+ ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())+ dispatch(ASIO_MOVE_ARG(LegacyCompletionHandler) handler)+ {+ return async_initiate<LegacyCompletionHandler, void ()>(+ initiate_dispatch(), handler, this);+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Request the strand to invoke the given function object.+ /**+ * This function is used to ask the executor to execute the given function+ * object. The function object will never be executed inside this function.+ * Instead, it will be scheduled to run by the underlying io_context.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename Allocator>+ void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const+ {+ typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f));+ service_.post(impl_, tmp);+ (void)a;+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use asio::post().) Request the strand to invoke the+ /// given handler and return immediately.+ /**+ * This function is used to ask the strand to execute the given handler, but+ * without allowing the strand to call the handler from inside this function.+ *+ * The strand object guarantees that handlers posted or dispatched through+ * the strand will not be executed concurrently. The strand's guarantee is in+ * addition to the guarantee provided by the underlying io_context. The+ * io_context guarantees that the handler will only be called in a thread in+ * which the io_context's run member function is currently being invoked.+ *+ * @param handler The handler to be called. The strand will make a copy of the+ * handler object as required. The function signature of the handler must be:+ * @code void handler(); @endcode+ */+ template <typename LegacyCompletionHandler>+ ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ())+ post(ASIO_MOVE_ARG(LegacyCompletionHandler) handler)+ {+ return async_initiate<LegacyCompletionHandler, void ()>(+ initiate_post(), handler, this);+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Request the strand to invoke the given function object.+ /**+ * This function is used to ask the executor to execute the given function+ * object. The function object will never be executed inside this function.+ * Instead, it will be scheduled to run by the underlying io_context.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename Allocator>+ void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const+ {+ typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f));+ service_.post(impl_, tmp);+ (void)a;+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use asio::bind_executor().) Create a new handler that+ /// automatically dispatches the wrapped handler on the strand.+ /**+ * This function is used to create a new handler function object that, when+ * invoked, will automatically pass the wrapped handler to the strand's+ * dispatch function.+ *+ * @param handler The handler to be wrapped. The strand will make a copy of+ * the handler object as required. The function signature of the handler must+ * be: @code void handler(A1 a1, ... An an); @endcode+ *+ * @return A function object that, when invoked, passes the wrapped handler to+ * the strand's dispatch function. Given a function object with the signature:+ * @code R f(A1 a1, ... An an); @endcode+ * If this function object is passed to the wrap function like so:+ * @code strand.wrap(f); @endcode+ * then the return value is a function object with the signature+ * @code void g(A1 a1, ... An an); @endcode+ * that, when invoked, executes code equivalent to:+ * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode+ */+ template <typename Handler>+#if defined(GENERATING_DOCUMENTATION)+ unspecified+#else+ detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running>+#endif+ wrap(Handler handler)+ {+ return detail::wrapped_handler<io_context::strand, Handler,+ detail::is_continuation_if_running>(*this, handler);+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Determine whether the strand is running in the current thread.+ /**+ * @return @c true if the current thread is executing a handler that was+ * submitted to the strand using post(), dispatch() or wrap(). Otherwise+ * returns @c false.+ */+ bool running_in_this_thread() const ASIO_NOEXCEPT+ {+ return service_.running_in_this_thread(impl_);+ }++ /// Compare two strands for equality.+ /**+ * Two strands are equal if they refer to the same ordered, non-concurrent+ * state.+ */+ friend bool operator==(const strand& a, const strand& b) ASIO_NOEXCEPT+ {+ return a.impl_ == b.impl_;+ }++ /// Compare two strands for inequality.+ /**+ * Two strands are equal if they refer to the same ordered, non-concurrent+ * state.+ */+ friend bool operator!=(const strand& a, const strand& b) ASIO_NOEXCEPT+ {+ return a.impl_ != b.impl_;+ }++private:+#if !defined(ASIO_NO_DEPRECATED)+ struct initiate_dispatch+ {+ template <typename LegacyCompletionHandler>+ void operator()(ASIO_MOVE_ARG(LegacyCompletionHandler) handler,+ strand* self) const+ {+ // If you get an error on the following line it means that your+ // handler does not meet the documented type requirements for a+ // LegacyCompletionHandler.+ ASIO_LEGACY_COMPLETION_HANDLER_CHECK(+ LegacyCompletionHandler, handler) type_check;++ detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);+ self->service_.dispatch(self->impl_, handler2.value);+ }+ };++ struct initiate_post+ {+ template <typename LegacyCompletionHandler>+ void operator()(ASIO_MOVE_ARG(LegacyCompletionHandler) handler,+ strand* self) const+ {+ // If you get an error on the following line it means that your+ // handler does not meet the documented type requirements for a+ // LegacyCompletionHandler.+ ASIO_LEGACY_COMPLETION_HANDLER_CHECK(+ LegacyCompletionHandler, handler) type_check;++ detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);+ self->service_.post(self->impl_, handler2.value);+ }+ };+#endif // !defined(ASIO_NO_DEPRECATED)++ asio::detail::strand_service& service_;+ mutable asio::detail::strand_service::implementation_type impl_;+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_EXTENSIONS)+ // && !defined(ASIO_NO_TS_EXECUTORS)++#endif // ASIO_IO_CONTEXT_STRAND_HPP
+ link/modules/asio-standalone/asio/include/asio/io_service.hpp view
@@ -0,0 +1,33 @@+//+// io_service.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IO_SERVICE_HPP+#define ASIO_IO_SERVICE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/io_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if !defined(ASIO_NO_DEPRECATED)+/// Typedef for backwards compatibility.+typedef io_context io_service;+#endif // !defined(ASIO_NO_DEPRECATED)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IO_SERVICE_HPP
+ link/modules/asio-standalone/asio/include/asio/io_service_strand.hpp view
@@ -0,0 +1,20 @@+//+// io_service_strand.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IO_SERVICE_STRAND_HPP+#define ASIO_IO_SERVICE_STRAND_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/io_context_strand.hpp"++#endif // ASIO_IO_SERVICE_STRAND_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/address.hpp view
@@ -0,0 +1,268 @@+//+// ip/address.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_ADDRESS_HPP+#define ASIO_IP_ADDRESS_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <string>+#include "asio/detail/throw_exception.hpp"+#include "asio/detail/string_view.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/error_code.hpp"+#include "asio/ip/address_v4.hpp"+#include "asio/ip/address_v6.hpp"+#include "asio/ip/bad_address_cast.hpp"++#if !defined(ASIO_NO_IOSTREAM)+# include <iosfwd>+#endif // !defined(ASIO_NO_IOSTREAM)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// Implements version-independent IP addresses.+/**+ * The asio::ip::address class provides the ability to use either IP+ * version 4 or version 6 addresses.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+class address+{+public:+ /// Default constructor.+ ASIO_DECL address() ASIO_NOEXCEPT;++ /// Construct an address from an IPv4 address.+ ASIO_DECL address(+ const asio::ip::address_v4& ipv4_address) ASIO_NOEXCEPT;++ /// Construct an address from an IPv6 address.+ ASIO_DECL address(+ const asio::ip::address_v6& ipv6_address) ASIO_NOEXCEPT;++ /// Copy constructor.+ ASIO_DECL address(const address& other) ASIO_NOEXCEPT;++#if defined(ASIO_HAS_MOVE)+ /// Move constructor.+ ASIO_DECL address(address&& other) ASIO_NOEXCEPT;+#endif // defined(ASIO_HAS_MOVE)++ /// Assign from another address.+ ASIO_DECL address& operator=(const address& other) ASIO_NOEXCEPT;++#if defined(ASIO_HAS_MOVE)+ /// Move-assign from another address.+ ASIO_DECL address& operator=(address&& other) ASIO_NOEXCEPT;+#endif // defined(ASIO_HAS_MOVE)++ /// Assign from an IPv4 address.+ ASIO_DECL address& operator=(+ const asio::ip::address_v4& ipv4_address) ASIO_NOEXCEPT;++ /// Assign from an IPv6 address.+ ASIO_DECL address& operator=(+ const asio::ip::address_v6& ipv6_address) ASIO_NOEXCEPT;++ /// Get whether the address is an IP version 4 address.+ bool is_v4() const ASIO_NOEXCEPT+ {+ return type_ == ipv4;+ }++ /// Get whether the address is an IP version 6 address.+ bool is_v6() const ASIO_NOEXCEPT+ {+ return type_ == ipv6;+ }++ /// Get the address as an IP version 4 address.+ ASIO_DECL asio::ip::address_v4 to_v4() const;++ /// Get the address as an IP version 6 address.+ ASIO_DECL asio::ip::address_v6 to_v6() const;++ /// Get the address as a string.+ ASIO_DECL std::string to_string() const;++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use other overload.) Get the address as a string.+ ASIO_DECL std::string to_string(asio::error_code& ec) const;++ /// (Deprecated: Use make_address().) Create an address from an IPv4 address+ /// string in dotted decimal form, or from an IPv6 address in hexadecimal+ /// notation.+ static address from_string(const char* str);++ /// (Deprecated: Use make_address().) Create an address from an IPv4 address+ /// string in dotted decimal form, or from an IPv6 address in hexadecimal+ /// notation.+ static address from_string(const char* str, asio::error_code& ec);++ /// (Deprecated: Use make_address().) Create an address from an IPv4 address+ /// string in dotted decimal form, or from an IPv6 address in hexadecimal+ /// notation.+ static address from_string(const std::string& str);++ /// (Deprecated: Use make_address().) Create an address from an IPv4 address+ /// string in dotted decimal form, or from an IPv6 address in hexadecimal+ /// notation.+ static address from_string(+ const std::string& str, asio::error_code& ec);+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Determine whether the address is a loopback address.+ ASIO_DECL bool is_loopback() const ASIO_NOEXCEPT;++ /// Determine whether the address is unspecified.+ ASIO_DECL bool is_unspecified() const ASIO_NOEXCEPT;++ /// Determine whether the address is a multicast address.+ ASIO_DECL bool is_multicast() const ASIO_NOEXCEPT;++ /// Compare two addresses for equality.+ ASIO_DECL friend bool operator==(const address& a1,+ const address& a2) ASIO_NOEXCEPT;++ /// Compare two addresses for inequality.+ friend bool operator!=(const address& a1,+ const address& a2) ASIO_NOEXCEPT+ {+ return !(a1 == a2);+ }++ /// Compare addresses for ordering.+ ASIO_DECL friend bool operator<(const address& a1,+ const address& a2) ASIO_NOEXCEPT;++ /// Compare addresses for ordering.+ friend bool operator>(const address& a1,+ const address& a2) ASIO_NOEXCEPT+ {+ return a2 < a1;+ }++ /// Compare addresses for ordering.+ friend bool operator<=(const address& a1,+ const address& a2) ASIO_NOEXCEPT+ {+ return !(a2 < a1);+ }++ /// Compare addresses for ordering.+ friend bool operator>=(const address& a1,+ const address& a2) ASIO_NOEXCEPT+ {+ return !(a1 < a2);+ }++private:+ // The type of the address.+ enum { ipv4, ipv6 } type_;++ // The underlying IPv4 address.+ asio::ip::address_v4 ipv4_address_;++ // The underlying IPv6 address.+ asio::ip::address_v6 ipv6_address_;+};++/// Create an address from an IPv4 address string in dotted decimal form,+/// or from an IPv6 address in hexadecimal notation.+/**+ * @relates address+ */+ASIO_DECL address make_address(const char* str);++/// Create an address from an IPv4 address string in dotted decimal form,+/// or from an IPv6 address in hexadecimal notation.+/**+ * @relates address+ */+ASIO_DECL address make_address(const char* str,+ asio::error_code& ec) ASIO_NOEXCEPT;++/// Create an address from an IPv4 address string in dotted decimal form,+/// or from an IPv6 address in hexadecimal notation.+/**+ * @relates address+ */+ASIO_DECL address make_address(const std::string& str);++/// Create an address from an IPv4 address string in dotted decimal form,+/// or from an IPv6 address in hexadecimal notation.+/**+ * @relates address+ */+ASIO_DECL address make_address(const std::string& str,+ asio::error_code& ec) ASIO_NOEXCEPT;++#if defined(ASIO_HAS_STRING_VIEW) \+ || defined(GENERATING_DOCUMENTATION)++/// Create an address from an IPv4 address string in dotted decimal form,+/// or from an IPv6 address in hexadecimal notation.+/**+ * @relates address+ */+ASIO_DECL address make_address(string_view str);++/// Create an address from an IPv4 address string in dotted decimal form,+/// or from an IPv6 address in hexadecimal notation.+/**+ * @relates address+ */+ASIO_DECL address make_address(string_view str,+ asio::error_code& ec) ASIO_NOEXCEPT;++#endif // defined(ASIO_HAS_STRING_VIEW)+ // || defined(GENERATING_DOCUMENTATION)++#if !defined(ASIO_NO_IOSTREAM)++/// Output an address as a string.+/**+ * Used to output a human-readable string for a specified address.+ *+ * @param os The output stream to which the string will be written.+ *+ * @param addr The address to be written.+ *+ * @return The output stream.+ *+ * @relates asio::ip::address+ */+template <typename Elem, typename Traits>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os, const address& addr);++#endif // !defined(ASIO_NO_IOSTREAM)++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/ip/impl/address.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/ip/impl/address.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_IP_ADDRESS_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/address_v4.hpp view
@@ -0,0 +1,335 @@+//+// ip/address_v4.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_ADDRESS_V4_HPP+#define ASIO_IP_ADDRESS_V4_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <string>+#include "asio/detail/array.hpp"+#include "asio/detail/cstdint.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/string_view.hpp"+#include "asio/detail/winsock_init.hpp"+#include "asio/error_code.hpp"++#if !defined(ASIO_NO_IOSTREAM)+# include <iosfwd>+#endif // !defined(ASIO_NO_IOSTREAM)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// Implements IP version 4 style addresses.+/**+ * The asio::ip::address_v4 class provides the ability to use and+ * manipulate IP version 4 addresses.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+class address_v4+{+public:+ /// The type used to represent an address as an unsigned integer.+ typedef uint_least32_t uint_type;++ /// The type used to represent an address as an array of bytes.+ /**+ * @note This type is defined in terms of the C++0x template @c std::array+ * when it is available. Otherwise, it uses @c boost:array.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef array<unsigned char, 4> bytes_type;+#else+ typedef asio::detail::array<unsigned char, 4> bytes_type;+#endif++ /// Default constructor.+ address_v4() ASIO_NOEXCEPT+ {+ addr_.s_addr = 0;+ }++ /// Construct an address from raw bytes.+ ASIO_DECL explicit address_v4(const bytes_type& bytes);++ /// Construct an address from an unsigned integer in host byte order.+ ASIO_DECL explicit address_v4(uint_type addr);++ /// Copy constructor.+ address_v4(const address_v4& other) ASIO_NOEXCEPT+ : addr_(other.addr_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ /// Move constructor.+ address_v4(address_v4&& other) ASIO_NOEXCEPT+ : addr_(other.addr_)+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Assign from another address.+ address_v4& operator=(const address_v4& other) ASIO_NOEXCEPT+ {+ addr_ = other.addr_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE)+ /// Move-assign from another address.+ address_v4& operator=(address_v4&& other) ASIO_NOEXCEPT+ {+ addr_ = other.addr_;+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Get the address in bytes, in network byte order.+ ASIO_DECL bytes_type to_bytes() const ASIO_NOEXCEPT;++ /// Get the address as an unsigned integer in host byte order+ ASIO_DECL uint_type to_uint() const ASIO_NOEXCEPT;++#if !defined(ASIO_NO_DEPRECATED)+ /// Get the address as an unsigned long in host byte order+ ASIO_DECL unsigned long to_ulong() const;+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Get the address as a string in dotted decimal format.+ ASIO_DECL std::string to_string() const;++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use other overload.) Get the address as a string in dotted+ /// decimal format.+ ASIO_DECL std::string to_string(asio::error_code& ec) const;++ /// (Deprecated: Use make_address_v4().) Create an address from an IP address+ /// string in dotted decimal form.+ static address_v4 from_string(const char* str);++ /// (Deprecated: Use make_address_v4().) Create an address from an IP address+ /// string in dotted decimal form.+ static address_v4 from_string(+ const char* str, asio::error_code& ec);++ /// (Deprecated: Use make_address_v4().) Create an address from an IP address+ /// string in dotted decimal form.+ static address_v4 from_string(const std::string& str);++ /// (Deprecated: Use make_address_v4().) Create an address from an IP address+ /// string in dotted decimal form.+ static address_v4 from_string(+ const std::string& str, asio::error_code& ec);+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Determine whether the address is a loopback address.+ ASIO_DECL bool is_loopback() const ASIO_NOEXCEPT;++ /// Determine whether the address is unspecified.+ ASIO_DECL bool is_unspecified() const ASIO_NOEXCEPT;++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use network_v4 class.) Determine whether the address is a+ /// class A address.+ ASIO_DECL bool is_class_a() const;++ /// (Deprecated: Use network_v4 class.) Determine whether the address is a+ /// class B address.+ ASIO_DECL bool is_class_b() const;++ /// (Deprecated: Use network_v4 class.) Determine whether the address is a+ /// class C address.+ ASIO_DECL bool is_class_c() const;+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Determine whether the address is a multicast address.+ ASIO_DECL bool is_multicast() const ASIO_NOEXCEPT;++ /// Compare two addresses for equality.+ friend bool operator==(const address_v4& a1,+ const address_v4& a2) ASIO_NOEXCEPT+ {+ return a1.addr_.s_addr == a2.addr_.s_addr;+ }++ /// Compare two addresses for inequality.+ friend bool operator!=(const address_v4& a1,+ const address_v4& a2) ASIO_NOEXCEPT+ {+ return a1.addr_.s_addr != a2.addr_.s_addr;+ }++ /// Compare addresses for ordering.+ friend bool operator<(const address_v4& a1,+ const address_v4& a2) ASIO_NOEXCEPT+ {+ return a1.to_uint() < a2.to_uint();+ }++ /// Compare addresses for ordering.+ friend bool operator>(const address_v4& a1,+ const address_v4& a2) ASIO_NOEXCEPT+ {+ return a1.to_uint() > a2.to_uint();+ }++ /// Compare addresses for ordering.+ friend bool operator<=(const address_v4& a1,+ const address_v4& a2) ASIO_NOEXCEPT+ {+ return a1.to_uint() <= a2.to_uint();+ }++ /// Compare addresses for ordering.+ friend bool operator>=(const address_v4& a1,+ const address_v4& a2) ASIO_NOEXCEPT+ {+ return a1.to_uint() >= a2.to_uint();+ }++ /// Obtain an address object that represents any address.+ static address_v4 any() ASIO_NOEXCEPT+ {+ return address_v4();+ }++ /// Obtain an address object that represents the loopback address.+ static address_v4 loopback() ASIO_NOEXCEPT+ {+ return address_v4(0x7F000001);+ }++ /// Obtain an address object that represents the broadcast address.+ static address_v4 broadcast() ASIO_NOEXCEPT+ {+ return address_v4(0xFFFFFFFF);+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use network_v4 class.) Obtain an address object that+ /// represents the broadcast address that corresponds to the specified+ /// address and netmask.+ ASIO_DECL static address_v4 broadcast(+ const address_v4& addr, const address_v4& mask);++ /// (Deprecated: Use network_v4 class.) Obtain the netmask that corresponds+ /// to the address, based on its address class.+ ASIO_DECL static address_v4 netmask(const address_v4& addr);+#endif // !defined(ASIO_NO_DEPRECATED)++private:+ // The underlying IPv4 address.+ asio::detail::in4_addr_type addr_;+};++/// Create an IPv4 address from raw bytes in network order.+/**+ * @relates address_v4+ */+inline address_v4 make_address_v4(const address_v4::bytes_type& bytes)+{+ return address_v4(bytes);+}++/// Create an IPv4 address from an unsigned integer in host byte order.+/**+ * @relates address_v4+ */+inline address_v4 make_address_v4(address_v4::uint_type addr)+{+ return address_v4(addr);+}++/// Create an IPv4 address from an IP address string in dotted decimal form.+/**+ * @relates address_v4+ */+ASIO_DECL address_v4 make_address_v4(const char* str);++/// Create an IPv4 address from an IP address string in dotted decimal form.+/**+ * @relates address_v4+ */+ASIO_DECL address_v4 make_address_v4(const char* str,+ asio::error_code& ec) ASIO_NOEXCEPT;++/// Create an IPv4 address from an IP address string in dotted decimal form.+/**+ * @relates address_v4+ */+ASIO_DECL address_v4 make_address_v4(const std::string& str);++/// Create an IPv4 address from an IP address string in dotted decimal form.+/**+ * @relates address_v4+ */+ASIO_DECL address_v4 make_address_v4(const std::string& str,+ asio::error_code& ec) ASIO_NOEXCEPT;++#if defined(ASIO_HAS_STRING_VIEW) \+ || defined(GENERATING_DOCUMENTATION)++/// Create an IPv4 address from an IP address string in dotted decimal form.+/**+ * @relates address_v4+ */+ASIO_DECL address_v4 make_address_v4(string_view str);++/// Create an IPv4 address from an IP address string in dotted decimal form.+/**+ * @relates address_v4+ */+ASIO_DECL address_v4 make_address_v4(string_view str,+ asio::error_code& ec) ASIO_NOEXCEPT;++#endif // defined(ASIO_HAS_STRING_VIEW)+ // || defined(GENERATING_DOCUMENTATION)++#if !defined(ASIO_NO_IOSTREAM)++/// Output an address as a string.+/**+ * Used to output a human-readable string for a specified address.+ *+ * @param os The output stream to which the string will be written.+ *+ * @param addr The address to be written.+ *+ * @return The output stream.+ *+ * @relates asio::ip::address_v4+ */+template <typename Elem, typename Traits>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os, const address_v4& addr);++#endif // !defined(ASIO_NO_IOSTREAM)++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/ip/impl/address_v4.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/ip/impl/address_v4.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_IP_ADDRESS_V4_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/address_v4_iterator.hpp view
@@ -0,0 +1,162 @@+//+// ip/address_v4_iterator.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_ADDRESS_V4_ITERATOR_HPP+#define ASIO_IP_ADDRESS_V4_ITERATOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/ip/address_v4.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++template <typename> class basic_address_iterator;++/// An input iterator that can be used for traversing IPv4 addresses.+/**+ * In addition to satisfying the input iterator requirements, this iterator+ * also supports decrement.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <> class basic_address_iterator<address_v4>+{+public:+ /// The type of the elements pointed to by the iterator.+ typedef address_v4 value_type;++ /// Distance between two iterators.+ typedef std::ptrdiff_t difference_type;++ /// The type of a pointer to an element pointed to by the iterator.+ typedef const address_v4* pointer;++ /// The type of a reference to an element pointed to by the iterator.+ typedef const address_v4& reference;++ /// Denotes that the iterator satisfies the input iterator requirements.+ typedef std::input_iterator_tag iterator_category;++ /// Construct an iterator that points to the specified address.+ basic_address_iterator(const address_v4& addr) ASIO_NOEXCEPT+ : address_(addr)+ {+ }++ /// Copy constructor.+ basic_address_iterator(+ const basic_address_iterator& other) ASIO_NOEXCEPT+ : address_(other.address_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ /// Move constructor.+ basic_address_iterator(basic_address_iterator&& other) ASIO_NOEXCEPT+ : address_(ASIO_MOVE_CAST(address_v4)(other.address_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Assignment operator.+ basic_address_iterator& operator=(+ const basic_address_iterator& other) ASIO_NOEXCEPT+ {+ address_ = other.address_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE)+ /// Move assignment operator.+ basic_address_iterator& operator=(+ basic_address_iterator&& other) ASIO_NOEXCEPT+ {+ address_ = ASIO_MOVE_CAST(address_v4)(other.address_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Dereference the iterator.+ const address_v4& operator*() const ASIO_NOEXCEPT+ {+ return address_;+ }++ /// Dereference the iterator.+ const address_v4* operator->() const ASIO_NOEXCEPT+ {+ return &address_;+ }++ /// Pre-increment operator.+ basic_address_iterator& operator++() ASIO_NOEXCEPT+ {+ address_ = address_v4((address_.to_uint() + 1) & 0xFFFFFFFF);+ return *this;+ }++ /// Post-increment operator.+ basic_address_iterator operator++(int) ASIO_NOEXCEPT+ {+ basic_address_iterator tmp(*this);+ ++*this;+ return tmp;+ }++ /// Pre-decrement operator.+ basic_address_iterator& operator--() ASIO_NOEXCEPT+ {+ address_ = address_v4((address_.to_uint() - 1) & 0xFFFFFFFF);+ return *this;+ }++ /// Post-decrement operator.+ basic_address_iterator operator--(int)+ {+ basic_address_iterator tmp(*this);+ --*this;+ return tmp;+ }++ /// Compare two addresses for equality.+ friend bool operator==(const basic_address_iterator& a,+ const basic_address_iterator& b)+ {+ return a.address_ == b.address_;+ }++ /// Compare two addresses for inequality.+ friend bool operator!=(const basic_address_iterator& a,+ const basic_address_iterator& b)+ {+ return a.address_ != b.address_;+ }++private:+ address_v4 address_;+};++/// An input iterator that can be used for traversing IPv4 addresses.+typedef basic_address_iterator<address_v4> address_v4_iterator;++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_ADDRESS_V4_ITERATOR_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/address_v4_range.hpp view
@@ -0,0 +1,134 @@+//+// ip/address_v4_range.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_ADDRESS_V4_RANGE_HPP+#define ASIO_IP_ADDRESS_V4_RANGE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/ip/address_v4_iterator.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++template <typename> class basic_address_range;++/// Represents a range of IPv4 addresses.+/**+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <> class basic_address_range<address_v4>+{+public:+ /// The type of an iterator that points into the range.+ typedef basic_address_iterator<address_v4> iterator;++ /// Construct an empty range.+ basic_address_range() ASIO_NOEXCEPT+ : begin_(address_v4()),+ end_(address_v4())+ {+ }++ /// Construct an range that represents the given range of addresses.+ explicit basic_address_range(const iterator& first,+ const iterator& last) ASIO_NOEXCEPT+ : begin_(first),+ end_(last)+ {+ }++ /// Copy constructor.+ basic_address_range(const basic_address_range& other) ASIO_NOEXCEPT+ : begin_(other.begin_),+ end_(other.end_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ /// Move constructor.+ basic_address_range(basic_address_range&& other) ASIO_NOEXCEPT+ : begin_(ASIO_MOVE_CAST(iterator)(other.begin_)),+ end_(ASIO_MOVE_CAST(iterator)(other.end_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Assignment operator.+ basic_address_range& operator=(+ const basic_address_range& other) ASIO_NOEXCEPT+ {+ begin_ = other.begin_;+ end_ = other.end_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE)+ /// Move assignment operator.+ basic_address_range& operator=(+ basic_address_range&& other) ASIO_NOEXCEPT+ {+ begin_ = ASIO_MOVE_CAST(iterator)(other.begin_);+ end_ = ASIO_MOVE_CAST(iterator)(other.end_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Obtain an iterator that points to the start of the range.+ iterator begin() const ASIO_NOEXCEPT+ {+ return begin_;+ }++ /// Obtain an iterator that points to the end of the range.+ iterator end() const ASIO_NOEXCEPT+ {+ return end_;+ }++ /// Determine whether the range is empty.+ bool empty() const ASIO_NOEXCEPT+ {+ return size() == 0;+ }++ /// Return the size of the range.+ std::size_t size() const ASIO_NOEXCEPT+ {+ return end_->to_uint() - begin_->to_uint();+ }++ /// Find an address in the range.+ iterator find(const address_v4& addr) const ASIO_NOEXCEPT+ {+ return addr >= *begin_ && addr < *end_ ? iterator(addr) : end_;+ }++private:+ iterator begin_;+ iterator end_;+};++/// Represents a range of IPv4 addresses.+typedef basic_address_range<address_v4> address_v4_range;++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_ADDRESS_V4_RANGE_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/address_v6.hpp view
@@ -0,0 +1,341 @@+//+// ip/address_v6.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_ADDRESS_V6_HPP+#define ASIO_IP_ADDRESS_V6_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <string>+#include "asio/detail/array.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/string_view.hpp"+#include "asio/detail/winsock_init.hpp"+#include "asio/error_code.hpp"+#include "asio/ip/address_v4.hpp"++#if !defined(ASIO_NO_IOSTREAM)+# include <iosfwd>+#endif // !defined(ASIO_NO_IOSTREAM)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++template <typename> class basic_address_iterator;++/// Implements IP version 6 style addresses.+/**+ * The asio::ip::address_v6 class provides the ability to use and+ * manipulate IP version 6 addresses.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+class address_v6+{+public:+ /// The type used to represent an address as an array of bytes.+ /**+ * @note This type is defined in terms of the C++0x template @c std::array+ * when it is available. Otherwise, it uses @c boost:array.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef array<unsigned char, 16> bytes_type;+#else+ typedef asio::detail::array<unsigned char, 16> bytes_type;+#endif++ /// Default constructor.+ ASIO_DECL address_v6() ASIO_NOEXCEPT;++ /// Construct an address from raw bytes and scope ID.+ ASIO_DECL explicit address_v6(const bytes_type& bytes,+ unsigned long scope_id = 0);++ /// Copy constructor.+ ASIO_DECL address_v6(const address_v6& other) ASIO_NOEXCEPT;++#if defined(ASIO_HAS_MOVE)+ /// Move constructor.+ ASIO_DECL address_v6(address_v6&& other) ASIO_NOEXCEPT;+#endif // defined(ASIO_HAS_MOVE)++ /// Assign from another address.+ ASIO_DECL address_v6& operator=(+ const address_v6& other) ASIO_NOEXCEPT;++#if defined(ASIO_HAS_MOVE)+ /// Move-assign from another address.+ ASIO_DECL address_v6& operator=(address_v6&& other) ASIO_NOEXCEPT;+#endif // defined(ASIO_HAS_MOVE)++ /// The scope ID of the address.+ /**+ * Returns the scope ID associated with the IPv6 address.+ */+ unsigned long scope_id() const ASIO_NOEXCEPT+ {+ return scope_id_;+ }++ /// The scope ID of the address.+ /**+ * Modifies the scope ID associated with the IPv6 address.+ */+ void scope_id(unsigned long id) ASIO_NOEXCEPT+ {+ scope_id_ = id;+ }++ /// Get the address in bytes, in network byte order.+ ASIO_DECL bytes_type to_bytes() const ASIO_NOEXCEPT;++ /// Get the address as a string.+ ASIO_DECL std::string to_string() const;++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use other overload.) Get the address as a string.+ ASIO_DECL std::string to_string(asio::error_code& ec) const;++ /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP+ /// address string.+ static address_v6 from_string(const char* str);++ /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP+ /// address string.+ static address_v6 from_string(+ const char* str, asio::error_code& ec);++ /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP+ /// address string.+ static address_v6 from_string(const std::string& str);++ /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP+ /// address string.+ static address_v6 from_string(+ const std::string& str, asio::error_code& ec);++ /// (Deprecated: Use make_address_v4().) Converts an IPv4-mapped or+ /// IPv4-compatible address to an IPv4 address.+ ASIO_DECL address_v4 to_v4() const;+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Determine whether the address is a loopback address.+ ASIO_DECL bool is_loopback() const ASIO_NOEXCEPT;++ /// Determine whether the address is unspecified.+ ASIO_DECL bool is_unspecified() const ASIO_NOEXCEPT;++ /// Determine whether the address is link local.+ ASIO_DECL bool is_link_local() const ASIO_NOEXCEPT;++ /// Determine whether the address is site local.+ ASIO_DECL bool is_site_local() const ASIO_NOEXCEPT;++ /// Determine whether the address is a mapped IPv4 address.+ ASIO_DECL bool is_v4_mapped() const ASIO_NOEXCEPT;++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: No replacement.) Determine whether the address is an+ /// IPv4-compatible address.+ ASIO_DECL bool is_v4_compatible() const;+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Determine whether the address is a multicast address.+ ASIO_DECL bool is_multicast() const ASIO_NOEXCEPT;++ /// Determine whether the address is a global multicast address.+ ASIO_DECL bool is_multicast_global() const ASIO_NOEXCEPT;++ /// Determine whether the address is a link-local multicast address.+ ASIO_DECL bool is_multicast_link_local() const ASIO_NOEXCEPT;++ /// Determine whether the address is a node-local multicast address.+ ASIO_DECL bool is_multicast_node_local() const ASIO_NOEXCEPT;++ /// Determine whether the address is a org-local multicast address.+ ASIO_DECL bool is_multicast_org_local() const ASIO_NOEXCEPT;++ /// Determine whether the address is a site-local multicast address.+ ASIO_DECL bool is_multicast_site_local() const ASIO_NOEXCEPT;++ /// Compare two addresses for equality.+ ASIO_DECL friend bool operator==(const address_v6& a1,+ const address_v6& a2) ASIO_NOEXCEPT;++ /// Compare two addresses for inequality.+ friend bool operator!=(const address_v6& a1,+ const address_v6& a2) ASIO_NOEXCEPT+ {+ return !(a1 == a2);+ }++ /// Compare addresses for ordering.+ ASIO_DECL friend bool operator<(const address_v6& a1,+ const address_v6& a2) ASIO_NOEXCEPT;++ /// Compare addresses for ordering.+ friend bool operator>(const address_v6& a1,+ const address_v6& a2) ASIO_NOEXCEPT+ {+ return a2 < a1;+ }++ /// Compare addresses for ordering.+ friend bool operator<=(const address_v6& a1,+ const address_v6& a2) ASIO_NOEXCEPT+ {+ return !(a2 < a1);+ }++ /// Compare addresses for ordering.+ friend bool operator>=(const address_v6& a1,+ const address_v6& a2) ASIO_NOEXCEPT+ {+ return !(a1 < a2);+ }++ /// Obtain an address object that represents any address.+ static address_v6 any() ASIO_NOEXCEPT+ {+ return address_v6();+ }++ /// Obtain an address object that represents the loopback address.+ ASIO_DECL static address_v6 loopback() ASIO_NOEXCEPT;++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use make_address_v6().) Create an IPv4-mapped IPv6 address.+ ASIO_DECL static address_v6 v4_mapped(const address_v4& addr);++ /// (Deprecated: No replacement.) Create an IPv4-compatible IPv6 address.+ ASIO_DECL static address_v6 v4_compatible(const address_v4& addr);+#endif // !defined(ASIO_NO_DEPRECATED)++private:+ friend class basic_address_iterator<address_v6>;++ // The underlying IPv6 address.+ asio::detail::in6_addr_type addr_;++ // The scope ID associated with the address.+ unsigned long scope_id_;+};++/// Create an IPv6 address from raw bytes and scope ID.+/**+ * @relates address_v6+ */+inline address_v6 make_address_v6(const address_v6::bytes_type& bytes,+ unsigned long scope_id = 0)+{+ return address_v6(bytes, scope_id);+}++/// Create an IPv6 address from an IP address string.+/**+ * @relates address_v6+ */+ASIO_DECL address_v6 make_address_v6(const char* str);++/// Create an IPv6 address from an IP address string.+/**+ * @relates address_v6+ */+ASIO_DECL address_v6 make_address_v6(const char* str,+ asio::error_code& ec) ASIO_NOEXCEPT;++/// Createan IPv6 address from an IP address string.+/**+ * @relates address_v6+ */+ASIO_DECL address_v6 make_address_v6(const std::string& str);++/// Create an IPv6 address from an IP address string.+/**+ * @relates address_v6+ */+ASIO_DECL address_v6 make_address_v6(const std::string& str,+ asio::error_code& ec) ASIO_NOEXCEPT;++#if defined(ASIO_HAS_STRING_VIEW) \+ || defined(GENERATING_DOCUMENTATION)++/// Create an IPv6 address from an IP address string.+/**+ * @relates address_v6+ */+ASIO_DECL address_v6 make_address_v6(string_view str);++/// Create an IPv6 address from an IP address string.+/**+ * @relates address_v6+ */+ASIO_DECL address_v6 make_address_v6(string_view str,+ asio::error_code& ec) ASIO_NOEXCEPT;++#endif // defined(ASIO_HAS_STRING_VIEW)+ // || defined(GENERATING_DOCUMENTATION)++/// Tag type used for distinguishing overloads that deal in IPv4-mapped IPv6+/// addresses.+enum v4_mapped_t { v4_mapped };++/// Create an IPv4 address from a IPv4-mapped IPv6 address.+/**+ * @relates address_v4+ */+ASIO_DECL address_v4 make_address_v4(+ v4_mapped_t, const address_v6& v6_addr);++/// Create an IPv4-mapped IPv6 address from an IPv4 address.+/**+ * @relates address_v6+ */+ASIO_DECL address_v6 make_address_v6(+ v4_mapped_t, const address_v4& v4_addr);++#if !defined(ASIO_NO_IOSTREAM)++/// Output an address as a string.+/**+ * Used to output a human-readable string for a specified address.+ *+ * @param os The output stream to which the string will be written.+ *+ * @param addr The address to be written.+ *+ * @return The output stream.+ *+ * @relates asio::ip::address_v6+ */+template <typename Elem, typename Traits>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os, const address_v6& addr);++#endif // !defined(ASIO_NO_IOSTREAM)++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/ip/impl/address_v6.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/ip/impl/address_v6.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_IP_ADDRESS_V6_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/address_v6_iterator.hpp view
@@ -0,0 +1,183 @@+//+// ip/address_v6_iterator.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Oliver Kowalke (oliver dot kowalke at gmail 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_IP_ADDRESS_V6_ITERATOR_HPP+#define ASIO_IP_ADDRESS_V6_ITERATOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/ip/address_v6.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++template <typename> class basic_address_iterator;++/// An input iterator that can be used for traversing IPv6 addresses.+/**+ * In addition to satisfying the input iterator requirements, this iterator+ * also supports decrement.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <> class basic_address_iterator<address_v6>+{+public:+ /// The type of the elements pointed to by the iterator.+ typedef address_v6 value_type;++ /// Distance between two iterators.+ typedef std::ptrdiff_t difference_type;++ /// The type of a pointer to an element pointed to by the iterator.+ typedef const address_v6* pointer;++ /// The type of a reference to an element pointed to by the iterator.+ typedef const address_v6& reference;++ /// Denotes that the iterator satisfies the input iterator requirements.+ typedef std::input_iterator_tag iterator_category;++ /// Construct an iterator that points to the specified address.+ basic_address_iterator(const address_v6& addr) ASIO_NOEXCEPT+ : address_(addr)+ {+ }++ /// Copy constructor.+ basic_address_iterator(+ const basic_address_iterator& other) ASIO_NOEXCEPT+ : address_(other.address_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ /// Move constructor.+ basic_address_iterator(basic_address_iterator&& other) ASIO_NOEXCEPT+ : address_(ASIO_MOVE_CAST(address_v6)(other.address_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Assignment operator.+ basic_address_iterator& operator=(+ const basic_address_iterator& other) ASIO_NOEXCEPT+ {+ address_ = other.address_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE)+ /// Move assignment operator.+ basic_address_iterator& operator=(+ basic_address_iterator&& other) ASIO_NOEXCEPT+ {+ address_ = ASIO_MOVE_CAST(address_v6)(other.address_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Dereference the iterator.+ const address_v6& operator*() const ASIO_NOEXCEPT+ {+ return address_;+ }++ /// Dereference the iterator.+ const address_v6* operator->() const ASIO_NOEXCEPT+ {+ return &address_;+ }++ /// Pre-increment operator.+ basic_address_iterator& operator++() ASIO_NOEXCEPT+ {+ for (int i = 15; i >= 0; --i)+ {+ if (address_.addr_.s6_addr[i] < 0xFF)+ {+ ++address_.addr_.s6_addr[i];+ break;+ }++ address_.addr_.s6_addr[i] = 0;+ }++ return *this;+ }++ /// Post-increment operator.+ basic_address_iterator operator++(int) ASIO_NOEXCEPT+ {+ basic_address_iterator tmp(*this);+ ++*this;+ return tmp;+ }++ /// Pre-decrement operator.+ basic_address_iterator& operator--() ASIO_NOEXCEPT+ {+ for (int i = 15; i >= 0; --i)+ {+ if (address_.addr_.s6_addr[i] > 0)+ {+ --address_.addr_.s6_addr[i];+ break;+ }++ address_.addr_.s6_addr[i] = 0xFF;+ }++ return *this;+ }++ /// Post-decrement operator.+ basic_address_iterator operator--(int)+ {+ basic_address_iterator tmp(*this);+ --*this;+ return tmp;+ }++ /// Compare two addresses for equality.+ friend bool operator==(const basic_address_iterator& a,+ const basic_address_iterator& b)+ {+ return a.address_ == b.address_;+ }++ /// Compare two addresses for inequality.+ friend bool operator!=(const basic_address_iterator& a,+ const basic_address_iterator& b)+ {+ return a.address_ != b.address_;+ }++private:+ address_v6 address_;+};++/// An input iterator that can be used for traversing IPv6 addresses.+typedef basic_address_iterator<address_v6> address_v6_iterator;++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_ADDRESS_V6_ITERATOR_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/address_v6_range.hpp view
@@ -0,0 +1,129 @@+//+// ip/address_v6_range.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Oliver Kowalke (oliver dot kowalke at gmail 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_IP_ADDRESS_V6_RANGE_HPP+#define ASIO_IP_ADDRESS_V6_RANGE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/ip/address_v6_iterator.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++template <typename> class basic_address_range;++/// Represents a range of IPv6 addresses.+/**+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <> class basic_address_range<address_v6>+{+public:+ /// The type of an iterator that points into the range.+ typedef basic_address_iterator<address_v6> iterator;++ /// Construct an empty range.+ basic_address_range() ASIO_NOEXCEPT+ : begin_(address_v6()),+ end_(address_v6())+ {+ }++ /// Construct an range that represents the given range of addresses.+ explicit basic_address_range(const iterator& first,+ const iterator& last) ASIO_NOEXCEPT+ : begin_(first),+ end_(last)+ {+ }++ /// Copy constructor.+ basic_address_range(const basic_address_range& other) ASIO_NOEXCEPT+ : begin_(other.begin_),+ end_(other.end_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ /// Move constructor.+ basic_address_range(basic_address_range&& other) ASIO_NOEXCEPT+ : begin_(ASIO_MOVE_CAST(iterator)(other.begin_)),+ end_(ASIO_MOVE_CAST(iterator)(other.end_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Assignment operator.+ basic_address_range& operator=(+ const basic_address_range& other) ASIO_NOEXCEPT+ {+ begin_ = other.begin_;+ end_ = other.end_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE)+ /// Move assignment operator.+ basic_address_range& operator=(+ basic_address_range&& other) ASIO_NOEXCEPT+ {+ begin_ = ASIO_MOVE_CAST(iterator)(other.begin_);+ end_ = ASIO_MOVE_CAST(iterator)(other.end_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Obtain an iterator that points to the start of the range.+ iterator begin() const ASIO_NOEXCEPT+ {+ return begin_;+ }++ /// Obtain an iterator that points to the end of the range.+ iterator end() const ASIO_NOEXCEPT+ {+ return end_;+ }++ /// Determine whether the range is empty.+ bool empty() const ASIO_NOEXCEPT+ {+ return begin_ == end_;+ }++ /// Find an address in the range.+ iterator find(const address_v6& addr) const ASIO_NOEXCEPT+ {+ return addr >= *begin_ && addr < *end_ ? iterator(addr) : end_;+ }++private:+ iterator begin_;+ iterator end_;+};++/// Represents a range of IPv6 addresses.+typedef basic_address_range<address_v6> address_v6_range;++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_ADDRESS_V6_RANGE_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/bad_address_cast.hpp view
@@ -0,0 +1,53 @@+//+// ip/bad_address_cast.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_BAD_ADDRESS_CAST_HPP+#define ASIO_IP_BAD_ADDRESS_CAST_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <typeinfo>++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// Thrown to indicate a failed address conversion.+class bad_address_cast :+#if defined(ASIO_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS+ public std::exception+#else+ public std::bad_cast+#endif+{+public:+ /// Default constructor.+ bad_address_cast() {}++ /// Destructor.+ virtual ~bad_address_cast() ASIO_NOEXCEPT_OR_NOTHROW {}++ /// Get the message associated with the exception.+ virtual const char* what() const ASIO_NOEXCEPT_OR_NOTHROW+ {+ return "bad address cast";+ }+};++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_ADDRESS_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/basic_endpoint.hpp view
@@ -0,0 +1,264 @@+//+// ip/basic_endpoint.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_BASIC_ENDPOINT_HPP+#define ASIO_IP_BASIC_ENDPOINT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/ip/address.hpp"+#include "asio/ip/detail/endpoint.hpp"++#if !defined(ASIO_NO_IOSTREAM)+# include <iosfwd>+#endif // !defined(ASIO_NO_IOSTREAM)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// Describes an endpoint for a version-independent IP socket.+/**+ * The asio::ip::basic_endpoint class template describes an endpoint that+ * may be associated with a particular socket.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Concepts:+ * Endpoint.+ */+template <typename InternetProtocol>+class basic_endpoint+{+public:+ /// The protocol type associated with the endpoint.+ typedef InternetProtocol protocol_type;++ /// The type of the endpoint structure. This type is dependent on the+ /// underlying implementation of the socket layer.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined data_type;+#else+ typedef asio::detail::socket_addr_type data_type;+#endif++ /// Default constructor.+ basic_endpoint() ASIO_NOEXCEPT+ : impl_()+ {+ }++ /// Construct an endpoint using a port number, specified in the host's byte+ /// order. The IP address will be the any address (i.e. INADDR_ANY or+ /// in6addr_any). This constructor would typically be used for accepting new+ /// connections.+ /**+ * @par Examples+ * To initialise an IPv4 TCP endpoint for port 1234, use:+ * @code+ * asio::ip::tcp::endpoint ep(asio::ip::tcp::v4(), 1234);+ * @endcode+ *+ * To specify an IPv6 UDP endpoint for port 9876, use:+ * @code+ * asio::ip::udp::endpoint ep(asio::ip::udp::v6(), 9876);+ * @endcode+ */+ basic_endpoint(const InternetProtocol& internet_protocol,+ unsigned short port_num) ASIO_NOEXCEPT+ : impl_(internet_protocol.family(), port_num)+ {+ }++ /// Construct an endpoint using a port number and an IP address. This+ /// constructor may be used for accepting connections on a specific interface+ /// or for making a connection to a remote endpoint.+ basic_endpoint(const asio::ip::address& addr,+ unsigned short port_num) ASIO_NOEXCEPT+ : impl_(addr, port_num)+ {+ }++ /// Copy constructor.+ basic_endpoint(const basic_endpoint& other) ASIO_NOEXCEPT+ : impl_(other.impl_)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move constructor.+ basic_endpoint(basic_endpoint&& other) ASIO_NOEXCEPT+ : impl_(other.impl_)+ {+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Assign from another endpoint.+ basic_endpoint& operator=(const basic_endpoint& other) ASIO_NOEXCEPT+ {+ impl_ = other.impl_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-assign from another endpoint.+ basic_endpoint& operator=(basic_endpoint&& other) ASIO_NOEXCEPT+ {+ impl_ = other.impl_;+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// The protocol associated with the endpoint.+ protocol_type protocol() const ASIO_NOEXCEPT+ {+ if (impl_.is_v4())+ return InternetProtocol::v4();+ return InternetProtocol::v6();+ }++ /// Get the underlying endpoint in the native type.+ data_type* data() ASIO_NOEXCEPT+ {+ return impl_.data();+ }++ /// Get the underlying endpoint in the native type.+ const data_type* data() const ASIO_NOEXCEPT+ {+ return impl_.data();+ }++ /// Get the underlying size of the endpoint in the native type.+ std::size_t size() const ASIO_NOEXCEPT+ {+ return impl_.size();+ }++ /// Set the underlying size of the endpoint in the native type.+ void resize(std::size_t new_size)+ {+ impl_.resize(new_size);+ }++ /// Get the capacity of the endpoint in the native type.+ std::size_t capacity() const ASIO_NOEXCEPT+ {+ return impl_.capacity();+ }++ /// Get the port associated with the endpoint. The port number is always in+ /// the host's byte order.+ unsigned short port() const ASIO_NOEXCEPT+ {+ return impl_.port();+ }++ /// Set the port associated with the endpoint. The port number is always in+ /// the host's byte order.+ void port(unsigned short port_num) ASIO_NOEXCEPT+ {+ impl_.port(port_num);+ }++ /// Get the IP address associated with the endpoint.+ asio::ip::address address() const ASIO_NOEXCEPT+ {+ return impl_.address();+ }++ /// Set the IP address associated with the endpoint.+ void address(const asio::ip::address& addr) ASIO_NOEXCEPT+ {+ impl_.address(addr);+ }++ /// Compare two endpoints for equality.+ friend bool operator==(const basic_endpoint<InternetProtocol>& e1,+ const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT+ {+ return e1.impl_ == e2.impl_;+ }++ /// Compare two endpoints for inequality.+ friend bool operator!=(const basic_endpoint<InternetProtocol>& e1,+ const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT+ {+ return !(e1 == e2);+ }++ /// Compare endpoints for ordering.+ friend bool operator<(const basic_endpoint<InternetProtocol>& e1,+ const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT+ {+ return e1.impl_ < e2.impl_;+ }++ /// Compare endpoints for ordering.+ friend bool operator>(const basic_endpoint<InternetProtocol>& e1,+ const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT+ {+ return e2.impl_ < e1.impl_;+ }++ /// Compare endpoints for ordering.+ friend bool operator<=(const basic_endpoint<InternetProtocol>& e1,+ const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT+ {+ return !(e2 < e1);+ }++ /// Compare endpoints for ordering.+ friend bool operator>=(const basic_endpoint<InternetProtocol>& e1,+ const basic_endpoint<InternetProtocol>& e2) ASIO_NOEXCEPT+ {+ return !(e1 < e2);+ }++private:+ // The underlying IP endpoint.+ asio::ip::detail::endpoint impl_;+};++#if !defined(ASIO_NO_IOSTREAM)++/// Output an endpoint as a string.+/**+ * Used to output a human-readable string for a specified endpoint.+ *+ * @param os The output stream to which the string will be written.+ *+ * @param endpoint The endpoint to be written.+ *+ * @return The output stream.+ *+ * @relates asio::ip::basic_endpoint+ */+template <typename Elem, typename Traits, typename InternetProtocol>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os,+ const basic_endpoint<InternetProtocol>& endpoint);++#endif // !defined(ASIO_NO_IOSTREAM)++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/ip/impl/basic_endpoint.hpp"++#endif // ASIO_IP_BASIC_ENDPOINT_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/basic_resolver.hpp view
@@ -0,0 +1,1030 @@+//+// ip/basic_resolver.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_BASIC_RESOLVER_HPP+#define ASIO_IP_BASIC_RESOLVER_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <string>+#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/string_view.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/ip/basic_resolver_iterator.hpp"+#include "asio/ip/basic_resolver_query.hpp"+#include "asio/ip/basic_resolver_results.hpp"+#include "asio/ip/resolver_base.hpp"+#if defined(ASIO_WINDOWS_RUNTIME)+# include "asio/detail/winrt_resolver_service.hpp"+#else+# include "asio/detail/resolver_service.hpp"+#endif++#if defined(ASIO_HAS_MOVE)+# include <utility>+#endif // defined(ASIO_HAS_MOVE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++#if !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL)+#define ASIO_IP_BASIC_RESOLVER_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename InternetProtocol, typename Executor = any_io_executor>+class basic_resolver;++#endif // !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL)++/// Provides endpoint resolution functionality.+/**+ * The basic_resolver class template provides the ability to resolve a query+ * to a list of endpoints.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename InternetProtocol, typename Executor>+class basic_resolver+ : public resolver_base+{+public:+ /// The type of the executor associated with the object.+ typedef Executor executor_type;++ /// Rebinds the resolver type to another executor.+ template <typename Executor1>+ struct rebind_executor+ {+ /// The resolver type when rebound to the specified executor.+ typedef basic_resolver<InternetProtocol, Executor1> other;+ };++ /// The protocol type.+ typedef InternetProtocol protocol_type;++ /// The endpoint type.+ typedef typename InternetProtocol::endpoint endpoint_type;++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated.) The query type.+ typedef basic_resolver_query<InternetProtocol> query;++ /// (Deprecated.) The iterator type.+ typedef basic_resolver_iterator<InternetProtocol> iterator;+#endif // !defined(ASIO_NO_DEPRECATED)++ /// The results type.+ typedef basic_resolver_results<InternetProtocol> results_type;++ /// Construct with executor.+ /**+ * This constructor creates a basic_resolver.+ *+ * @param ex The I/O executor that the resolver will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * resolver.+ */+ explicit basic_resolver(const executor_type& ex)+ : impl_(ex)+ {+ }++ /// Construct with execution context.+ /**+ * This constructor creates a basic_resolver.+ *+ * @param context An execution context which provides the I/O executor that+ * the resolver will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the resolver.+ */+ template <typename ExecutionContext>+ explicit basic_resolver(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a basic_resolver from another.+ /**+ * This constructor moves a resolver from one object to another.+ *+ * @param other The other basic_resolver 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_resolver(const executor_type&) constructor.+ */+ basic_resolver(basic_resolver&& other)+ : impl_(std::move(other.impl_))+ {+ }++ /// Move-assign a basic_resolver from another.+ /**+ * This assignment operator moves a resolver from one object to another.+ * Cancels any outstanding asynchronous operations associated with the target+ * object.+ *+ * @param other The other basic_resolver 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_resolver(const executor_type&) constructor.+ */+ basic_resolver& operator=(basic_resolver&& other)+ {+ impl_ = std::move(other.impl_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destroys the resolver.+ /**+ * This function destroys the resolver, cancelling any outstanding+ * asynchronous wait operations associated with the resolver as if by calling+ * @c cancel.+ */+ ~basic_resolver()+ {+ }++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_NOEXCEPT+ {+ return impl_.get_executor();+ }++ /// Cancel any asynchronous operations that are waiting on the resolver.+ /**+ * This function forces the completion of any pending asynchronous+ * operations on the host resolver. The handler for each cancelled operation+ * will be invoked with the asio::error::operation_aborted error code.+ */+ void cancel()+ {+ return impl_.get_service().cancel(impl_.get_implementation());+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use overload with separate host and service parameters.)+ /// Perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve a query into a list of endpoint entries.+ *+ * @param q A query object that determines what endpoints will be returned.+ *+ * @returns A range object representing the list of endpoint entries. A+ * successful call to this function is guaranteed to return a non-empty+ * range.+ *+ * @throws asio::system_error Thrown on failure.+ */+ results_type resolve(const query& q)+ {+ asio::error_code ec;+ results_type r = impl_.get_service().resolve(+ impl_.get_implementation(), q, ec);+ asio::detail::throw_error(ec, "resolve");+ return r;+ }++ /// (Deprecated: Use overload with separate host and service parameters.)+ /// Perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve a query into a list of endpoint entries.+ *+ * @param q A query object that determines what endpoints will be returned.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns A range object representing the list of endpoint entries. An+ * empty range is returned if an error occurs. A successful call to this+ * function is guaranteed to return a non-empty range.+ */+ results_type resolve(const query& q, asio::error_code& ec)+ {+ return impl_.get_service().resolve(impl_.get_implementation(), q, ec);+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @returns A range object representing the list of endpoint entries. A+ * successful call to this function is guaranteed to return a non-empty+ * range.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ results_type resolve(ASIO_STRING_VIEW_PARAM host,+ ASIO_STRING_VIEW_PARAM service)+ {+ return resolve(host, service, resolver_base::flags());+ }++ /// Perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns A range object representing the list of endpoint entries. An+ * empty range is returned if an error occurs. A successful call to this+ * function is guaranteed to return a non-empty range.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ results_type resolve(ASIO_STRING_VIEW_PARAM host,+ ASIO_STRING_VIEW_PARAM service, asio::error_code& ec)+ {+ return resolve(host, service, resolver_base::flags(), ec);+ }++ /// Perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param resolve_flags A set of flags that determine how name resolution+ * should be performed. The default flags are suitable for communication with+ * remote hosts. See the @ref resolver_base documentation for the set of+ * available flags.+ *+ * @returns A range object representing the list of endpoint entries. A+ * successful call to this function is guaranteed to return a non-empty+ * range.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ results_type resolve(ASIO_STRING_VIEW_PARAM host,+ ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags)+ {+ asio::error_code ec;+ basic_resolver_query<protocol_type> q(static_cast<std::string>(host),+ static_cast<std::string>(service), resolve_flags);+ results_type r = impl_.get_service().resolve(+ impl_.get_implementation(), q, ec);+ asio::detail::throw_error(ec, "resolve");+ return r;+ }++ /// Perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param resolve_flags A set of flags that determine how name resolution+ * should be performed. The default flags are suitable for communication with+ * remote hosts. See the @ref resolver_base documentation for the set of+ * available flags.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns A range object representing the list of endpoint entries. An+ * empty range is returned if an error occurs. A successful call to this+ * function is guaranteed to return a non-empty range.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ results_type resolve(ASIO_STRING_VIEW_PARAM host,+ ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags,+ asio::error_code& ec)+ {+ basic_resolver_query<protocol_type> q(static_cast<std::string>(host),+ static_cast<std::string>(service), resolve_flags);+ return impl_.get_service().resolve(impl_.get_implementation(), q, ec);+ }++ /// Perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param protocol A protocol object, normally representing either the IPv4 or+ * IPv6 version of an internet protocol.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @returns A range object representing the list of endpoint entries. A+ * successful call to this function is guaranteed to return a non-empty+ * range.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ results_type resolve(const protocol_type& protocol,+ ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service)+ {+ return resolve(protocol, host, service, resolver_base::flags());+ }++ /// Perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param protocol A protocol object, normally representing either the IPv4 or+ * IPv6 version of an internet protocol.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns A range object representing the list of endpoint entries. An+ * empty range is returned if an error occurs. A successful call to this+ * function is guaranteed to return a non-empty range.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ results_type resolve(const protocol_type& protocol,+ ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service,+ asio::error_code& ec)+ {+ return resolve(protocol, host, service, resolver_base::flags(), ec);+ }++ /// Perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param protocol A protocol object, normally representing either the IPv4 or+ * IPv6 version of an internet protocol.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param resolve_flags A set of flags that determine how name resolution+ * should be performed. The default flags are suitable for communication with+ * remote hosts. See the @ref resolver_base documentation for the set of+ * available flags.+ *+ * @returns A range object representing the list of endpoint entries. A+ * successful call to this function is guaranteed to return a non-empty+ * range.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ results_type resolve(const protocol_type& protocol,+ ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service,+ resolver_base::flags resolve_flags)+ {+ asio::error_code ec;+ basic_resolver_query<protocol_type> q(+ protocol, static_cast<std::string>(host),+ static_cast<std::string>(service), resolve_flags);+ results_type r = impl_.get_service().resolve(+ impl_.get_implementation(), q, ec);+ asio::detail::throw_error(ec, "resolve");+ return r;+ }++ /// Perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param protocol A protocol object, normally representing either the IPv4 or+ * IPv6 version of an internet protocol.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param resolve_flags A set of flags that determine how name resolution+ * should be performed. The default flags are suitable for communication with+ * remote hosts. See the @ref resolver_base documentation for the set of+ * available flags.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns A range object representing the list of endpoint entries. An+ * empty range is returned if an error occurs. A successful call to this+ * function is guaranteed to return a non-empty range.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ results_type resolve(const protocol_type& protocol,+ ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service,+ resolver_base::flags resolve_flags, asio::error_code& ec)+ {+ basic_resolver_query<protocol_type> q(+ protocol, static_cast<std::string>(host),+ static_cast<std::string>(service), resolve_flags);+ return impl_.get_service().resolve(impl_.get_implementation(), q, ec);+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use overload with separate host and service parameters.)+ /// Asynchronously perform forward resolution of a query to a list of entries.+ /**+ * This function is used to asynchronously resolve a query into a list of+ * endpoint entries.+ *+ * @param q A query object that determines what endpoints will be returned.+ *+ * @param handler The handler to be called when the resolve operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * resolver::results_type results // Resolved endpoints as a range.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * A successful resolve operation is guaranteed to pass a non-empty range to+ * the handler.+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ results_type)) ResolveHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,+ void (asio::error_code, results_type))+ async_resolve(const query& q,+ ASIO_MOVE_ARG(ResolveHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return asio::async_initiate<ResolveHandler,+ void (asio::error_code, results_type)>(+ initiate_async_resolve(this), handler, q);+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Asynchronously perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param handler The handler to be called when the resolve operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * resolver::results_type results // Resolved endpoints as a range.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * A successful resolve operation is guaranteed to pass a non-empty range to+ * the handler.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ results_type)) ResolveHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,+ void (asio::error_code, results_type))+ async_resolve(ASIO_STRING_VIEW_PARAM host,+ ASIO_STRING_VIEW_PARAM service,+ ASIO_MOVE_ARG(ResolveHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_resolve(host, service, resolver_base::flags(),+ ASIO_MOVE_CAST(ResolveHandler)(handler));+ }++ /// Asynchronously perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param resolve_flags A set of flags that determine how name resolution+ * should be performed. The default flags are suitable for communication with+ * remote hosts. See the @ref resolver_base documentation for the set of+ * available flags.+ *+ * @param handler The handler to be called when the resolve operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * resolver::results_type results // Resolved endpoints as a range.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * A successful resolve operation is guaranteed to pass a non-empty range to+ * the handler.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ results_type)) ResolveHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,+ void (asio::error_code, results_type))+ async_resolve(ASIO_STRING_VIEW_PARAM host,+ ASIO_STRING_VIEW_PARAM service,+ resolver_base::flags resolve_flags,+ ASIO_MOVE_ARG(ResolveHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ basic_resolver_query<protocol_type> q(static_cast<std::string>(host),+ static_cast<std::string>(service), resolve_flags);++ return asio::async_initiate<ResolveHandler,+ void (asio::error_code, results_type)>(+ initiate_async_resolve(this), handler, q);+ }++ /// Asynchronously perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param protocol A protocol object, normally representing either the IPv4 or+ * IPv6 version of an internet protocol.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param handler The handler to be called when the resolve operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * resolver::results_type results // Resolved endpoints as a range.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * A successful resolve operation is guaranteed to pass a non-empty range to+ * the handler.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ results_type)) ResolveHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,+ void (asio::error_code, results_type))+ async_resolve(const protocol_type& protocol,+ ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service,+ ASIO_MOVE_ARG(ResolveHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_resolve(protocol, host, service, resolver_base::flags(),+ ASIO_MOVE_CAST(ResolveHandler)(handler));+ }++ /// Asynchronously perform forward resolution of a query to a list of entries.+ /**+ * This function is used to resolve host and service names into a list of+ * endpoint entries.+ *+ * @param protocol A protocol object, normally representing either the IPv4 or+ * IPv6 version of an internet protocol.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param resolve_flags A set of flags that determine how name resolution+ * should be performed. The default flags are suitable for communication with+ * remote hosts. See the @ref resolver_base documentation for the set of+ * available flags.+ *+ * @param handler The handler to be called when the resolve operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * resolver::results_type results // Resolved endpoints as a range.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * A successful resolve operation is guaranteed to pass a non-empty range to+ * the handler.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ results_type)) ResolveHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,+ void (asio::error_code, results_type))+ async_resolve(const protocol_type& protocol,+ ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service,+ resolver_base::flags resolve_flags,+ ASIO_MOVE_ARG(ResolveHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ basic_resolver_query<protocol_type> q(+ protocol, static_cast<std::string>(host),+ static_cast<std::string>(service), resolve_flags);++ return asio::async_initiate<ResolveHandler,+ void (asio::error_code, results_type)>(+ initiate_async_resolve(this), handler, q);+ }++ /// Perform reverse resolution of an endpoint to a list of entries.+ /**+ * This function is used to resolve an endpoint into a list of endpoint+ * entries.+ *+ * @param e An endpoint object that determines what endpoints will be+ * returned.+ *+ * @returns A range object representing the list of endpoint entries. A+ * successful call to this function is guaranteed to return a non-empty+ * range.+ *+ * @throws asio::system_error Thrown on failure.+ */+ results_type resolve(const endpoint_type& e)+ {+ asio::error_code ec;+ results_type i = impl_.get_service().resolve(+ impl_.get_implementation(), e, ec);+ asio::detail::throw_error(ec, "resolve");+ return i;+ }++ /// Perform reverse resolution of an endpoint to a list of entries.+ /**+ * This function is used to resolve an endpoint into a list of endpoint+ * entries.+ *+ * @param e An endpoint object that determines what endpoints will be+ * returned.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns A range object representing the list of endpoint entries. An+ * empty range is returned if an error occurs. A successful call to this+ * function is guaranteed to return a non-empty range.+ */+ results_type resolve(const endpoint_type& e, asio::error_code& ec)+ {+ return impl_.get_service().resolve(impl_.get_implementation(), e, ec);+ }++ /// Asynchronously perform reverse resolution of an endpoint to a list of+ /// entries.+ /**+ * This function is used to asynchronously resolve an endpoint into a list of+ * endpoint entries.+ *+ * @param e An endpoint object that determines what endpoints will be+ * returned.+ *+ * @param handler The handler to be called when the resolve operation+ * completes. Copies will be made of the handler as required. The function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * resolver::results_type results // Resolved endpoints as a range.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * A successful resolve operation is guaranteed to pass a non-empty range to+ * the handler.+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ results_type)) ResolveHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler,+ void (asio::error_code, results_type))+ async_resolve(const endpoint_type& e,+ ASIO_MOVE_ARG(ResolveHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return asio::async_initiate<ResolveHandler,+ void (asio::error_code, results_type)>(+ initiate_async_resolve(this), handler, e);+ }++private:+ // Disallow copying and assignment.+ basic_resolver(const basic_resolver&) ASIO_DELETED;+ basic_resolver& operator=(const basic_resolver&) ASIO_DELETED;++ class initiate_async_resolve+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_resolve(basic_resolver* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ResolveHandler, typename Query>+ void operator()(ASIO_MOVE_ARG(ResolveHandler) handler,+ const Query& q) const+ {+ // If you get an error on the following line it means that your handler+ // does not meet the documented type requirements for a ResolveHandler.+ ASIO_RESOLVE_HANDLER_CHECK(+ ResolveHandler, handler, results_type) type_check;++ asio::detail::non_const_lvalue<ResolveHandler> handler2(handler);+ self_->impl_.get_service().async_resolve(+ self_->impl_.get_implementation(), q,+ handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_resolver* self_;+ };++# if defined(ASIO_WINDOWS_RUNTIME)+ asio::detail::io_object_impl<+ asio::detail::winrt_resolver_service<InternetProtocol>,+ Executor> impl_;+# else+ asio::detail::io_object_impl<+ asio::detail::resolver_service<InternetProtocol>,+ Executor> impl_;+# endif+};++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_BASIC_RESOLVER_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_entry.hpp view
@@ -0,0 +1,113 @@+//+// ip/basic_resolver_entry.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_BASIC_RESOLVER_ENTRY_HPP+#define ASIO_IP_BASIC_RESOLVER_ENTRY_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <string>+#include "asio/detail/string_view.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// An entry produced by a resolver.+/**+ * The asio::ip::basic_resolver_entry class template describes an entry+ * as returned by a resolver.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename InternetProtocol>+class basic_resolver_entry+{+public:+ /// The protocol type associated with the endpoint entry.+ typedef InternetProtocol protocol_type;++ /// The endpoint type associated with the endpoint entry.+ typedef typename InternetProtocol::endpoint endpoint_type;++ /// Default constructor.+ basic_resolver_entry()+ {+ }++ /// Construct with specified endpoint, host name and service name.+ basic_resolver_entry(const endpoint_type& ep,+ ASIO_STRING_VIEW_PARAM host, ASIO_STRING_VIEW_PARAM service)+ : endpoint_(ep),+ host_name_(static_cast<std::string>(host)),+ service_name_(static_cast<std::string>(service))+ {+ }++ /// Get the endpoint associated with the entry.+ endpoint_type endpoint() const+ {+ return endpoint_;+ }++ /// Convert to the endpoint associated with the entry.+ operator endpoint_type() const+ {+ return endpoint_;+ }++ /// Get the host name associated with the entry.+ std::string host_name() const+ {+ return host_name_;+ }++ /// Get the host name associated with the entry.+ template <class Allocator>+ std::basic_string<char, std::char_traits<char>, Allocator> host_name(+ const Allocator& alloc = Allocator()) const+ {+ return std::basic_string<char, std::char_traits<char>, Allocator>(+ host_name_.c_str(), alloc);+ }++ /// Get the service name associated with the entry.+ std::string service_name() const+ {+ return service_name_;+ }++ /// Get the service name associated with the entry.+ template <class Allocator>+ std::basic_string<char, std::char_traits<char>, Allocator> service_name(+ const Allocator& alloc = Allocator()) const+ {+ return std::basic_string<char, std::char_traits<char>, Allocator>(+ service_name_.c_str(), alloc);+ }++private:+ endpoint_type endpoint_;+ std::string host_name_;+ std::string service_name_;+};++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_BASIC_RESOLVER_ENTRY_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_iterator.hpp view
@@ -0,0 +1,192 @@+//+// ip/basic_resolver_iterator.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_BASIC_RESOLVER_ITERATOR_HPP+#define ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include <cstring>+#include <iterator>+#include <string>+#include <vector>+#include "asio/detail/memory.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/ip/basic_resolver_entry.hpp"++#if defined(ASIO_WINDOWS_RUNTIME)+# include "asio/detail/winrt_utils.hpp"+#endif // defined(ASIO_WINDOWS_RUNTIME)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// An iterator over the entries produced by a resolver.+/**+ * The asio::ip::basic_resolver_iterator class template is used to define+ * iterators over the results returned by a resolver.+ *+ * The iterator's value_type, obtained when the iterator is dereferenced, is:+ * @code const basic_resolver_entry<InternetProtocol> @endcode+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename InternetProtocol>+class basic_resolver_iterator+{+public:+ /// The type used for the distance between two iterators.+ typedef std::ptrdiff_t difference_type;++ /// The type of the value pointed to by the iterator.+ typedef basic_resolver_entry<InternetProtocol> value_type;++ /// The type of the result of applying operator->() to the iterator.+ typedef const basic_resolver_entry<InternetProtocol>* pointer;++ /// The type of the result of applying operator*() to the iterator.+ typedef const basic_resolver_entry<InternetProtocol>& reference;++ /// The iterator category.+ typedef std::forward_iterator_tag iterator_category;++ /// Default constructor creates an end iterator.+ basic_resolver_iterator()+ : index_(0)+ {+ }++ /// Copy constructor.+ basic_resolver_iterator(const basic_resolver_iterator& other)+ : values_(other.values_),+ index_(other.index_)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move constructor.+ basic_resolver_iterator(basic_resolver_iterator&& other)+ : values_(ASIO_MOVE_CAST(values_ptr_type)(other.values_)),+ index_(other.index_)+ {+ other.index_ = 0;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Assignment operator.+ basic_resolver_iterator& operator=(const basic_resolver_iterator& other)+ {+ values_ = other.values_;+ index_ = other.index_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-assignment operator.+ basic_resolver_iterator& operator=(basic_resolver_iterator&& other)+ {+ if (this != &other)+ {+ values_ = ASIO_MOVE_CAST(values_ptr_type)(other.values_);+ index_ = other.index_;+ other.index_ = 0;+ }++ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Dereference an iterator.+ const basic_resolver_entry<InternetProtocol>& operator*() const+ {+ return dereference();+ }++ /// Dereference an iterator.+ const basic_resolver_entry<InternetProtocol>* operator->() const+ {+ return &dereference();+ }++ /// Increment operator (prefix).+ basic_resolver_iterator& operator++()+ {+ increment();+ return *this;+ }++ /// Increment operator (postfix).+ basic_resolver_iterator operator++(int)+ {+ basic_resolver_iterator tmp(*this);+ ++*this;+ return tmp;+ }++ /// Test two iterators for equality.+ friend bool operator==(const basic_resolver_iterator& a,+ const basic_resolver_iterator& b)+ {+ return a.equal(b);+ }++ /// Test two iterators for inequality.+ friend bool operator!=(const basic_resolver_iterator& a,+ const basic_resolver_iterator& b)+ {+ return !a.equal(b);+ }++protected:+ void increment()+ {+ if (++index_ == values_->size())+ {+ // Reset state to match a default constructed end iterator.+ values_.reset();+ index_ = 0;+ }+ }++ bool equal(const basic_resolver_iterator& other) const+ {+ if (!values_ && !other.values_)+ return true;+ if (values_ != other.values_)+ return false;+ return index_ == other.index_;+ }++ const basic_resolver_entry<InternetProtocol>& dereference() const+ {+ return (*values_)[index_];+ }++ typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;+ typedef asio::detail::shared_ptr<values_type> values_ptr_type;+ values_ptr_type values_;+ std::size_t index_;+};++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_query.hpp view
@@ -0,0 +1,244 @@+//+// ip/basic_resolver_query.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_BASIC_RESOLVER_QUERY_HPP+#define ASIO_IP_BASIC_RESOLVER_QUERY_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <string>+#include "asio/detail/socket_ops.hpp"+#include "asio/ip/resolver_query_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// An query to be passed to a resolver.+/**+ * The asio::ip::basic_resolver_query class template describes a query+ * that can be passed to a resolver.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename InternetProtocol>+class basic_resolver_query+ : public resolver_query_base+{+public:+ /// The protocol type associated with the endpoint query.+ typedef InternetProtocol protocol_type;++ /// Construct with specified service name for any protocol.+ /**+ * This constructor is typically used to perform name resolution for local+ * service binding.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number.+ *+ * @param resolve_flags A set of flags that determine how name resolution+ * should be performed. The default flags are suitable for local service+ * binding.+ *+ * @note On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ basic_resolver_query(const std::string& service,+ resolver_query_base::flags resolve_flags = passive | address_configured)+ : hints_(),+ host_name_(),+ service_name_(service)+ {+ typename InternetProtocol::endpoint endpoint;+ hints_.ai_flags = static_cast<int>(resolve_flags);+ hints_.ai_family = PF_UNSPEC;+ hints_.ai_socktype = endpoint.protocol().type();+ hints_.ai_protocol = endpoint.protocol().protocol();+ hints_.ai_addrlen = 0;+ hints_.ai_canonname = 0;+ hints_.ai_addr = 0;+ hints_.ai_next = 0;+ }++ /// Construct with specified service name for a given protocol.+ /**+ * This constructor is typically used to perform name resolution for local+ * service binding with a specific protocol version.+ *+ * @param protocol A protocol object, normally representing either the IPv4 or+ * IPv6 version of an internet protocol.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number.+ *+ * @param resolve_flags A set of flags that determine how name resolution+ * should be performed. The default flags are suitable for local service+ * binding.+ *+ * @note On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ basic_resolver_query(const protocol_type& protocol,+ const std::string& service,+ resolver_query_base::flags resolve_flags = passive | address_configured)+ : hints_(),+ host_name_(),+ service_name_(service)+ {+ hints_.ai_flags = static_cast<int>(resolve_flags);+ hints_.ai_family = protocol.family();+ hints_.ai_socktype = protocol.type();+ hints_.ai_protocol = protocol.protocol();+ hints_.ai_addrlen = 0;+ hints_.ai_canonname = 0;+ hints_.ai_addr = 0;+ hints_.ai_next = 0;+ }++ /// Construct with specified host name and service name for any protocol.+ /**+ * This constructor is typically used to perform name resolution for+ * communication with remote hosts.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param resolve_flags A set of flags that determine how name resolution+ * should be performed. The default flags are suitable for communication with+ * remote hosts.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ basic_resolver_query(const std::string& host, const std::string& service,+ resolver_query_base::flags resolve_flags = address_configured)+ : hints_(),+ host_name_(host),+ service_name_(service)+ {+ typename InternetProtocol::endpoint endpoint;+ hints_.ai_flags = static_cast<int>(resolve_flags);+ hints_.ai_family = ASIO_OS_DEF(AF_UNSPEC);+ hints_.ai_socktype = endpoint.protocol().type();+ hints_.ai_protocol = endpoint.protocol().protocol();+ hints_.ai_addrlen = 0;+ hints_.ai_canonname = 0;+ hints_.ai_addr = 0;+ hints_.ai_next = 0;+ }++ /// Construct with specified host name and service name for a given protocol.+ /**+ * This constructor is typically used to perform name resolution for+ * communication with remote hosts.+ *+ * @param protocol A protocol object, normally representing either the IPv4 or+ * IPv6 version of an internet protocol.+ *+ * @param host A string identifying a location. May be a descriptive name or+ * a numeric address string. If an empty string and the passive flag has been+ * specified, the resolved endpoints are suitable for local service binding.+ * If an empty string and passive is not specified, the resolved endpoints+ * will use the loopback address.+ *+ * @param service A string identifying the requested service. This may be a+ * descriptive name or a numeric string corresponding to a port number. May+ * be an empty string, in which case all resolved endpoints will have a port+ * number of 0.+ *+ * @param resolve_flags A set of flags that determine how name resolution+ * should be performed. The default flags are suitable for communication with+ * remote hosts.+ *+ * @note On POSIX systems, host names may be locally defined in the file+ * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name+ * resolution is performed using DNS. Operating systems may use additional+ * locations when resolving host names (such as NETBIOS names on Windows).+ *+ * On POSIX systems, service names are typically defined in the file+ * <tt>/etc/services</tt>. On Windows, service names may be found in the file+ * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems+ * may use additional locations when resolving service names.+ */+ basic_resolver_query(const protocol_type& protocol,+ const std::string& host, const std::string& service,+ resolver_query_base::flags resolve_flags = address_configured)+ : hints_(),+ host_name_(host),+ service_name_(service)+ {+ hints_.ai_flags = static_cast<int>(resolve_flags);+ hints_.ai_family = protocol.family();+ hints_.ai_socktype = protocol.type();+ hints_.ai_protocol = protocol.protocol();+ hints_.ai_addrlen = 0;+ hints_.ai_canonname = 0;+ hints_.ai_addr = 0;+ hints_.ai_next = 0;+ }++ /// Get the hints associated with the query.+ const asio::detail::addrinfo_type& hints() const+ {+ return hints_;+ }++ /// Get the host name associated with the query.+ std::string host_name() const+ {+ return host_name_;+ }++ /// Get the service name associated with the query.+ std::string service_name() const+ {+ return service_name_;+ }++private:+ asio::detail::addrinfo_type hints_;+ std::string host_name_;+ std::string service_name_;+};++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_BASIC_RESOLVER_QUERY_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/basic_resolver_results.hpp view
@@ -0,0 +1,311 @@+//+// ip/basic_resolver_results.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_BASIC_RESOLVER_RESULTS_HPP+#define ASIO_IP_BASIC_RESOLVER_RESULTS_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include <cstring>+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/ip/basic_resolver_iterator.hpp"++#if defined(ASIO_WINDOWS_RUNTIME)+# include "asio/detail/winrt_utils.hpp"+#endif // defined(ASIO_WINDOWS_RUNTIME)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// A range of entries produced by a resolver.+/**+ * The asio::ip::basic_resolver_results class template is used to define+ * a range over the results returned by a resolver.+ *+ * The iterator's value_type, obtained when a results iterator is dereferenced,+ * is: @code const basic_resolver_entry<InternetProtocol> @endcode+ *+ * @note For backward compatibility, basic_resolver_results is derived from+ * basic_resolver_iterator. This derivation is deprecated.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename InternetProtocol>+class basic_resolver_results+#if !defined(ASIO_NO_DEPRECATED)+ : public basic_resolver_iterator<InternetProtocol>+#else // !defined(ASIO_NO_DEPRECATED)+ : private basic_resolver_iterator<InternetProtocol>+#endif // !defined(ASIO_NO_DEPRECATED)+{+public:+ /// The protocol type associated with the results.+ typedef InternetProtocol protocol_type;++ /// The endpoint type associated with the results.+ typedef typename protocol_type::endpoint endpoint_type;++ /// The type of a value in the results range.+ typedef basic_resolver_entry<protocol_type> value_type;++ /// The type of a const reference to a value in the range.+ typedef const value_type& const_reference;++ /// The type of a non-const reference to a value in the range.+ typedef value_type& reference;++ /// The type of an iterator into the range.+ typedef basic_resolver_iterator<protocol_type> const_iterator;++ /// The type of an iterator into the range.+ typedef const_iterator iterator;++ /// Type used to represent the distance between two iterators in the range.+ typedef std::ptrdiff_t difference_type;++ /// Type used to represent a count of the elements in the range.+ typedef std::size_t size_type;++ /// Default constructor creates an empty range.+ basic_resolver_results()+ {+ }++ /// Copy constructor.+ basic_resolver_results(const basic_resolver_results& other)+ : basic_resolver_iterator<InternetProtocol>(other)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move constructor.+ basic_resolver_results(basic_resolver_results&& other)+ : basic_resolver_iterator<InternetProtocol>(+ ASIO_MOVE_CAST(basic_resolver_results)(other))+ {+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Assignment operator.+ basic_resolver_results& operator=(const basic_resolver_results& other)+ {+ basic_resolver_iterator<InternetProtocol>::operator=(other);+ return *this;+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-assignment operator.+ basic_resolver_results& operator=(basic_resolver_results&& other)+ {+ basic_resolver_iterator<InternetProtocol>::operator=(+ ASIO_MOVE_CAST(basic_resolver_results)(other));+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++#if !defined(GENERATING_DOCUMENTATION)+ // Create results from an addrinfo list returned by getaddrinfo.+ static basic_resolver_results create(+ asio::detail::addrinfo_type* address_info,+ const std::string& host_name, const std::string& service_name)+ {+ basic_resolver_results results;+ if (!address_info)+ return results;++ std::string actual_host_name = host_name;+ if (address_info->ai_canonname)+ actual_host_name = address_info->ai_canonname;++ results.values_.reset(new values_type);++ while (address_info)+ {+ if (address_info->ai_family == ASIO_OS_DEF(AF_INET)+ || address_info->ai_family == ASIO_OS_DEF(AF_INET6))+ {+ using namespace std; // For memcpy.+ typename InternetProtocol::endpoint endpoint;+ endpoint.resize(static_cast<std::size_t>(address_info->ai_addrlen));+ memcpy(endpoint.data(), address_info->ai_addr,+ address_info->ai_addrlen);+ results.values_->push_back(+ basic_resolver_entry<InternetProtocol>(endpoint,+ actual_host_name, service_name));+ }+ address_info = address_info->ai_next;+ }++ return results;+ }++ // Create results from an endpoint, host name and service name.+ static basic_resolver_results create(const endpoint_type& endpoint,+ const std::string& host_name, const std::string& service_name)+ {+ basic_resolver_results results;+ results.values_.reset(new values_type);+ results.values_->push_back(+ basic_resolver_entry<InternetProtocol>(+ endpoint, host_name, service_name));+ return results;+ }++ // Create results from a sequence of endpoints, host and service name.+ template <typename EndpointIterator>+ static basic_resolver_results create(+ EndpointIterator begin, EndpointIterator end,+ const std::string& host_name, const std::string& service_name)+ {+ basic_resolver_results results;+ if (begin != end)+ {+ results.values_.reset(new values_type);+ for (EndpointIterator ep_iter = begin; ep_iter != end; ++ep_iter)+ {+ results.values_->push_back(+ basic_resolver_entry<InternetProtocol>(+ *ep_iter, host_name, service_name));+ }+ }+ return results;+ }++# if defined(ASIO_WINDOWS_RUNTIME)+ // Create results from a Windows Runtime list of EndpointPair objects.+ static basic_resolver_results create(+ Windows::Foundation::Collections::IVectorView<+ Windows::Networking::EndpointPair^>^ endpoints,+ const asio::detail::addrinfo_type& hints,+ const std::string& host_name, const std::string& service_name)+ {+ basic_resolver_results results;+ if (endpoints->Size)+ {+ results.values_.reset(new values_type);+ for (unsigned int i = 0; i < endpoints->Size; ++i)+ {+ auto pair = endpoints->GetAt(i);++ if (hints.ai_family == ASIO_OS_DEF(AF_INET)+ && pair->RemoteHostName->Type+ != Windows::Networking::HostNameType::Ipv4)+ continue;++ if (hints.ai_family == ASIO_OS_DEF(AF_INET6)+ && pair->RemoteHostName->Type+ != Windows::Networking::HostNameType::Ipv6)+ continue;++ results.values_->push_back(+ basic_resolver_entry<InternetProtocol>(+ typename InternetProtocol::endpoint(+ ip::make_address(+ asio::detail::winrt_utils::string(+ pair->RemoteHostName->CanonicalName)),+ asio::detail::winrt_utils::integer(+ pair->RemoteServiceName)),+ host_name, service_name));+ }+ }+ return results;+ }+# endif // defined(ASIO_WINDOWS_RUNTIME)+#endif // !defined(GENERATING_DOCUMENTATION)++ /// Get the number of entries in the results range.+ size_type size() const ASIO_NOEXCEPT+ {+ return this->values_ ? this->values_->size() : 0;+ }++ /// Get the maximum number of entries permitted in a results range.+ size_type max_size() const ASIO_NOEXCEPT+ {+ return this->values_ ? this->values_->max_size() : values_type().max_size();+ }++ /// Determine whether the results range is empty.+ bool empty() const ASIO_NOEXCEPT+ {+ return this->values_ ? this->values_->empty() : true;+ }++ /// Obtain a begin iterator for the results range.+ const_iterator begin() const+ {+ basic_resolver_results tmp(*this);+ tmp.index_ = 0;+ return ASIO_MOVE_CAST(basic_resolver_results)(tmp);+ }++ /// Obtain an end iterator for the results range.+ const_iterator end() const+ {+ return const_iterator();+ }++ /// Obtain a begin iterator for the results range.+ const_iterator cbegin() const+ {+ return begin();+ }++ /// Obtain an end iterator for the results range.+ const_iterator cend() const+ {+ return end();+ }++ /// Swap the results range with another.+ void swap(basic_resolver_results& that) ASIO_NOEXCEPT+ {+ if (this != &that)+ {+ this->values_.swap(that.values_);+ std::size_t index = this->index_;+ this->index_ = that.index_;+ that.index_ = index;+ }+ }++ /// Test two iterators for equality.+ friend bool operator==(const basic_resolver_results& a,+ const basic_resolver_results& b)+ {+ return a.equal(b);+ }++ /// Test two iterators for inequality.+ friend bool operator!=(const basic_resolver_results& a,+ const basic_resolver_results& b)+ {+ return !a.equal(b);+ }++private:+ typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;+};++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_BASIC_RESOLVER_RESULTS_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/detail/endpoint.hpp view
@@ -0,0 +1,141 @@+//+// ip/detail/endpoint.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_DETAIL_ENDPOINT_HPP+#define ASIO_IP_DETAIL_ENDPOINT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <string>+#include "asio/detail/socket_types.hpp"+#include "asio/detail/winsock_init.hpp"+#include "asio/error_code.hpp"+#include "asio/ip/address.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {+namespace detail {++// Helper class for implementating an IP endpoint.+class endpoint+{+public:+ // Default constructor.+ ASIO_DECL endpoint() ASIO_NOEXCEPT;++ // Construct an endpoint using a family and port number.+ ASIO_DECL endpoint(int family,+ unsigned short port_num) ASIO_NOEXCEPT;++ // Construct an endpoint using an address and port number.+ ASIO_DECL endpoint(const asio::ip::address& addr,+ unsigned short port_num) ASIO_NOEXCEPT;++ // Copy constructor.+ endpoint(const endpoint& other) ASIO_NOEXCEPT+ : data_(other.data_)+ {+ }++ // Assign from another endpoint.+ endpoint& operator=(const endpoint& other) ASIO_NOEXCEPT+ {+ data_ = other.data_;+ return *this;+ }++ // Get the underlying endpoint in the native type.+ asio::detail::socket_addr_type* data() ASIO_NOEXCEPT+ {+ return &data_.base;+ }++ // Get the underlying endpoint in the native type.+ const asio::detail::socket_addr_type* data() const ASIO_NOEXCEPT+ {+ return &data_.base;+ }++ // Get the underlying size of the endpoint in the native type.+ std::size_t size() const ASIO_NOEXCEPT+ {+ if (is_v4())+ return sizeof(asio::detail::sockaddr_in4_type);+ else+ return sizeof(asio::detail::sockaddr_in6_type);+ }++ // Set the underlying size of the endpoint in the native type.+ ASIO_DECL void resize(std::size_t new_size);++ // Get the capacity of the endpoint in the native type.+ std::size_t capacity() const ASIO_NOEXCEPT+ {+ return sizeof(data_);+ }++ // Get the port associated with the endpoint.+ ASIO_DECL unsigned short port() const ASIO_NOEXCEPT;++ // Set the port associated with the endpoint.+ ASIO_DECL void port(unsigned short port_num) ASIO_NOEXCEPT;++ // Get the IP address associated with the endpoint.+ ASIO_DECL asio::ip::address address() const ASIO_NOEXCEPT;++ // Set the IP address associated with the endpoint.+ ASIO_DECL void address(+ const asio::ip::address& addr) ASIO_NOEXCEPT;++ // Compare two endpoints for equality.+ ASIO_DECL friend bool operator==(const endpoint& e1,+ const endpoint& e2) ASIO_NOEXCEPT;++ // Compare endpoints for ordering.+ ASIO_DECL friend bool operator<(const endpoint& e1,+ const endpoint& e2) ASIO_NOEXCEPT;++ // Determine whether the endpoint is IPv4.+ bool is_v4() const ASIO_NOEXCEPT+ {+ return data_.base.sa_family == ASIO_OS_DEF(AF_INET);+ }++#if !defined(ASIO_NO_IOSTREAM)+ // Convert to a string.+ ASIO_DECL std::string to_string() const;+#endif // !defined(ASIO_NO_IOSTREAM)++private:+ // The underlying IP socket address.+ union data_union+ {+ asio::detail::socket_addr_type base;+ asio::detail::sockaddr_in4_type v4;+ asio::detail::sockaddr_in6_type v6;+ } data_;+};++} // namespace detail+} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/ip/detail/impl/endpoint.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_IP_DETAIL_ENDPOINT_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/detail/impl/endpoint.ipp view
@@ -0,0 +1,199 @@+//+// ip/detail/impl/endpoint.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_DETAIL_IMPL_ENDPOINT_IPP+#define ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstring>+#if !defined(ASIO_NO_IOSTREAM)+# include <sstream>+#endif // !defined(ASIO_NO_IOSTREAM)+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"+#include "asio/ip/detail/endpoint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {+namespace detail {++endpoint::endpoint() ASIO_NOEXCEPT+ : data_()+{+ data_.v4.sin_family = ASIO_OS_DEF(AF_INET);+ data_.v4.sin_port = 0;+ data_.v4.sin_addr.s_addr = ASIO_OS_DEF(INADDR_ANY);+}++endpoint::endpoint(int family, unsigned short port_num) ASIO_NOEXCEPT+ : data_()+{+ using namespace std; // For memcpy.+ if (family == ASIO_OS_DEF(AF_INET))+ {+ data_.v4.sin_family = ASIO_OS_DEF(AF_INET);+ data_.v4.sin_port =+ asio::detail::socket_ops::host_to_network_short(port_num);+ data_.v4.sin_addr.s_addr = ASIO_OS_DEF(INADDR_ANY);+ }+ else+ {+ data_.v6.sin6_family = ASIO_OS_DEF(AF_INET6);+ data_.v6.sin6_port =+ asio::detail::socket_ops::host_to_network_short(port_num);+ data_.v6.sin6_flowinfo = 0;+ data_.v6.sin6_addr.s6_addr[0] = 0; data_.v6.sin6_addr.s6_addr[1] = 0;+ data_.v6.sin6_addr.s6_addr[2] = 0; data_.v6.sin6_addr.s6_addr[3] = 0;+ data_.v6.sin6_addr.s6_addr[4] = 0; data_.v6.sin6_addr.s6_addr[5] = 0;+ data_.v6.sin6_addr.s6_addr[6] = 0; data_.v6.sin6_addr.s6_addr[7] = 0;+ data_.v6.sin6_addr.s6_addr[8] = 0; data_.v6.sin6_addr.s6_addr[9] = 0;+ data_.v6.sin6_addr.s6_addr[10] = 0; data_.v6.sin6_addr.s6_addr[11] = 0;+ data_.v6.sin6_addr.s6_addr[12] = 0; data_.v6.sin6_addr.s6_addr[13] = 0;+ data_.v6.sin6_addr.s6_addr[14] = 0; data_.v6.sin6_addr.s6_addr[15] = 0;+ data_.v6.sin6_scope_id = 0;+ }+}++endpoint::endpoint(const asio::ip::address& addr,+ unsigned short port_num) ASIO_NOEXCEPT+ : data_()+{+ using namespace std; // For memcpy.+ if (addr.is_v4())+ {+ data_.v4.sin_family = ASIO_OS_DEF(AF_INET);+ data_.v4.sin_port =+ asio::detail::socket_ops::host_to_network_short(port_num);+ data_.v4.sin_addr.s_addr =+ asio::detail::socket_ops::host_to_network_long(+ addr.to_v4().to_uint());+ }+ else+ {+ data_.v6.sin6_family = ASIO_OS_DEF(AF_INET6);+ data_.v6.sin6_port =+ asio::detail::socket_ops::host_to_network_short(port_num);+ data_.v6.sin6_flowinfo = 0;+ asio::ip::address_v6 v6_addr = addr.to_v6();+ asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes();+ memcpy(data_.v6.sin6_addr.s6_addr, bytes.data(), 16);+ data_.v6.sin6_scope_id =+ static_cast<asio::detail::u_long_type>(+ v6_addr.scope_id());+ }+}++void endpoint::resize(std::size_t new_size)+{+ if (new_size > sizeof(asio::detail::sockaddr_storage_type))+ {+ asio::error_code ec(asio::error::invalid_argument);+ asio::detail::throw_error(ec);+ }+}++unsigned short endpoint::port() const ASIO_NOEXCEPT+{+ if (is_v4())+ {+ return asio::detail::socket_ops::network_to_host_short(+ data_.v4.sin_port);+ }+ else+ {+ return asio::detail::socket_ops::network_to_host_short(+ data_.v6.sin6_port);+ }+}++void endpoint::port(unsigned short port_num) ASIO_NOEXCEPT+{+ if (is_v4())+ {+ data_.v4.sin_port+ = asio::detail::socket_ops::host_to_network_short(port_num);+ }+ else+ {+ data_.v6.sin6_port+ = asio::detail::socket_ops::host_to_network_short(port_num);+ }+}++asio::ip::address endpoint::address() const ASIO_NOEXCEPT+{+ using namespace std; // For memcpy.+ if (is_v4())+ {+ return asio::ip::address_v4(+ asio::detail::socket_ops::network_to_host_long(+ data_.v4.sin_addr.s_addr));+ }+ else+ {+ asio::ip::address_v6::bytes_type bytes;+#if defined(ASIO_HAS_STD_ARRAY)+ memcpy(bytes.data(), data_.v6.sin6_addr.s6_addr, 16);+#else // defined(ASIO_HAS_STD_ARRAY)+ memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16);+#endif // defined(ASIO_HAS_STD_ARRAY)+ return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id);+ }+}++void endpoint::address(const asio::ip::address& addr) ASIO_NOEXCEPT+{+ endpoint tmp_endpoint(addr, port());+ data_ = tmp_endpoint.data_;+}++bool operator==(const endpoint& e1, const endpoint& e2) ASIO_NOEXCEPT+{+ return e1.address() == e2.address() && e1.port() == e2.port();+}++bool operator<(const endpoint& e1, const endpoint& e2) ASIO_NOEXCEPT+{+ if (e1.address() < e2.address())+ return true;+ if (e1.address() != e2.address())+ return false;+ return e1.port() < e2.port();+}++#if !defined(ASIO_NO_IOSTREAM)+std::string endpoint::to_string() const+{+ std::ostringstream tmp_os;+ tmp_os.imbue(std::locale::classic());+ if (is_v4())+ tmp_os << address();+ else+ tmp_os << '[' << address() << ']';+ tmp_os << ':' << port();++ return tmp_os.str();+}+#endif // !defined(ASIO_NO_IOSTREAM)++} // namespace detail+} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP
+ link/modules/asio-standalone/asio/include/asio/ip/detail/socket_option.hpp view
@@ -0,0 +1,566 @@+//+// detail/socket_option.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_DETAIL_SOCKET_OPTION_HPP+#define ASIO_IP_DETAIL_SOCKET_OPTION_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include <cstring>+#include <stdexcept>+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/ip/address.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {+namespace detail {+namespace socket_option {++// Helper template for implementing multicast enable loopback options.+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>+class multicast_enable_loopback+{+public:+#if defined(__sun) || defined(__osf__)+ typedef unsigned char ipv4_value_type;+ typedef unsigned char ipv6_value_type;+#elif defined(_AIX) || defined(__hpux) || defined(__QNXNTO__) + typedef unsigned char ipv4_value_type;+ typedef unsigned int ipv6_value_type;+#else+ typedef int ipv4_value_type;+ typedef int ipv6_value_type;+#endif++ // Default constructor.+ multicast_enable_loopback()+ : ipv4_value_(0),+ ipv6_value_(0)+ {+ }++ // Construct with a specific option value.+ explicit multicast_enable_loopback(bool v)+ : ipv4_value_(v ? 1 : 0),+ ipv6_value_(v ? 1 : 0)+ {+ }++ // Set the value of the boolean.+ multicast_enable_loopback& operator=(bool v)+ {+ ipv4_value_ = v ? 1 : 0;+ ipv6_value_ = v ? 1 : 0;+ return *this;+ }++ // Get the current value of the boolean.+ bool value() const+ {+ return !!ipv4_value_;+ }++ // Convert to bool.+ operator bool() const+ {+ return !!ipv4_value_;+ }++ // Test for false.+ bool operator!() const+ {+ return !ipv4_value_;+ }++ // Get the level of the socket option.+ template <typename Protocol>+ int level(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return IPv6_Level;+ return IPv4_Level;+ }++ // Get the name of the socket option.+ template <typename Protocol>+ int name(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return IPv6_Name;+ return IPv4_Name;+ }++ // Get the address of the boolean data.+ template <typename Protocol>+ void* data(const Protocol& protocol)+ {+ if (protocol.family() == PF_INET6)+ return &ipv6_value_;+ return &ipv4_value_;+ }++ // Get the address of the boolean data.+ template <typename Protocol>+ const void* data(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return &ipv6_value_;+ return &ipv4_value_;+ }++ // Get the size of the boolean data.+ template <typename Protocol>+ std::size_t size(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return sizeof(ipv6_value_);+ return sizeof(ipv4_value_);+ }++ // Set the size of the boolean data.+ template <typename Protocol>+ void resize(const Protocol& protocol, std::size_t s)+ {+ if (protocol.family() == PF_INET6)+ {+ if (s != sizeof(ipv6_value_))+ {+ std::length_error ex("multicast_enable_loopback socket option resize");+ asio::detail::throw_exception(ex);+ }+ ipv4_value_ = ipv6_value_ ? 1 : 0;+ }+ else+ {+ if (s != sizeof(ipv4_value_))+ {+ std::length_error ex("multicast_enable_loopback socket option resize");+ asio::detail::throw_exception(ex);+ }+ ipv6_value_ = ipv4_value_ ? 1 : 0;+ }+ }++private:+ ipv4_value_type ipv4_value_;+ ipv6_value_type ipv6_value_;+};++// Helper template for implementing unicast hops options.+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>+class unicast_hops+{+public:+ // Default constructor.+ unicast_hops()+ : value_(0)+ {+ }++ // Construct with a specific option value.+ explicit unicast_hops(int v)+ : value_(v)+ {+ }++ // Set the value of the option.+ unicast_hops& operator=(int v)+ {+ value_ = v;+ return *this;+ }++ // Get the current value of the option.+ int value() const+ {+ return value_;+ }++ // Get the level of the socket option.+ template <typename Protocol>+ int level(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return IPv6_Level;+ return IPv4_Level;+ }++ // Get the name of the socket option.+ template <typename Protocol>+ int name(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return IPv6_Name;+ return IPv4_Name;+ }++ // Get the address of the data.+ template <typename Protocol>+ int* data(const Protocol&)+ {+ return &value_;+ }++ // Get the address of the data.+ template <typename Protocol>+ const int* data(const Protocol&) const+ {+ return &value_;+ }++ // Get the size of the data.+ template <typename Protocol>+ std::size_t size(const Protocol&) const+ {+ return sizeof(value_);+ }++ // Set the size of the data.+ template <typename Protocol>+ void resize(const Protocol&, std::size_t s)+ {+ if (s != sizeof(value_))+ {+ std::length_error ex("unicast hops socket option resize");+ asio::detail::throw_exception(ex);+ }+#if defined(__hpux)+ if (value_ < 0)+ value_ = value_ & 0xFF;+#endif+ }++private:+ int value_;+};++// Helper template for implementing multicast hops options.+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>+class multicast_hops+{+public:+#if defined(ASIO_WINDOWS) && defined(UNDER_CE)+ typedef int ipv4_value_type;+#else+ typedef unsigned char ipv4_value_type;+#endif+ typedef int ipv6_value_type;++ // Default constructor.+ multicast_hops()+ : ipv4_value_(0),+ ipv6_value_(0)+ {+ }++ // Construct with a specific option value.+ explicit multicast_hops(int v)+ {+ if (v < 0 || v > 255)+ {+ std::out_of_range ex("multicast hops value out of range");+ asio::detail::throw_exception(ex);+ }+ ipv4_value_ = (ipv4_value_type)v;+ ipv6_value_ = v;+ }++ // Set the value of the option.+ multicast_hops& operator=(int v)+ {+ if (v < 0 || v > 255)+ {+ std::out_of_range ex("multicast hops value out of range");+ asio::detail::throw_exception(ex);+ }+ ipv4_value_ = (ipv4_value_type)v;+ ipv6_value_ = v;+ return *this;+ }++ // Get the current value of the option.+ int value() const+ {+ return ipv6_value_;+ }++ // Get the level of the socket option.+ template <typename Protocol>+ int level(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return IPv6_Level;+ return IPv4_Level;+ }++ // Get the name of the socket option.+ template <typename Protocol>+ int name(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return IPv6_Name;+ return IPv4_Name;+ }++ // Get the address of the data.+ template <typename Protocol>+ void* data(const Protocol& protocol)+ {+ if (protocol.family() == PF_INET6)+ return &ipv6_value_;+ return &ipv4_value_;+ }++ // Get the address of the data.+ template <typename Protocol>+ const void* data(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return &ipv6_value_;+ return &ipv4_value_;+ }++ // Get the size of the data.+ template <typename Protocol>+ std::size_t size(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return sizeof(ipv6_value_);+ return sizeof(ipv4_value_);+ }++ // Set the size of the data.+ template <typename Protocol>+ void resize(const Protocol& protocol, std::size_t s)+ {+ if (protocol.family() == PF_INET6)+ {+ if (s != sizeof(ipv6_value_))+ {+ std::length_error ex("multicast hops socket option resize");+ asio::detail::throw_exception(ex);+ }+ if (ipv6_value_ < 0)+ ipv4_value_ = 0;+ else if (ipv6_value_ > 255)+ ipv4_value_ = 255;+ else+ ipv4_value_ = (ipv4_value_type)ipv6_value_;+ }+ else+ {+ if (s != sizeof(ipv4_value_))+ {+ std::length_error ex("multicast hops socket option resize");+ asio::detail::throw_exception(ex);+ }+ ipv6_value_ = ipv4_value_;+ }+ }++private:+ ipv4_value_type ipv4_value_;+ ipv6_value_type ipv6_value_;+};++// Helper template for implementing ip_mreq-based options.+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>+class multicast_request+{+public:+ // Default constructor.+ multicast_request()+ : ipv4_value_(), // Zero-initialisation gives the "any" address.+ ipv6_value_() // Zero-initialisation gives the "any" address.+ {+ }++ // Construct with multicast address only.+ explicit multicast_request(const address& multicast_address)+ : ipv4_value_(), // Zero-initialisation gives the "any" address.+ ipv6_value_() // Zero-initialisation gives the "any" address.+ {+ if (multicast_address.is_v6())+ {+ using namespace std; // For memcpy.+ address_v6 ipv6_address = multicast_address.to_v6();+ address_v6::bytes_type bytes = ipv6_address.to_bytes();+ memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.data(), 16);+ ipv6_value_.ipv6mr_interface = ipv6_address.scope_id();+ }+ else+ {+ ipv4_value_.imr_multiaddr.s_addr =+ asio::detail::socket_ops::host_to_network_long(+ multicast_address.to_v4().to_uint());+ ipv4_value_.imr_interface.s_addr =+ asio::detail::socket_ops::host_to_network_long(+ address_v4::any().to_uint());+ }+ }++ // Construct with multicast address and IPv4 address specifying an interface.+ explicit multicast_request(const address_v4& multicast_address,+ const address_v4& network_interface = address_v4::any())+ : ipv6_value_() // Zero-initialisation gives the "any" address.+ {+ ipv4_value_.imr_multiaddr.s_addr =+ asio::detail::socket_ops::host_to_network_long(+ multicast_address.to_uint());+ ipv4_value_.imr_interface.s_addr =+ asio::detail::socket_ops::host_to_network_long(+ network_interface.to_uint());+ }++ // Construct with multicast address and IPv6 network interface index.+ explicit multicast_request(+ const address_v6& multicast_address,+ unsigned long network_interface = 0)+ : ipv4_value_() // Zero-initialisation gives the "any" address.+ {+ using namespace std; // For memcpy.+ address_v6::bytes_type bytes = multicast_address.to_bytes();+ memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.data(), 16);+ if (network_interface)+ ipv6_value_.ipv6mr_interface = network_interface;+ else+ ipv6_value_.ipv6mr_interface = multicast_address.scope_id();+ }++ // Get the level of the socket option.+ template <typename Protocol>+ int level(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return IPv6_Level;+ return IPv4_Level;+ }++ // Get the name of the socket option.+ template <typename Protocol>+ int name(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return IPv6_Name;+ return IPv4_Name;+ }++ // Get the address of the option data.+ template <typename Protocol>+ const void* data(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return &ipv6_value_;+ return &ipv4_value_;+ }++ // Get the size of the option data.+ template <typename Protocol>+ std::size_t size(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return sizeof(ipv6_value_);+ return sizeof(ipv4_value_);+ }++private:+ asio::detail::in4_mreq_type ipv4_value_;+ asio::detail::in6_mreq_type ipv6_value_;+};++// Helper template for implementing options that specify a network interface.+template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>+class network_interface+{+public:+ // Default constructor.+ network_interface()+ {+ ipv4_value_.s_addr =+ asio::detail::socket_ops::host_to_network_long(+ address_v4::any().to_uint());+ ipv6_value_ = 0;+ }++ // Construct with IPv4 interface.+ explicit network_interface(const address_v4& ipv4_interface)+ {+ ipv4_value_.s_addr =+ asio::detail::socket_ops::host_to_network_long(+ ipv4_interface.to_uint());+ ipv6_value_ = 0;+ }++ // Construct with IPv6 interface.+ explicit network_interface(unsigned int ipv6_interface)+ {+ ipv4_value_.s_addr =+ asio::detail::socket_ops::host_to_network_long(+ address_v4::any().to_uint());+ ipv6_value_ = ipv6_interface;+ }++ // Get the level of the socket option.+ template <typename Protocol>+ int level(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return IPv6_Level;+ return IPv4_Level;+ }++ // Get the name of the socket option.+ template <typename Protocol>+ int name(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return IPv6_Name;+ return IPv4_Name;+ }++ // Get the address of the option data.+ template <typename Protocol>+ const void* data(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return &ipv6_value_;+ return &ipv4_value_;+ }++ // Get the size of the option data.+ template <typename Protocol>+ std::size_t size(const Protocol& protocol) const+ {+ if (protocol.family() == PF_INET6)+ return sizeof(ipv6_value_);+ return sizeof(ipv4_value_);+ }++private:+ asio::detail::in4_addr_type ipv4_value_;+ unsigned int ipv6_value_;+};++} // namespace socket_option+} // namespace detail+} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_DETAIL_SOCKET_OPTION_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/host_name.hpp view
@@ -0,0 +1,42 @@+//+// ip/host_name.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_HOST_NAME_HPP+#define ASIO_IP_HOST_NAME_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <string>+#include "asio/error_code.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// Get the current host name.+ASIO_DECL std::string host_name();++/// Get the current host name.+ASIO_DECL std::string host_name(asio::error_code& ec);++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/ip/impl/host_name.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_IP_HOST_NAME_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/icmp.hpp view
@@ -0,0 +1,115 @@+//+// ip/icmp.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_ICMP_HPP+#define ASIO_IP_ICMP_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/socket_types.hpp"+#include "asio/basic_raw_socket.hpp"+#include "asio/ip/basic_endpoint.hpp"+#include "asio/ip/basic_resolver.hpp"+#include "asio/ip/basic_resolver_iterator.hpp"+#include "asio/ip/basic_resolver_query.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// Encapsulates the flags needed for ICMP.+/**+ * The asio::ip::icmp class contains flags necessary for ICMP sockets.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Safe.+ *+ * @par Concepts:+ * Protocol, InternetProtocol.+ */+class icmp+{+public:+ /// The type of a ICMP endpoint.+ typedef basic_endpoint<icmp> endpoint;++ /// Construct to represent the IPv4 ICMP protocol.+ static icmp v4() ASIO_NOEXCEPT+ {+ return icmp(ASIO_OS_DEF(IPPROTO_ICMP),+ ASIO_OS_DEF(AF_INET));+ }++ /// Construct to represent the IPv6 ICMP protocol.+ static icmp v6() ASIO_NOEXCEPT+ {+ return icmp(ASIO_OS_DEF(IPPROTO_ICMPV6),+ ASIO_OS_DEF(AF_INET6));+ }++ /// Obtain an identifier for the type of the protocol.+ int type() const ASIO_NOEXCEPT+ {+ return ASIO_OS_DEF(SOCK_RAW);+ }++ /// Obtain an identifier for the protocol.+ int protocol() const ASIO_NOEXCEPT+ {+ return protocol_;+ }++ /// Obtain an identifier for the protocol family.+ int family() const ASIO_NOEXCEPT+ {+ return family_;+ }++ /// The ICMP socket type.+ typedef basic_raw_socket<icmp> socket;++ /// The ICMP resolver type.+ typedef basic_resolver<icmp> resolver;++ /// Compare two protocols for equality.+ friend bool operator==(const icmp& p1, const icmp& p2)+ {+ return p1.protocol_ == p2.protocol_ && p1.family_ == p2.family_;+ }++ /// Compare two protocols for inequality.+ friend bool operator!=(const icmp& p1, const icmp& p2)+ {+ return p1.protocol_ != p2.protocol_ || p1.family_ != p2.family_;+ }++private:+ // Construct with a specific family.+ explicit icmp(int protocol_id, int protocol_family) ASIO_NOEXCEPT+ : protocol_(protocol_id),+ family_(protocol_family)+ {+ }++ int protocol_;+ int family_;+};++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_ICMP_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/address.hpp view
@@ -0,0 +1,67 @@+//+// ip/impl/address.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_IMPL_ADDRESS_HPP+#define ASIO_IP_IMPL_ADDRESS_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#if !defined(ASIO_NO_IOSTREAM)++#include "asio/detail/throw_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++#if !defined(ASIO_NO_DEPRECATED)++inline address address::from_string(const char* str)+{+ return asio::ip::make_address(str);+}++inline address address::from_string(+ const char* str, asio::error_code& ec)+{+ return asio::ip::make_address(str, ec);+}++inline address address::from_string(const std::string& str)+{+ return asio::ip::make_address(str);+}++inline address address::from_string(+ const std::string& str, asio::error_code& ec)+{+ return asio::ip::make_address(str, ec);+}++#endif // !defined(ASIO_NO_DEPRECATED)++template <typename Elem, typename Traits>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os, const address& addr)+{+ return os << addr.to_string().c_str();+}++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_IOSTREAM)++#endif // ASIO_IP_IMPL_ADDRESS_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/address.ipp view
@@ -0,0 +1,239 @@+//+// ip/impl/address.ipp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_IMPL_ADDRESS_IPP+#define ASIO_IP_IMPL_ADDRESS_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <typeinfo>+#include "asio/detail/throw_error.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/error.hpp"+#include "asio/ip/address.hpp"+#include "asio/ip/bad_address_cast.hpp"+#include "asio/system_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++address::address() ASIO_NOEXCEPT+ : type_(ipv4),+ ipv4_address_(),+ ipv6_address_()+{+}++address::address(+ const asio::ip::address_v4& ipv4_address) ASIO_NOEXCEPT+ : type_(ipv4),+ ipv4_address_(ipv4_address),+ ipv6_address_()+{+}++address::address(+ const asio::ip::address_v6& ipv6_address) ASIO_NOEXCEPT+ : type_(ipv6),+ ipv4_address_(),+ ipv6_address_(ipv6_address)+{+}++address::address(const address& other) ASIO_NOEXCEPT+ : type_(other.type_),+ ipv4_address_(other.ipv4_address_),+ ipv6_address_(other.ipv6_address_)+{+}++#if defined(ASIO_HAS_MOVE)+address::address(address&& other) ASIO_NOEXCEPT+ : type_(other.type_),+ ipv4_address_(other.ipv4_address_),+ ipv6_address_(other.ipv6_address_)+{+}+#endif // defined(ASIO_HAS_MOVE)++address& address::operator=(const address& other) ASIO_NOEXCEPT+{+ type_ = other.type_;+ ipv4_address_ = other.ipv4_address_;+ ipv6_address_ = other.ipv6_address_;+ return *this;+}++#if defined(ASIO_HAS_MOVE)+address& address::operator=(address&& other) ASIO_NOEXCEPT+{+ type_ = other.type_;+ ipv4_address_ = other.ipv4_address_;+ ipv6_address_ = other.ipv6_address_;+ return *this;+}+#endif // defined(ASIO_HAS_MOVE)++address& address::operator=(+ const asio::ip::address_v4& ipv4_address) ASIO_NOEXCEPT+{+ type_ = ipv4;+ ipv4_address_ = ipv4_address;+ ipv6_address_ = asio::ip::address_v6();+ return *this;+}++address& address::operator=(+ const asio::ip::address_v6& ipv6_address) ASIO_NOEXCEPT+{+ type_ = ipv6;+ ipv4_address_ = asio::ip::address_v4();+ ipv6_address_ = ipv6_address;+ return *this;+}++address make_address(const char* str)+{+ asio::error_code ec;+ address addr = make_address(str, ec);+ asio::detail::throw_error(ec);+ return addr;+}++address make_address(const char* str,+ asio::error_code& ec) ASIO_NOEXCEPT+{+ asio::ip::address_v6 ipv6_address =+ asio::ip::make_address_v6(str, ec);+ if (!ec)+ return address(ipv6_address);++ asio::ip::address_v4 ipv4_address =+ asio::ip::make_address_v4(str, ec);+ if (!ec)+ return address(ipv4_address);++ return address();+}++address make_address(const std::string& str)+{+ return make_address(str.c_str());+}++address make_address(const std::string& str,+ asio::error_code& ec) ASIO_NOEXCEPT+{+ return make_address(str.c_str(), ec);+}++#if defined(ASIO_HAS_STRING_VIEW)++address make_address(string_view str)+{+ return make_address(static_cast<std::string>(str));+}++address make_address(string_view str,+ asio::error_code& ec) ASIO_NOEXCEPT+{+ return make_address(static_cast<std::string>(str), ec);+}++#endif // defined(ASIO_HAS_STRING_VIEW)++asio::ip::address_v4 address::to_v4() const+{+ if (type_ != ipv4)+ {+ bad_address_cast ex;+ asio::detail::throw_exception(ex);+ }+ return ipv4_address_;+}++asio::ip::address_v6 address::to_v6() const+{+ if (type_ != ipv6)+ {+ bad_address_cast ex;+ asio::detail::throw_exception(ex);+ }+ return ipv6_address_;+}++std::string address::to_string() const+{+ if (type_ == ipv6)+ return ipv6_address_.to_string();+ return ipv4_address_.to_string();+}++#if !defined(ASIO_NO_DEPRECATED)+std::string address::to_string(asio::error_code& ec) const+{+ if (type_ == ipv6)+ return ipv6_address_.to_string(ec);+ return ipv4_address_.to_string(ec);+}+#endif // !defined(ASIO_NO_DEPRECATED)++bool address::is_loopback() const ASIO_NOEXCEPT+{+ return (type_ == ipv4)+ ? ipv4_address_.is_loopback()+ : ipv6_address_.is_loopback();+}++bool address::is_unspecified() const ASIO_NOEXCEPT+{+ return (type_ == ipv4)+ ? ipv4_address_.is_unspecified()+ : ipv6_address_.is_unspecified();+}++bool address::is_multicast() const ASIO_NOEXCEPT+{+ return (type_ == ipv4)+ ? ipv4_address_.is_multicast()+ : ipv6_address_.is_multicast();+}++bool operator==(const address& a1, const address& a2) ASIO_NOEXCEPT+{+ if (a1.type_ != a2.type_)+ return false;+ if (a1.type_ == address::ipv6)+ return a1.ipv6_address_ == a2.ipv6_address_;+ return a1.ipv4_address_ == a2.ipv4_address_;+}++bool operator<(const address& a1, const address& a2) ASIO_NOEXCEPT+{+ if (a1.type_ < a2.type_)+ return true;+ if (a1.type_ > a2.type_)+ return false;+ if (a1.type_ == address::ipv6)+ return a1.ipv6_address_ < a2.ipv6_address_;+ return a1.ipv4_address_ < a2.ipv4_address_;+}++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_IMPL_ADDRESS_IPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/address_v4.hpp view
@@ -0,0 +1,67 @@+//+// ip/impl/address_v4.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_IMPL_ADDRESS_V4_HPP+#define ASIO_IP_IMPL_ADDRESS_V4_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#if !defined(ASIO_NO_IOSTREAM)++#include "asio/detail/throw_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++#if !defined(ASIO_NO_DEPRECATED)++inline address_v4 address_v4::from_string(const char* str)+{+ return asio::ip::make_address_v4(str);+}++inline address_v4 address_v4::from_string(+ const char* str, asio::error_code& ec)+{+ return asio::ip::make_address_v4(str, ec);+}++inline address_v4 address_v4::from_string(const std::string& str)+{+ return asio::ip::make_address_v4(str);+}++inline address_v4 address_v4::from_string(+ const std::string& str, asio::error_code& ec)+{+ return asio::ip::make_address_v4(str, ec);+}++#endif // !defined(ASIO_NO_DEPRECATED)++template <typename Elem, typename Traits>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os, const address_v4& addr)+{+ return os << addr.to_string().c_str();+}++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_IOSTREAM)++#endif // ASIO_IP_IMPL_ADDRESS_V4_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/address_v4.ipp view
@@ -0,0 +1,210 @@+//+// ip/impl/address_v4.ipp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_IMPL_ADDRESS_V4_IPP+#define ASIO_IP_IMPL_ADDRESS_V4_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <climits>+#include <limits>+#include <stdexcept>+#include "asio/error.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/ip/address_v4.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++address_v4::address_v4(const address_v4::bytes_type& bytes)+{+#if UCHAR_MAX > 0xFF+ if (bytes[0] > 0xFF || bytes[1] > 0xFF+ || bytes[2] > 0xFF || bytes[3] > 0xFF)+ {+ std::out_of_range ex("address_v4 from bytes_type");+ asio::detail::throw_exception(ex);+ }+#endif // UCHAR_MAX > 0xFF++ using namespace std; // For memcpy.+ memcpy(&addr_.s_addr, bytes.data(), 4);+}++address_v4::address_v4(address_v4::uint_type addr)+{+ if ((std::numeric_limits<uint_type>::max)() > 0xFFFFFFFF)+ {+ std::out_of_range ex("address_v4 from unsigned integer");+ asio::detail::throw_exception(ex);+ }++ addr_.s_addr = asio::detail::socket_ops::host_to_network_long(+ static_cast<asio::detail::u_long_type>(addr));+}++address_v4::bytes_type address_v4::to_bytes() const ASIO_NOEXCEPT+{+ using namespace std; // For memcpy.+ bytes_type bytes;+#if defined(ASIO_HAS_STD_ARRAY)+ memcpy(bytes.data(), &addr_.s_addr, 4);+#else // defined(ASIO_HAS_STD_ARRAY)+ memcpy(bytes.elems, &addr_.s_addr, 4);+#endif // defined(ASIO_HAS_STD_ARRAY)+ return bytes;+}++address_v4::uint_type address_v4::to_uint() const ASIO_NOEXCEPT+{+ return asio::detail::socket_ops::network_to_host_long(addr_.s_addr);+}++#if !defined(ASIO_NO_DEPRECATED)+unsigned long address_v4::to_ulong() const+{+ return asio::detail::socket_ops::network_to_host_long(addr_.s_addr);+}+#endif // !defined(ASIO_NO_DEPRECATED)++std::string address_v4::to_string() const+{+ asio::error_code ec;+ char addr_str[asio::detail::max_addr_v4_str_len];+ const char* addr =+ asio::detail::socket_ops::inet_ntop(+ ASIO_OS_DEF(AF_INET), &addr_, addr_str,+ asio::detail::max_addr_v4_str_len, 0, ec);+ if (addr == 0)+ asio::detail::throw_error(ec);+ return addr;+}++#if !defined(ASIO_NO_DEPRECATED)+std::string address_v4::to_string(asio::error_code& ec) const+{+ char addr_str[asio::detail::max_addr_v4_str_len];+ const char* addr =+ asio::detail::socket_ops::inet_ntop(+ ASIO_OS_DEF(AF_INET), &addr_, addr_str,+ asio::detail::max_addr_v4_str_len, 0, ec);+ if (addr == 0)+ return std::string();+ return addr;+}+#endif // !defined(ASIO_NO_DEPRECATED)++bool address_v4::is_loopback() const ASIO_NOEXCEPT+{+ return (to_uint() & 0xFF000000) == 0x7F000000;+}++bool address_v4::is_unspecified() const ASIO_NOEXCEPT+{+ return to_uint() == 0;+}++#if !defined(ASIO_NO_DEPRECATED)+bool address_v4::is_class_a() const+{+ return (to_uint() & 0x80000000) == 0;+}++bool address_v4::is_class_b() const+{+ return (to_uint() & 0xC0000000) == 0x80000000;+}++bool address_v4::is_class_c() const+{+ return (to_uint() & 0xE0000000) == 0xC0000000;+}+#endif // !defined(ASIO_NO_DEPRECATED)++bool address_v4::is_multicast() const ASIO_NOEXCEPT+{+ return (to_uint() & 0xF0000000) == 0xE0000000;+}++#if !defined(ASIO_NO_DEPRECATED)+address_v4 address_v4::broadcast(const address_v4& addr, const address_v4& mask)+{+ return address_v4(addr.to_uint() | (mask.to_uint() ^ 0xFFFFFFFF));+}++address_v4 address_v4::netmask(const address_v4& addr)+{+ if (addr.is_class_a())+ return address_v4(0xFF000000);+ if (addr.is_class_b())+ return address_v4(0xFFFF0000);+ if (addr.is_class_c())+ return address_v4(0xFFFFFF00);+ return address_v4(0xFFFFFFFF);+}+#endif // !defined(ASIO_NO_DEPRECATED)++address_v4 make_address_v4(const char* str)+{+ asio::error_code ec;+ address_v4 addr = make_address_v4(str, ec);+ asio::detail::throw_error(ec);+ return addr;+}++address_v4 make_address_v4(const char* str,+ asio::error_code& ec) ASIO_NOEXCEPT+{+ address_v4::bytes_type bytes;+ if (asio::detail::socket_ops::inet_pton(+ ASIO_OS_DEF(AF_INET), str, &bytes, 0, ec) <= 0)+ return address_v4();+ return address_v4(bytes);+}++address_v4 make_address_v4(const std::string& str)+{+ return make_address_v4(str.c_str());+}++address_v4 make_address_v4(const std::string& str,+ asio::error_code& ec) ASIO_NOEXCEPT+{+ return make_address_v4(str.c_str(), ec);+}++#if defined(ASIO_HAS_STRING_VIEW)++address_v4 make_address_v4(string_view str)+{+ return make_address_v4(static_cast<std::string>(str));+}++address_v4 make_address_v4(string_view str,+ asio::error_code& ec) ASIO_NOEXCEPT+{+ return make_address_v4(static_cast<std::string>(str), ec);+}++#endif // defined(ASIO_HAS_STRING_VIEW)++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_IMPL_ADDRESS_V4_IPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/address_v6.hpp view
@@ -0,0 +1,67 @@+//+// ip/impl/address_v6.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_IMPL_ADDRESS_V6_HPP+#define ASIO_IP_IMPL_ADDRESS_V6_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#if !defined(ASIO_NO_IOSTREAM)++#include "asio/detail/throw_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++#if !defined(ASIO_NO_DEPRECATED)++inline address_v6 address_v6::from_string(const char* str)+{+ return asio::ip::make_address_v6(str);+}++inline address_v6 address_v6::from_string(+ const char* str, asio::error_code& ec)+{+ return asio::ip::make_address_v6(str, ec);+}++inline address_v6 address_v6::from_string(const std::string& str)+{+ return asio::ip::make_address_v6(str);+}++inline address_v6 address_v6::from_string(+ const std::string& str, asio::error_code& ec)+{+ return asio::ip::make_address_v6(str, ec);+}++#endif // !defined(ASIO_NO_DEPRECATED)++template <typename Elem, typename Traits>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os, const address_v6& addr)+{+ return os << addr.to_string().c_str();+}++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_IOSTREAM)++#endif // ASIO_IP_IMPL_ADDRESS_V6_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/address_v6.ipp view
@@ -0,0 +1,350 @@+//+// ip/impl/address_v6.ipp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_IMPL_ADDRESS_V6_IPP+#define ASIO_IP_IMPL_ADDRESS_V6_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstring>+#include <stdexcept>+#include <typeinfo>+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/error.hpp"+#include "asio/ip/address_v6.hpp"+#include "asio/ip/bad_address_cast.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++address_v6::address_v6() ASIO_NOEXCEPT+ : addr_(),+ scope_id_(0)+{+}++address_v6::address_v6(const address_v6::bytes_type& bytes,+ unsigned long scope)+ : scope_id_(scope)+{+#if UCHAR_MAX > 0xFF+ for (std::size_t i = 0; i < bytes.size(); ++i)+ {+ if (bytes[i] > 0xFF)+ {+ std::out_of_range ex("address_v6 from bytes_type");+ asio::detail::throw_exception(ex);+ }+ }+#endif // UCHAR_MAX > 0xFF++ using namespace std; // For memcpy.+ memcpy(addr_.s6_addr, bytes.data(), 16);+}++address_v6::address_v6(const address_v6& other) ASIO_NOEXCEPT+ : addr_(other.addr_),+ scope_id_(other.scope_id_)+{+}++#if defined(ASIO_HAS_MOVE)+address_v6::address_v6(address_v6&& other) ASIO_NOEXCEPT+ : addr_(other.addr_),+ scope_id_(other.scope_id_)+{+}+#endif // defined(ASIO_HAS_MOVE)++address_v6& address_v6::operator=(const address_v6& other) ASIO_NOEXCEPT+{+ addr_ = other.addr_;+ scope_id_ = other.scope_id_;+ return *this;+}++#if defined(ASIO_HAS_MOVE)+address_v6& address_v6::operator=(address_v6&& other) ASIO_NOEXCEPT+{+ addr_ = other.addr_;+ scope_id_ = other.scope_id_;+ return *this;+}+#endif // defined(ASIO_HAS_MOVE)++address_v6::bytes_type address_v6::to_bytes() const ASIO_NOEXCEPT+{+ using namespace std; // For memcpy.+ bytes_type bytes;+#if defined(ASIO_HAS_STD_ARRAY)+ memcpy(bytes.data(), addr_.s6_addr, 16);+#else // defined(ASIO_HAS_STD_ARRAY)+ memcpy(bytes.elems, addr_.s6_addr, 16);+#endif // defined(ASIO_HAS_STD_ARRAY)+ return bytes;+}++std::string address_v6::to_string() const+{+ asio::error_code ec;+ char addr_str[asio::detail::max_addr_v6_str_len];+ const char* addr =+ asio::detail::socket_ops::inet_ntop(+ ASIO_OS_DEF(AF_INET6), &addr_, addr_str,+ asio::detail::max_addr_v6_str_len, scope_id_, ec);+ if (addr == 0)+ asio::detail::throw_error(ec);+ return addr;+}++#if !defined(ASIO_NO_DEPRECATED)+std::string address_v6::to_string(asio::error_code& ec) const+{+ char addr_str[asio::detail::max_addr_v6_str_len];+ const char* addr =+ asio::detail::socket_ops::inet_ntop(+ ASIO_OS_DEF(AF_INET6), &addr_, addr_str,+ asio::detail::max_addr_v6_str_len, scope_id_, ec);+ if (addr == 0)+ return std::string();+ return addr;+}++address_v4 address_v6::to_v4() const+{+ if (!is_v4_mapped() && !is_v4_compatible())+ {+ bad_address_cast ex;+ asio::detail::throw_exception(ex);+ }++ address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12],+ addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } };+ return address_v4(v4_bytes);+}+#endif // !defined(ASIO_NO_DEPRECATED)++bool address_v6::is_loopback() const ASIO_NOEXCEPT+{+ return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)+ && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)+ && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)+ && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)+ && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)+ && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)+ && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)+ && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1));+}++bool address_v6::is_unspecified() const ASIO_NOEXCEPT+{+ return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)+ && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)+ && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)+ && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)+ && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)+ && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)+ && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0)+ && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0));+}++bool address_v6::is_link_local() const ASIO_NOEXCEPT+{+ return ((addr_.s6_addr[0] == 0xfe) && ((addr_.s6_addr[1] & 0xc0) == 0x80));+}++bool address_v6::is_site_local() const ASIO_NOEXCEPT+{+ return ((addr_.s6_addr[0] == 0xfe) && ((addr_.s6_addr[1] & 0xc0) == 0xc0));+}++bool address_v6::is_v4_mapped() const ASIO_NOEXCEPT+{+ return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)+ && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)+ && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)+ && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)+ && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)+ && (addr_.s6_addr[10] == 0xff) && (addr_.s6_addr[11] == 0xff));+}++#if !defined(ASIO_NO_DEPRECATED)+bool address_v6::is_v4_compatible() const+{+ return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0)+ && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0)+ && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0)+ && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0)+ && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0)+ && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0)+ && !((addr_.s6_addr[12] == 0)+ && (addr_.s6_addr[13] == 0)+ && (addr_.s6_addr[14] == 0)+ && ((addr_.s6_addr[15] == 0) || (addr_.s6_addr[15] == 1))));+}+#endif // !defined(ASIO_NO_DEPRECATED)++bool address_v6::is_multicast() const ASIO_NOEXCEPT+{+ return (addr_.s6_addr[0] == 0xff);+}++bool address_v6::is_multicast_global() const ASIO_NOEXCEPT+{+ return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x0e));+}++bool address_v6::is_multicast_link_local() const ASIO_NOEXCEPT+{+ return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x02));+}++bool address_v6::is_multicast_node_local() const ASIO_NOEXCEPT+{+ return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x01));+}++bool address_v6::is_multicast_org_local() const ASIO_NOEXCEPT+{+ return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x08));+}++bool address_v6::is_multicast_site_local() const ASIO_NOEXCEPT+{+ return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x05));+}++bool operator==(const address_v6& a1, const address_v6& a2) ASIO_NOEXCEPT+{+ using namespace std; // For memcmp.+ return memcmp(&a1.addr_, &a2.addr_,+ sizeof(asio::detail::in6_addr_type)) == 0+ && a1.scope_id_ == a2.scope_id_;+}++bool operator<(const address_v6& a1, const address_v6& a2) ASIO_NOEXCEPT+{+ using namespace std; // For memcmp.+ int memcmp_result = memcmp(&a1.addr_, &a2.addr_,+ sizeof(asio::detail::in6_addr_type));+ if (memcmp_result < 0)+ return true;+ if (memcmp_result > 0)+ return false;+ return a1.scope_id_ < a2.scope_id_;+}++address_v6 address_v6::loopback() ASIO_NOEXCEPT+{+ address_v6 tmp;+ tmp.addr_.s6_addr[15] = 1;+ return tmp;+}++#if !defined(ASIO_NO_DEPRECATED)+address_v6 address_v6::v4_mapped(const address_v4& addr)+{+ address_v4::bytes_type v4_bytes = addr.to_bytes();+ bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF,+ v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };+ return address_v6(v6_bytes);+}++address_v6 address_v6::v4_compatible(const address_v4& addr)+{+ address_v4::bytes_type v4_bytes = addr.to_bytes();+ bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,+ v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };+ return address_v6(v6_bytes);+}+#endif // !defined(ASIO_NO_DEPRECATED)++address_v6 make_address_v6(const char* str)+{+ asio::error_code ec;+ address_v6 addr = make_address_v6(str, ec);+ asio::detail::throw_error(ec);+ return addr;+}++address_v6 make_address_v6(const char* str,+ asio::error_code& ec) ASIO_NOEXCEPT+{+ address_v6::bytes_type bytes;+ unsigned long scope_id = 0;+ if (asio::detail::socket_ops::inet_pton(+ ASIO_OS_DEF(AF_INET6), str, &bytes[0], &scope_id, ec) <= 0)+ return address_v6();+ return address_v6(bytes, scope_id);+}++address_v6 make_address_v6(const std::string& str)+{+ return make_address_v6(str.c_str());+}++address_v6 make_address_v6(const std::string& str,+ asio::error_code& ec) ASIO_NOEXCEPT+{+ return make_address_v6(str.c_str(), ec);+}++#if defined(ASIO_HAS_STRING_VIEW)++address_v6 make_address_v6(string_view str)+{+ return make_address_v6(static_cast<std::string>(str));+}++address_v6 make_address_v6(string_view str,+ asio::error_code& ec) ASIO_NOEXCEPT+{+ return make_address_v6(static_cast<std::string>(str), ec);+}++#endif // defined(ASIO_HAS_STRING_VIEW)++address_v4 make_address_v4(+ v4_mapped_t, const address_v6& v6_addr)+{+ if (!v6_addr.is_v4_mapped())+ {+ bad_address_cast ex;+ asio::detail::throw_exception(ex);+ }++ address_v6::bytes_type v6_bytes = v6_addr.to_bytes();+ address_v4::bytes_type v4_bytes = { { v6_bytes[12],+ v6_bytes[13], v6_bytes[14], v6_bytes[15] } };+ return address_v4(v4_bytes);+}++address_v6 make_address_v6(+ v4_mapped_t, const address_v4& v4_addr)+{+ address_v4::bytes_type v4_bytes = v4_addr.to_bytes();+ address_v6::bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,+ 0xFF, 0xFF, v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } };+ return address_v6(v6_bytes);+}++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_IMPL_ADDRESS_V6_IPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/basic_endpoint.hpp view
@@ -0,0 +1,43 @@+//+// ip/impl/basic_endpoint.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_IMPL_BASIC_ENDPOINT_HPP+#define ASIO_IP_IMPL_BASIC_ENDPOINT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#if !defined(ASIO_NO_IOSTREAM)++#include "asio/detail/throw_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++template <typename Elem, typename Traits, typename InternetProtocol>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os,+ const basic_endpoint<InternetProtocol>& endpoint)+{+ asio::ip::detail::endpoint tmp_ep(endpoint.address(), endpoint.port());+ return os << tmp_ep.to_string().c_str();+}++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_IOSTREAM)++#endif // ASIO_IP_IMPL_BASIC_ENDPOINT_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/host_name.ipp view
@@ -0,0 +1,54 @@+//+// ip/impl/host_name.ipp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_IMPL_HOST_NAME_IPP+#define ASIO_IP_IMPL_HOST_NAME_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/winsock_init.hpp"+#include "asio/ip/host_name.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++std::string host_name()+{+ char name[1024];+ asio::error_code ec;+ if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)+ {+ asio::detail::throw_error(ec);+ return std::string();+ }+ return std::string(name);+}++std::string host_name(asio::error_code& ec)+{+ char name[1024];+ if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0)+ return std::string();+ return std::string(name);+}++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_IMPL_HOST_NAME_IPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/network_v4.hpp view
@@ -0,0 +1,54 @@+//+// ip/impl/network_v4.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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_IP_IMPL_NETWORK_V4_HPP+#define ASIO_IP_IMPL_NETWORK_V4_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#if !defined(ASIO_NO_IOSTREAM)++#include "asio/detail/throw_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++template <typename Elem, typename Traits>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os, const network_v4& addr)+{+ asio::error_code ec;+ std::string s = addr.to_string(ec);+ if (ec)+ {+ if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)+ asio::detail::throw_error(ec);+ else+ os.setstate(std::basic_ostream<Elem, Traits>::failbit);+ }+ else+ for (std::string::iterator i = s.begin(); i != s.end(); ++i)+ os << os.widen(*i);+ return os;+}++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_IOSTREAM)++#endif // ASIO_IP_IMPL_NETWORK_V4_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/network_v4.ipp view
@@ -0,0 +1,216 @@+//+// ip/impl/network_v4.ipp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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_IP_IMPL_NETWORK_V4_IPP+#define ASIO_IP_IMPL_NETWORK_V4_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <climits>+#include <cstdio>+#include <cstdlib>+#include <stdexcept>+#include "asio/error.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/ip/network_v4.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++network_v4::network_v4(const address_v4& addr, unsigned short prefix_len)+ : address_(addr),+ prefix_length_(prefix_len)+{+ if (prefix_len > 32)+ {+ std::out_of_range ex("prefix length too large");+ asio::detail::throw_exception(ex);+ }+}++network_v4::network_v4(const address_v4& addr, const address_v4& mask)+ : address_(addr),+ prefix_length_(0)+{+ address_v4::bytes_type mask_bytes = mask.to_bytes();+ bool finished = false;+ for (std::size_t i = 0; i < mask_bytes.size(); ++i)+ {+ if (finished)+ {+ if (mask_bytes[i])+ {+ std::invalid_argument ex("non-contiguous netmask");+ asio::detail::throw_exception(ex);+ }+ continue;+ }+ else+ {+ switch (mask_bytes[i])+ {+ case 255:+ prefix_length_ += 8;+ break;+ case 254: // prefix_length_ += 7+ prefix_length_ += 1;+ case 252: // prefix_length_ += 6+ prefix_length_ += 1;+ case 248: // prefix_length_ += 5+ prefix_length_ += 1;+ case 240: // prefix_length_ += 4+ prefix_length_ += 1;+ case 224: // prefix_length_ += 3+ prefix_length_ += 1;+ case 192: // prefix_length_ += 2+ prefix_length_ += 1;+ case 128: // prefix_length_ += 1+ prefix_length_ += 1;+ case 0: // nbits += 0+ finished = true;+ break;+ default:+ std::out_of_range ex("non-contiguous netmask");+ asio::detail::throw_exception(ex);+ }+ }+ }+}++address_v4 network_v4::netmask() const ASIO_NOEXCEPT+{+ uint32_t nmbits = 0xffffffff;+ if (prefix_length_ == 0)+ nmbits = 0;+ else+ nmbits = nmbits << (32 - prefix_length_);+ return address_v4(nmbits);+}++address_v4_range network_v4::hosts() const ASIO_NOEXCEPT+{+ return is_host()+ ? address_v4_range(address_, address_v4(address_.to_uint() + 1))+ : address_v4_range(address_v4(network().to_uint() + 1), broadcast());+}++bool network_v4::is_subnet_of(const network_v4& other) const+{+ if (other.prefix_length_ >= prefix_length_)+ return false; // Only real subsets are allowed.+ const network_v4 me(address_, other.prefix_length_);+ return other.canonical() == me.canonical();+}++std::string network_v4::to_string() const+{+ asio::error_code ec;+ std::string addr = to_string(ec);+ asio::detail::throw_error(ec);+ return addr;+}++std::string network_v4::to_string(asio::error_code& ec) const+{+ using namespace std; // For sprintf.+ ec = asio::error_code();+ char prefix_len[16];+#if defined(ASIO_HAS_SECURE_RTL)+ sprintf_s(prefix_len, sizeof(prefix_len), "/%u", prefix_length_);+#else // defined(ASIO_HAS_SECURE_RTL)+ sprintf(prefix_len, "/%u", prefix_length_);+#endif // defined(ASIO_HAS_SECURE_RTL)+ return address_.to_string() + prefix_len;+}++network_v4 make_network_v4(const char* str)+{+ return make_network_v4(std::string(str));+}++network_v4 make_network_v4(const char* str, asio::error_code& ec)+{+ return make_network_v4(std::string(str), ec);+}++network_v4 make_network_v4(const std::string& str)+{+ asio::error_code ec;+ network_v4 net = make_network_v4(str, ec);+ asio::detail::throw_error(ec);+ return net;+}++network_v4 make_network_v4(const std::string& str,+ asio::error_code& ec)+{+ std::string::size_type pos = str.find_first_of("/");++ if (pos == std::string::npos)+ {+ ec = asio::error::invalid_argument;+ return network_v4();+ }++ if (pos == str.size() - 1)+ {+ ec = asio::error::invalid_argument;+ return network_v4();+ }++ std::string::size_type end = str.find_first_not_of("0123456789", pos + 1);+ if (end != std::string::npos)+ {+ ec = asio::error::invalid_argument;+ return network_v4();+ }++ const address_v4 addr = make_address_v4(str.substr(0, pos), ec);+ if (ec)+ return network_v4();++ const int prefix_len = std::atoi(str.substr(pos + 1).c_str());+ if (prefix_len < 0 || prefix_len > 32)+ {+ ec = asio::error::invalid_argument;+ return network_v4();+ }++ return network_v4(addr, static_cast<unsigned short>(prefix_len));+}++#if defined(ASIO_HAS_STRING_VIEW)++network_v4 make_network_v4(string_view str)+{+ return make_network_v4(static_cast<std::string>(str));+}++network_v4 make_network_v4(string_view str,+ asio::error_code& ec)+{+ return make_network_v4(static_cast<std::string>(str), ec);+}++#endif // defined(ASIO_HAS_STRING_VIEW)++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_IMPL_NETWORK_V4_IPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/network_v6.hpp view
@@ -0,0 +1,53 @@+//+// ip/impl/network_v6.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_IMPL_NETWORK_V6_HPP+#define ASIO_IP_IMPL_NETWORK_V6_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#if !defined(ASIO_NO_IOSTREAM)++#include "asio/detail/throw_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++template <typename Elem, typename Traits>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os, const network_v6& addr)+{+ asio::error_code ec;+ std::string s = addr.to_string(ec);+ if (ec)+ {+ if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit)+ asio::detail::throw_error(ec);+ else+ os.setstate(std::basic_ostream<Elem, Traits>::failbit);+ }+ else+ for (std::string::iterator i = s.begin(); i != s.end(); ++i)+ os << os.widen(*i);+ return os;+}++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_IOSTREAM)++#endif // ASIO_IP_IMPL_NETWORK_V6_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/impl/network_v6.ipp view
@@ -0,0 +1,185 @@+//+// ip/impl/network_v6.ipp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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_IP_IMPL_NETWORK_V6_IPP+#define ASIO_IP_IMPL_NETWORK_V6_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <climits>+#include <cstdio>+#include <cstdlib>+#include <stdexcept>+#include "asio/error.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/throw_exception.hpp"+#include "asio/ip/network_v6.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++network_v6::network_v6(const address_v6& addr, unsigned short prefix_len)+ : address_(addr),+ prefix_length_(prefix_len)+{+ if (prefix_len > 128)+ {+ std::out_of_range ex("prefix length too large");+ asio::detail::throw_exception(ex);+ }+}++ASIO_DECL address_v6 network_v6::network() const ASIO_NOEXCEPT+{+ address_v6::bytes_type bytes(address_.to_bytes());+ for (std::size_t i = 0; i < 16; ++i)+ {+ if (prefix_length_ <= i * 8)+ bytes[i] = 0;+ else if (prefix_length_ < (i + 1) * 8)+ bytes[i] &= 0xFF00 >> (prefix_length_ % 8);+ }+ return address_v6(bytes, address_.scope_id());+}++address_v6_range network_v6::hosts() const ASIO_NOEXCEPT+{+ address_v6::bytes_type begin_bytes(address_.to_bytes());+ address_v6::bytes_type end_bytes(address_.to_bytes());+ for (std::size_t i = 0; i < 16; ++i)+ {+ if (prefix_length_ <= i * 8)+ {+ begin_bytes[i] = 0;+ end_bytes[i] = 0xFF;+ }+ else if (prefix_length_ < (i + 1) * 8)+ {+ begin_bytes[i] &= 0xFF00 >> (prefix_length_ % 8);+ end_bytes[i] |= 0xFF >> (prefix_length_ % 8);+ }+ }+ return address_v6_range(+ address_v6_iterator(address_v6(begin_bytes, address_.scope_id())),+ ++address_v6_iterator(address_v6(end_bytes, address_.scope_id())));+}++bool network_v6::is_subnet_of(const network_v6& other) const+{+ if (other.prefix_length_ >= prefix_length_)+ return false; // Only real subsets are allowed.+ const network_v6 me(address_, other.prefix_length_);+ return other.canonical() == me.canonical();+}++std::string network_v6::to_string() const+{+ asio::error_code ec;+ std::string addr = to_string(ec);+ asio::detail::throw_error(ec);+ return addr;+}++std::string network_v6::to_string(asio::error_code& ec) const+{+ using namespace std; // For sprintf.+ ec = asio::error_code();+ char prefix_len[16];+#if defined(ASIO_HAS_SECURE_RTL)+ sprintf_s(prefix_len, sizeof(prefix_len), "/%u", prefix_length_);+#else // defined(ASIO_HAS_SECURE_RTL)+ sprintf(prefix_len, "/%u", prefix_length_);+#endif // defined(ASIO_HAS_SECURE_RTL)+ return address_.to_string() + prefix_len;+}++network_v6 make_network_v6(const char* str)+{+ return make_network_v6(std::string(str));+}++network_v6 make_network_v6(const char* str, asio::error_code& ec)+{+ return make_network_v6(std::string(str), ec);+}++network_v6 make_network_v6(const std::string& str)+{+ asio::error_code ec;+ network_v6 net = make_network_v6(str, ec);+ asio::detail::throw_error(ec);+ return net;+}++network_v6 make_network_v6(const std::string& str,+ asio::error_code& ec)+{+ std::string::size_type pos = str.find_first_of("/");++ if (pos == std::string::npos)+ {+ ec = asio::error::invalid_argument;+ return network_v6();+ }++ if (pos == str.size() - 1)+ {+ ec = asio::error::invalid_argument;+ return network_v6();+ }++ std::string::size_type end = str.find_first_not_of("0123456789", pos + 1);+ if (end != std::string::npos)+ {+ ec = asio::error::invalid_argument;+ return network_v6();+ }++ const address_v6 addr = make_address_v6(str.substr(0, pos), ec);+ if (ec)+ return network_v6();++ const int prefix_len = std::atoi(str.substr(pos + 1).c_str());+ if (prefix_len < 0 || prefix_len > 128)+ {+ ec = asio::error::invalid_argument;+ return network_v6();+ }++ return network_v6(addr, static_cast<unsigned short>(prefix_len));+}++#if defined(ASIO_HAS_STRING_VIEW)++network_v6 make_network_v6(string_view str)+{+ return make_network_v6(static_cast<std::string>(str));+}++network_v6 make_network_v6(string_view str,+ asio::error_code& ec)+{+ return make_network_v6(static_cast<std::string>(str), ec);+}++#endif // defined(ASIO_HAS_STRING_VIEW)++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_IMPL_NETWORK_V6_IPP
+ link/modules/asio-standalone/asio/include/asio/ip/multicast.hpp view
@@ -0,0 +1,191 @@+//+// ip/multicast.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_MULTICAST_HPP+#define ASIO_IP_MULTICAST_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/ip/detail/socket_option.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {+namespace multicast {++/// Socket option to join a multicast group on a specified interface.+/**+ * Implements the IPPROTO_IP/IP_ADD_MEMBERSHIP socket option.+ *+ * @par Examples+ * Setting the option to join a multicast group:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::ip::address multicast_address =+ * asio::ip::address::from_string("225.0.0.1");+ * asio::ip::multicast::join_group option(multicast_address);+ * socket.set_option(option);+ * @endcode+ *+ * @par Concepts:+ * SettableSocketOption.+ */+#if defined(GENERATING_DOCUMENTATION)+typedef implementation_defined join_group;+#else+typedef asio::ip::detail::socket_option::multicast_request<+ ASIO_OS_DEF(IPPROTO_IP),+ ASIO_OS_DEF(IP_ADD_MEMBERSHIP),+ ASIO_OS_DEF(IPPROTO_IPV6),+ ASIO_OS_DEF(IPV6_JOIN_GROUP)> join_group;+#endif++/// Socket option to leave a multicast group on a specified interface.+/**+ * Implements the IPPROTO_IP/IP_DROP_MEMBERSHIP socket option.+ *+ * @par Examples+ * Setting the option to leave a multicast group:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::ip::address multicast_address =+ * asio::ip::address::from_string("225.0.0.1");+ * asio::ip::multicast::leave_group option(multicast_address);+ * socket.set_option(option);+ * @endcode+ *+ * @par Concepts:+ * SettableSocketOption.+ */+#if defined(GENERATING_DOCUMENTATION)+typedef implementation_defined leave_group;+#else+typedef asio::ip::detail::socket_option::multicast_request<+ ASIO_OS_DEF(IPPROTO_IP),+ ASIO_OS_DEF(IP_DROP_MEMBERSHIP),+ ASIO_OS_DEF(IPPROTO_IPV6),+ ASIO_OS_DEF(IPV6_LEAVE_GROUP)> leave_group;+#endif++/// Socket option for local interface to use for outgoing multicast packets.+/**+ * Implements the IPPROTO_IP/IP_MULTICAST_IF socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::ip::address_v4 local_interface =+ * asio::ip::address_v4::from_string("1.2.3.4");+ * asio::ip::multicast::outbound_interface option(local_interface);+ * socket.set_option(option);+ * @endcode+ *+ * @par Concepts:+ * SettableSocketOption.+ */+#if defined(GENERATING_DOCUMENTATION)+typedef implementation_defined outbound_interface;+#else+typedef asio::ip::detail::socket_option::network_interface<+ ASIO_OS_DEF(IPPROTO_IP),+ ASIO_OS_DEF(IP_MULTICAST_IF),+ ASIO_OS_DEF(IPPROTO_IPV6),+ ASIO_OS_DEF(IPV6_MULTICAST_IF)> outbound_interface;+#endif++/// Socket option for time-to-live associated with outgoing multicast packets.+/**+ * Implements the IPPROTO_IP/IP_MULTICAST_TTL socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::ip::multicast::hops option(4);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::ip::multicast::hops option;+ * socket.get_option(option);+ * int ttl = option.value();+ * @endcode+ *+ * @par Concepts:+ * GettableSocketOption, SettableSocketOption.+ */+#if defined(GENERATING_DOCUMENTATION)+typedef implementation_defined hops;+#else+typedef asio::ip::detail::socket_option::multicast_hops<+ ASIO_OS_DEF(IPPROTO_IP),+ ASIO_OS_DEF(IP_MULTICAST_TTL),+ ASIO_OS_DEF(IPPROTO_IPV6),+ ASIO_OS_DEF(IPV6_MULTICAST_HOPS)> hops;+#endif++/// Socket option determining whether outgoing multicast packets will be+/// received on the same socket if it is a member of the multicast group.+/**+ * Implements the IPPROTO_IP/IP_MULTICAST_LOOP socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::ip::multicast::enable_loopback option(true);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::ip::multicast::enable_loopback option;+ * socket.get_option(option);+ * bool is_set = option.value();+ * @endcode+ *+ * @par Concepts:+ * GettableSocketOption, SettableSocketOption.+ */+#if defined(GENERATING_DOCUMENTATION)+typedef implementation_defined enable_loopback;+#else+typedef asio::ip::detail::socket_option::multicast_enable_loopback<+ ASIO_OS_DEF(IPPROTO_IP),+ ASIO_OS_DEF(IP_MULTICAST_LOOP),+ ASIO_OS_DEF(IPPROTO_IPV6),+ ASIO_OS_DEF(IPV6_MULTICAST_LOOP)> enable_loopback;+#endif++} // namespace multicast+} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_MULTICAST_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/network_v4.hpp view
@@ -0,0 +1,261 @@+//+// ip/network_v4.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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_IP_NETWORK_V4_HPP+#define ASIO_IP_NETWORK_V4_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <string>+#include "asio/detail/string_view.hpp"+#include "asio/error_code.hpp"+#include "asio/ip/address_v4_range.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// Represents an IPv4 network.+/**+ * The asio::ip::network_v4 class provides the ability to use and+ * manipulate IP version 4 networks.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+class network_v4+{+public:+ /// Default constructor.+ network_v4() ASIO_NOEXCEPT+ : address_(),+ prefix_length_(0)+ {+ }++ /// Construct a network based on the specified address and prefix length.+ ASIO_DECL network_v4(const address_v4& addr,+ unsigned short prefix_len);++ /// Construct network based on the specified address and netmask.+ ASIO_DECL network_v4(const address_v4& addr,+ const address_v4& mask);++ /// Copy constructor.+ network_v4(const network_v4& other) ASIO_NOEXCEPT+ : address_(other.address_),+ prefix_length_(other.prefix_length_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ /// Move constructor.+ network_v4(network_v4&& other) ASIO_NOEXCEPT+ : address_(ASIO_MOVE_CAST(address_v4)(other.address_)),+ prefix_length_(other.prefix_length_)+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Assign from another network.+ network_v4& operator=(const network_v4& other) ASIO_NOEXCEPT+ {+ address_ = other.address_;+ prefix_length_ = other.prefix_length_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE)+ /// Move-assign from another network.+ network_v4& operator=(network_v4&& other) ASIO_NOEXCEPT+ {+ address_ = ASIO_MOVE_CAST(address_v4)(other.address_);+ prefix_length_ = other.prefix_length_;+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Obtain the address object specified when the network object was created.+ address_v4 address() const ASIO_NOEXCEPT+ {+ return address_;+ }++ /// Obtain the prefix length that was specified when the network object was+ /// created.+ unsigned short prefix_length() const ASIO_NOEXCEPT+ {+ return prefix_length_;+ }++ /// Obtain the netmask that was specified when the network object was created.+ ASIO_DECL address_v4 netmask() const ASIO_NOEXCEPT;++ /// Obtain an address object that represents the network address.+ address_v4 network() const ASIO_NOEXCEPT+ {+ return address_v4(address_.to_uint() & netmask().to_uint());+ }++ /// Obtain an address object that represents the network's broadcast address.+ address_v4 broadcast() const ASIO_NOEXCEPT+ {+ return address_v4(network().to_uint() | (netmask().to_uint() ^ 0xFFFFFFFF));+ }++ /// Obtain an address range corresponding to the hosts in the network.+ ASIO_DECL address_v4_range hosts() const ASIO_NOEXCEPT;++ /// Obtain the true network address, omitting any host bits.+ network_v4 canonical() const ASIO_NOEXCEPT+ {+ return network_v4(network(), netmask());+ }++ /// Test if network is a valid host address.+ bool is_host() const ASIO_NOEXCEPT+ {+ return prefix_length_ == 32;+ }++ /// Test if a network is a real subnet of another network.+ ASIO_DECL bool is_subnet_of(const network_v4& other) const;++ /// Get the network as an address in dotted decimal format.+ ASIO_DECL std::string to_string() const;++ /// Get the network as an address in dotted decimal format.+ ASIO_DECL std::string to_string(asio::error_code& ec) const;++ /// Compare two networks for equality.+ friend bool operator==(const network_v4& a, const network_v4& b)+ {+ return a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_;+ }++ /// Compare two networks for inequality.+ friend bool operator!=(const network_v4& a, const network_v4& b)+ {+ return !(a == b);+ }++private:+ address_v4 address_;+ unsigned short prefix_length_;+};++/// Create an IPv4 network from an address and prefix length.+/**+ * @relates address_v4+ */+inline network_v4 make_network_v4(+ const address_v4& addr, unsigned short prefix_len)+{+ return network_v4(addr, prefix_len);+}++/// Create an IPv4 network from an address and netmask.+/**+ * @relates address_v4+ */+inline network_v4 make_network_v4(+ const address_v4& addr, const address_v4& mask)+{+ return network_v4(addr, mask);+}++/// Create an IPv4 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v4+ */+ASIO_DECL network_v4 make_network_v4(const char* str);++/// Create an IPv4 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v4+ */+ASIO_DECL network_v4 make_network_v4(+ const char* str, asio::error_code& ec);++/// Create an IPv4 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v4+ */+ASIO_DECL network_v4 make_network_v4(const std::string& str);++/// Create an IPv4 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v4+ */+ASIO_DECL network_v4 make_network_v4(+ const std::string& str, asio::error_code& ec);++#if defined(ASIO_HAS_STRING_VIEW) \+ || defined(GENERATING_DOCUMENTATION)++/// Create an IPv4 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v4+ */+ASIO_DECL network_v4 make_network_v4(string_view str);++/// Create an IPv4 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v4+ */+ASIO_DECL network_v4 make_network_v4(+ string_view str, asio::error_code& ec);++#endif // defined(ASIO_HAS_STRING_VIEW)+ // || defined(GENERATING_DOCUMENTATION)++#if !defined(ASIO_NO_IOSTREAM)++/// Output a network as a string.+/**+ * Used to output a human-readable string for a specified network.+ *+ * @param os The output stream to which the string will be written.+ *+ * @param net The network to be written.+ *+ * @return The output stream.+ *+ * @relates asio::ip::address_v4+ */+template <typename Elem, typename Traits>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os, const network_v4& net);++#endif // !defined(ASIO_NO_IOSTREAM)++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/ip/impl/network_v4.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/ip/impl/network_v4.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_IP_NETWORK_V4_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/network_v6.hpp view
@@ -0,0 +1,235 @@+//+// ip/network_v6.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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_IP_NETWORK_V6_HPP+#define ASIO_IP_NETWORK_V6_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <string>+#include "asio/detail/string_view.hpp"+#include "asio/error_code.hpp"+#include "asio/ip/address_v6_range.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// Represents an IPv6 network.+/**+ * The asio::ip::network_v6 class provides the ability to use and+ * manipulate IP version 6 networks.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+class network_v6+{+public:+ /// Default constructor.+ network_v6() ASIO_NOEXCEPT+ : address_(),+ prefix_length_(0)+ {+ }++ /// Construct a network based on the specified address and prefix length.+ ASIO_DECL network_v6(const address_v6& addr,+ unsigned short prefix_len);++ /// Copy constructor.+ network_v6(const network_v6& other) ASIO_NOEXCEPT+ : address_(other.address_),+ prefix_length_(other.prefix_length_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ /// Move constructor.+ network_v6(network_v6&& other) ASIO_NOEXCEPT+ : address_(ASIO_MOVE_CAST(address_v6)(other.address_)),+ prefix_length_(other.prefix_length_)+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Assign from another network.+ network_v6& operator=(const network_v6& other) ASIO_NOEXCEPT+ {+ address_ = other.address_;+ prefix_length_ = other.prefix_length_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE)+ /// Move-assign from another network.+ network_v6& operator=(network_v6&& other) ASIO_NOEXCEPT+ {+ address_ = ASIO_MOVE_CAST(address_v6)(other.address_);+ prefix_length_ = other.prefix_length_;+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Obtain the address object specified when the network object was created.+ address_v6 address() const ASIO_NOEXCEPT+ {+ return address_;+ }++ /// Obtain the prefix length that was specified when the network object was+ /// created.+ unsigned short prefix_length() const ASIO_NOEXCEPT+ {+ return prefix_length_;+ }++ /// Obtain an address object that represents the network address.+ ASIO_DECL address_v6 network() const ASIO_NOEXCEPT;++ /// Obtain an address range corresponding to the hosts in the network.+ ASIO_DECL address_v6_range hosts() const ASIO_NOEXCEPT;++ /// Obtain the true network address, omitting any host bits.+ network_v6 canonical() const ASIO_NOEXCEPT+ {+ return network_v6(network(), prefix_length());+ }++ /// Test if network is a valid host address.+ bool is_host() const ASIO_NOEXCEPT+ {+ return prefix_length_ == 128;+ }++ /// Test if a network is a real subnet of another network.+ ASIO_DECL bool is_subnet_of(const network_v6& other) const;++ /// Get the network as an address in dotted decimal format.+ ASIO_DECL std::string to_string() const;++ /// Get the network as an address in dotted decimal format.+ ASIO_DECL std::string to_string(asio::error_code& ec) const;++ /// Compare two networks for equality.+ friend bool operator==(const network_v6& a, const network_v6& b)+ {+ return a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_;+ }++ /// Compare two networks for inequality.+ friend bool operator!=(const network_v6& a, const network_v6& b)+ {+ return !(a == b);+ }++private:+ address_v6 address_;+ unsigned short prefix_length_;+};++/// Create an IPv6 network from an address and prefix length.+/**+ * @relates address_v6+ */+inline network_v6 make_network_v6(+ const address_v6& addr, unsigned short prefix_len)+{+ return network_v6(addr, prefix_len);+}++/// Create an IPv6 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v6+ */+ASIO_DECL network_v6 make_network_v6(const char* str);++/// Create an IPv6 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v6+ */+ASIO_DECL network_v6 make_network_v6(+ const char* str, asio::error_code& ec);++/// Create an IPv6 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v6+ */+ASIO_DECL network_v6 make_network_v6(const std::string& str);++/// Create an IPv6 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v6+ */+ASIO_DECL network_v6 make_network_v6(+ const std::string& str, asio::error_code& ec);++#if defined(ASIO_HAS_STRING_VIEW) \+ || defined(GENERATING_DOCUMENTATION)++/// Create an IPv6 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v6+ */+ASIO_DECL network_v6 make_network_v6(string_view str);++/// Create an IPv6 network from a string containing IP address and prefix+/// length.+/**+ * @relates network_v6+ */+ASIO_DECL network_v6 make_network_v6(+ string_view str, asio::error_code& ec);++#endif // defined(ASIO_HAS_STRING_VIEW)+ // || defined(GENERATING_DOCUMENTATION)++#if !defined(ASIO_NO_IOSTREAM)++/// Output a network as a string.+/**+ * Used to output a human-readable string for a specified network.+ *+ * @param os The output stream to which the string will be written.+ *+ * @param net The network to be written.+ *+ * @return The output stream.+ *+ * @relates asio::ip::address_v6+ */+template <typename Elem, typename Traits>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os, const network_v6& net);++#endif // !defined(ASIO_NO_IOSTREAM)++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/ip/impl/network_v6.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/ip/impl/network_v6.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_IP_NETWORK_V6_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/resolver_base.hpp view
@@ -0,0 +1,129 @@+//+// ip/resolver_base.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_RESOLVER_BASE_HPP+#define ASIO_IP_RESOLVER_BASE_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/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// The resolver_base class is used as a base for the basic_resolver class+/// templates to provide a common place to define the flag constants.+class resolver_base+{+public:+#if defined(GENERATING_DOCUMENTATION)+ /// A bitmask type (C++ Std [lib.bitmask.types]).+ typedef unspecified flags;++ /// Determine the canonical name of the host specified in the query.+ static const flags canonical_name = implementation_defined;++ /// Indicate that returned endpoint is intended for use as a locally bound+ /// socket endpoint.+ static const flags passive = implementation_defined;++ /// Host name should be treated as a numeric string defining an IPv4 or IPv6+ /// address and no name resolution should be attempted.+ static const flags numeric_host = implementation_defined;++ /// Service name should be treated as a numeric string defining a port number+ /// and no name resolution should be attempted.+ static const flags numeric_service = implementation_defined;++ /// If the query protocol family is specified as IPv6, return IPv4-mapped+ /// IPv6 addresses on finding no IPv6 addresses.+ static const flags v4_mapped = implementation_defined;++ /// If used with v4_mapped, return all matching IPv6 and IPv4 addresses.+ static const flags all_matching = implementation_defined;++ /// Only return IPv4 addresses if a non-loopback IPv4 address is configured+ /// for the system. Only return IPv6 addresses if a non-loopback IPv6 address+ /// is configured for the system.+ static const flags address_configured = implementation_defined;+#else+ enum flags+ {+ canonical_name = ASIO_OS_DEF(AI_CANONNAME),+ passive = ASIO_OS_DEF(AI_PASSIVE),+ numeric_host = ASIO_OS_DEF(AI_NUMERICHOST),+ numeric_service = ASIO_OS_DEF(AI_NUMERICSERV),+ v4_mapped = ASIO_OS_DEF(AI_V4MAPPED),+ all_matching = ASIO_OS_DEF(AI_ALL),+ address_configured = ASIO_OS_DEF(AI_ADDRCONFIG)+ };++ // Implement bitmask operations as shown in C++ Std [lib.bitmask.types].++ friend flags operator&(flags x, flags y)+ {+ return static_cast<flags>(+ static_cast<unsigned int>(x) & static_cast<unsigned int>(y));+ }++ friend flags operator|(flags x, flags y)+ {+ return static_cast<flags>(+ static_cast<unsigned int>(x) | static_cast<unsigned int>(y));+ }++ friend flags operator^(flags x, flags y)+ {+ return static_cast<flags>(+ static_cast<unsigned int>(x) ^ static_cast<unsigned int>(y));+ }++ friend flags operator~(flags x)+ {+ return static_cast<flags>(~static_cast<unsigned int>(x));+ }++ friend flags& operator&=(flags& x, flags y)+ {+ x = x & y;+ return x;+ }++ friend flags& operator|=(flags& x, flags y)+ {+ x = x | y;+ return x;+ }++ friend flags& operator^=(flags& x, flags y)+ {+ x = x ^ y;+ return x;+ }+#endif++protected:+ /// Protected destructor to prevent deletion through this type.+ ~resolver_base()+ {+ }+};++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_RESOLVER_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/resolver_query_base.hpp view
@@ -0,0 +1,43 @@+//+// ip/resolver_query_base.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_RESOLVER_QUERY_BASE_HPP+#define ASIO_IP_RESOLVER_QUERY_BASE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/ip/resolver_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// The resolver_query_base class is used as a base for the+/// basic_resolver_query class templates to provide a common place to define+/// the flag constants.+class resolver_query_base : public resolver_base+{+protected:+ /// Protected destructor to prevent deletion through this type.+ ~resolver_query_base()+ {+ }+};++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_RESOLVER_QUERY_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/tcp.hpp view
@@ -0,0 +1,155 @@+//+// ip/tcp.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_TCP_HPP+#define ASIO_IP_TCP_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/basic_socket_acceptor.hpp"+#include "asio/basic_socket_iostream.hpp"+#include "asio/basic_stream_socket.hpp"+#include "asio/detail/socket_option.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/ip/basic_endpoint.hpp"+#include "asio/ip/basic_resolver.hpp"+#include "asio/ip/basic_resolver_iterator.hpp"+#include "asio/ip/basic_resolver_query.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// Encapsulates the flags needed for TCP.+/**+ * The asio::ip::tcp class contains flags necessary for TCP sockets.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Safe.+ *+ * @par Concepts:+ * Protocol, InternetProtocol.+ */+class tcp+{+public:+ /// The type of a TCP endpoint.+ typedef basic_endpoint<tcp> endpoint;++ /// Construct to represent the IPv4 TCP protocol.+ static tcp v4() ASIO_NOEXCEPT+ {+ return tcp(ASIO_OS_DEF(AF_INET));+ }++ /// Construct to represent the IPv6 TCP protocol.+ static tcp v6() ASIO_NOEXCEPT+ {+ return tcp(ASIO_OS_DEF(AF_INET6));+ }++ /// Obtain an identifier for the type of the protocol.+ int type() const ASIO_NOEXCEPT+ {+ return ASIO_OS_DEF(SOCK_STREAM);+ }++ /// Obtain an identifier for the protocol.+ int protocol() const ASIO_NOEXCEPT+ {+ return ASIO_OS_DEF(IPPROTO_TCP);+ }++ /// Obtain an identifier for the protocol family.+ int family() const ASIO_NOEXCEPT+ {+ return family_;+ }++ /// The TCP socket type.+ typedef basic_stream_socket<tcp> socket;++ /// The TCP acceptor type.+ typedef basic_socket_acceptor<tcp> acceptor;++ /// The TCP resolver type.+ typedef basic_resolver<tcp> resolver;++#if !defined(ASIO_NO_IOSTREAM)+ /// The TCP iostream type.+ typedef basic_socket_iostream<tcp> iostream;+#endif // !defined(ASIO_NO_IOSTREAM)++ /// Socket option for disabling the Nagle algorithm.+ /**+ * Implements the IPPROTO_TCP/TCP_NODELAY socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::tcp::no_delay option(true);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::tcp::no_delay option;+ * socket.get_option(option);+ * bool is_set = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Boolean_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined no_delay;+#else+ typedef asio::detail::socket_option::boolean<+ ASIO_OS_DEF(IPPROTO_TCP), ASIO_OS_DEF(TCP_NODELAY)> no_delay;+#endif++ /// Compare two protocols for equality.+ friend bool operator==(const tcp& p1, const tcp& p2)+ {+ return p1.family_ == p2.family_;+ }++ /// Compare two protocols for inequality.+ friend bool operator!=(const tcp& p1, const tcp& p2)+ {+ return p1.family_ != p2.family_;+ }++private:+ // Construct with a specific family.+ explicit tcp(int protocol_family) ASIO_NOEXCEPT+ : family_(protocol_family)+ {+ }++ int family_;+};++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_TCP_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/udp.hpp view
@@ -0,0 +1,111 @@+//+// ip/udp.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_UDP_HPP+#define ASIO_IP_UDP_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/basic_datagram_socket.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/ip/basic_endpoint.hpp"+#include "asio/ip/basic_resolver.hpp"+#include "asio/ip/basic_resolver_iterator.hpp"+#include "asio/ip/basic_resolver_query.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// Encapsulates the flags needed for UDP.+/**+ * The asio::ip::udp class contains flags necessary for UDP sockets.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Safe.+ *+ * @par Concepts:+ * Protocol, InternetProtocol.+ */+class udp+{+public:+ /// The type of a UDP endpoint.+ typedef basic_endpoint<udp> endpoint;++ /// Construct to represent the IPv4 UDP protocol.+ static udp v4() ASIO_NOEXCEPT+ {+ return udp(ASIO_OS_DEF(AF_INET));+ }++ /// Construct to represent the IPv6 UDP protocol.+ static udp v6() ASIO_NOEXCEPT+ {+ return udp(ASIO_OS_DEF(AF_INET6));+ }++ /// Obtain an identifier for the type of the protocol.+ int type() const ASIO_NOEXCEPT+ {+ return ASIO_OS_DEF(SOCK_DGRAM);+ }++ /// Obtain an identifier for the protocol.+ int protocol() const ASIO_NOEXCEPT+ {+ return ASIO_OS_DEF(IPPROTO_UDP);+ }++ /// Obtain an identifier for the protocol family.+ int family() const ASIO_NOEXCEPT+ {+ return family_;+ }++ /// The UDP socket type.+ typedef basic_datagram_socket<udp> socket;++ /// The UDP resolver type.+ typedef basic_resolver<udp> resolver;++ /// Compare two protocols for equality.+ friend bool operator==(const udp& p1, const udp& p2)+ {+ return p1.family_ == p2.family_;+ }++ /// Compare two protocols for inequality.+ friend bool operator!=(const udp& p1, const udp& p2)+ {+ return p1.family_ != p2.family_;+ }++private:+ // Construct with a specific family.+ explicit udp(int protocol_family) ASIO_NOEXCEPT+ : family_(protocol_family)+ {+ }++ int family_;+};++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_UDP_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/unicast.hpp view
@@ -0,0 +1,70 @@+//+// ip/unicast.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_UNICAST_HPP+#define ASIO_IP_UNICAST_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/ip/detail/socket_option.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {+namespace unicast {++/// Socket option for time-to-live associated with outgoing unicast packets.+/**+ * Implements the IPPROTO_IP/IP_UNICAST_TTL socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::ip::unicast::hops option(4);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::ip::unicast::hops option;+ * socket.get_option(option);+ * int ttl = option.value();+ * @endcode+ *+ * @par Concepts:+ * GettableSocketOption, SettableSocketOption.+ */+#if defined(GENERATING_DOCUMENTATION)+typedef implementation_defined hops;+#else+typedef asio::ip::detail::socket_option::unicast_hops<+ ASIO_OS_DEF(IPPROTO_IP),+ ASIO_OS_DEF(IP_TTL),+ ASIO_OS_DEF(IPPROTO_IPV6),+ ASIO_OS_DEF(IPV6_UNICAST_HOPS)> hops;+#endif++} // namespace unicast+} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_UNICAST_HPP
+ link/modules/asio-standalone/asio/include/asio/ip/v6_only.hpp view
@@ -0,0 +1,69 @@+//+// ip/v6_only.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IP_V6_ONLY_HPP+#define ASIO_IP_V6_ONLY_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/socket_option.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ip {++/// Socket option for determining whether an IPv6 socket supports IPv6+/// communication only.+/**+ * Implements the IPPROTO_IPV6/IP_V6ONLY socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::v6_only option(true);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::ip::v6_only option;+ * socket.get_option(option);+ * bool v6_only = option.value();+ * @endcode+ *+ * @par Concepts:+ * GettableSocketOption, SettableSocketOption.+ */+#if defined(GENERATING_DOCUMENTATION)+typedef implementation_defined v6_only;+#elif defined(IPV6_V6ONLY)+typedef asio::detail::socket_option::boolean<+ IPPROTO_IPV6, IPV6_V6ONLY> v6_only;+#else+typedef asio::detail::socket_option::boolean<+ asio::detail::custom_socket_option_level,+ asio::detail::always_fail_option> v6_only;+#endif++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IP_V6_ONLY_HPP
+ link/modules/asio-standalone/asio/include/asio/is_applicable_property.hpp view
@@ -0,0 +1,61 @@+//+// is_applicable_property.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IS_APPLICABLE_PROPERTY_HPP+#define ASIO_IS_APPLICABLE_PROPERTY_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"++namespace asio {+namespace detail {++template <typename T, typename Property, typename = void>+struct is_applicable_property_trait : false_type+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename Property>+struct is_applicable_property_trait<T, Property,+ typename void_type<+ typename enable_if<+ !!Property::template is_applicable_property_v<T>+ >::type+ >::type> : true_type+{+};++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++} // namespace detail++template <typename T, typename Property, typename = void>+struct is_applicable_property :+ detail::is_applicable_property_trait<T, Property>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename Property>+ASIO_CONSTEXPR const bool is_applicable_property_v+ = is_applicable_property<T, Property>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++} // namespace asio++#endif // ASIO_IS_APPLICABLE_PROPERTY_HPP
+ link/modules/asio-standalone/asio/include/asio/is_executor.hpp view
@@ -0,0 +1,46 @@+//+// is_executor.hpp+// ~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IS_EXECUTOR_HPP+#define ASIO_IS_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/is_executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// The is_executor trait detects whether a type T meets the Executor type+/// requirements.+/**+ * Class template @c is_executor is a UnaryTypeTrait that is derived from @c+ * true_type if the type @c T meets the syntactic requirements for Executor,+ * otherwise @c false_type.+ */+template <typename T>+struct is_executor+#if defined(GENERATING_DOCUMENTATION)+ : integral_constant<bool, automatically_determined>+#else // defined(GENERATING_DOCUMENTATION)+ : asio::detail::is_executor<T>+#endif // defined(GENERATING_DOCUMENTATION)+{+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IS_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/is_read_buffered.hpp view
@@ -0,0 +1,59 @@+//+// is_read_buffered.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IS_READ_BUFFERED_HPP+#define ASIO_IS_READ_BUFFERED_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/buffered_read_stream_fwd.hpp"+#include "asio/buffered_stream_fwd.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++namespace detail {++template <typename Stream>+char is_read_buffered_helper(buffered_stream<Stream>* s);++template <typename Stream>+char is_read_buffered_helper(buffered_read_stream<Stream>* s);++struct is_read_buffered_big_type { char data[10]; };+is_read_buffered_big_type is_read_buffered_helper(...);++} // namespace detail++/// The is_read_buffered class is a traits class that may be used to determine+/// whether a stream type supports buffering of read data.+template <typename Stream>+class is_read_buffered+{+public:+#if defined(GENERATING_DOCUMENTATION)+ /// The value member is true only if the Stream type supports buffering of+ /// read data.+ static const bool value;+#else+ ASIO_STATIC_CONSTANT(bool,+ value = sizeof(detail::is_read_buffered_helper((Stream*)0)) == 1);+#endif+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IS_READ_BUFFERED_HPP
+ link/modules/asio-standalone/asio/include/asio/is_write_buffered.hpp view
@@ -0,0 +1,59 @@+//+// is_write_buffered.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_IS_WRITE_BUFFERED_HPP+#define ASIO_IS_WRITE_BUFFERED_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/buffered_stream_fwd.hpp"+#include "asio/buffered_write_stream_fwd.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++namespace detail {++template <typename Stream>+char is_write_buffered_helper(buffered_stream<Stream>* s);++template <typename Stream>+char is_write_buffered_helper(buffered_write_stream<Stream>* s);++struct is_write_buffered_big_type { char data[10]; };+is_write_buffered_big_type is_write_buffered_helper(...);++} // namespace detail++/// The is_write_buffered class is a traits class that may be used to determine+/// whether a stream type supports buffering of written data.+template <typename Stream>+class is_write_buffered+{+public:+#if defined(GENERATING_DOCUMENTATION)+ /// The value member is true only if the Stream type supports buffering of+ /// written data.+ static const bool value;+#else+ ASIO_STATIC_CONSTANT(bool,+ value = sizeof(detail::is_write_buffered_helper((Stream*)0)) == 1);+#endif+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_IS_WRITE_BUFFERED_HPP
+ link/modules/asio-standalone/asio/include/asio/local/basic_endpoint.hpp view
@@ -0,0 +1,247 @@+//+// local/basic_endpoint.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Derived from a public domain implementation written by Daniel Casimiro.+//+// 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_LOCAL_BASIC_ENDPOINT_HPP+#define ASIO_LOCAL_BASIC_ENDPOINT_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_LOCAL_SOCKETS) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/local/detail/endpoint.hpp"++#if !defined(ASIO_NO_IOSTREAM)+# include <iosfwd>+#endif // !defined(ASIO_NO_IOSTREAM)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace local {++/// Describes an endpoint for a UNIX socket.+/**+ * The asio::local::basic_endpoint class template describes an endpoint+ * that may be associated with a particular UNIX socket.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Concepts:+ * Endpoint.+ */+template <typename Protocol>+class basic_endpoint+{+public:+ /// The protocol type associated with the endpoint.+ typedef Protocol protocol_type;++ /// The type of the endpoint structure. This type is dependent on the+ /// underlying implementation of the socket layer.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined data_type;+#else+ typedef asio::detail::socket_addr_type data_type;+#endif++ /// Default constructor.+ basic_endpoint() ASIO_NOEXCEPT+ {+ }++ /// Construct an endpoint using the specified path name.+ basic_endpoint(const char* path_name)+ : impl_(path_name)+ {+ }++ /// Construct an endpoint using the specified path name.+ basic_endpoint(const std::string& path_name)+ : impl_(path_name)+ {+ }++ #if defined(ASIO_HAS_STRING_VIEW)+ /// Construct an endpoint using the specified path name.+ basic_endpoint(string_view path_name)+ : impl_(path_name)+ {+ }+ #endif // defined(ASIO_HAS_STRING_VIEW)++ /// Copy constructor.+ basic_endpoint(const basic_endpoint& other)+ : impl_(other.impl_)+ {+ }++#if defined(ASIO_HAS_MOVE)+ /// Move constructor.+ basic_endpoint(basic_endpoint&& other)+ : impl_(other.impl_)+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ /// Assign from another endpoint.+ basic_endpoint& operator=(const basic_endpoint& other)+ {+ impl_ = other.impl_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE)+ /// Move-assign from another endpoint.+ basic_endpoint& operator=(basic_endpoint&& other)+ {+ impl_ = other.impl_;+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE)++ /// The protocol associated with the endpoint.+ protocol_type protocol() const+ {+ return protocol_type();+ }++ /// Get the underlying endpoint in the native type.+ data_type* data()+ {+ return impl_.data();+ }++ /// Get the underlying endpoint in the native type.+ const data_type* data() const+ {+ return impl_.data();+ }++ /// Get the underlying size of the endpoint in the native type.+ std::size_t size() const+ {+ return impl_.size();+ }++ /// Set the underlying size of the endpoint in the native type.+ void resize(std::size_t new_size)+ {+ impl_.resize(new_size);+ }++ /// Get the capacity of the endpoint in the native type.+ std::size_t capacity() const+ {+ return impl_.capacity();+ }++ /// Get the path associated with the endpoint.+ std::string path() const+ {+ return impl_.path();+ }++ /// Set the path associated with the endpoint.+ void path(const char* p)+ {+ impl_.path(p);+ }++ /// Set the path associated with the endpoint.+ void path(const std::string& p)+ {+ impl_.path(p);+ }++ /// Compare two endpoints for equality.+ friend bool operator==(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return e1.impl_ == e2.impl_;+ }++ /// Compare two endpoints for inequality.+ friend bool operator!=(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return !(e1.impl_ == e2.impl_);+ }++ /// Compare endpoints for ordering.+ friend bool operator<(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return e1.impl_ < e2.impl_;+ }++ /// Compare endpoints for ordering.+ friend bool operator>(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return e2.impl_ < e1.impl_;+ }++ /// Compare endpoints for ordering.+ friend bool operator<=(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return !(e2 < e1);+ }++ /// Compare endpoints for ordering.+ friend bool operator>=(const basic_endpoint<Protocol>& e1,+ const basic_endpoint<Protocol>& e2)+ {+ return !(e1 < e2);+ }++private:+ // The underlying UNIX domain endpoint.+ asio::local::detail::endpoint impl_;+};++/// Output an endpoint as a string.+/**+ * Used to output a human-readable string for a specified endpoint.+ *+ * @param os The output stream to which the string will be written.+ *+ * @param endpoint The endpoint to be written.+ *+ * @return The output stream.+ *+ * @relates asio::local::basic_endpoint+ */+template <typename Elem, typename Traits, typename Protocol>+std::basic_ostream<Elem, Traits>& operator<<(+ std::basic_ostream<Elem, Traits>& os,+ const basic_endpoint<Protocol>& endpoint)+{+ os << endpoint.path();+ return os;+}++} // namespace local+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_LOCAL_SOCKETS)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_LOCAL_BASIC_ENDPOINT_HPP
+ link/modules/asio-standalone/asio/include/asio/local/connect_pair.hpp view
@@ -0,0 +1,101 @@+//+// local/connect_pair.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_LOCAL_CONNECT_PAIR_HPP+#define ASIO_LOCAL_CONNECT_PAIR_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_LOCAL_SOCKETS) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/basic_socket.hpp"+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"+#include "asio/local/basic_endpoint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace local {++/// Create a pair of connected sockets.+template <typename Protocol, typename Executor1, typename Executor2>+void connect_pair(basic_socket<Protocol, Executor1>& socket1,+ basic_socket<Protocol, Executor2>& socket2);++/// Create a pair of connected sockets.+template <typename Protocol, typename Executor1, typename Executor2>+ASIO_SYNC_OP_VOID connect_pair(basic_socket<Protocol, Executor1>& socket1,+ basic_socket<Protocol, Executor2>& socket2, asio::error_code& ec);++template <typename Protocol, typename Executor1, typename Executor2>+inline void connect_pair(basic_socket<Protocol, Executor1>& socket1,+ basic_socket<Protocol, Executor2>& socket2)+{+ asio::error_code ec;+ connect_pair(socket1, socket2, ec);+ asio::detail::throw_error(ec, "connect_pair");+}++template <typename Protocol, typename Executor1, typename Executor2>+inline ASIO_SYNC_OP_VOID connect_pair(+ basic_socket<Protocol, Executor1>& socket1,+ basic_socket<Protocol, Executor2>& socket2, asio::error_code& ec)+{+ // Check that this function is only being used with a UNIX domain socket.+ asio::local::basic_endpoint<Protocol>* tmp+ = static_cast<typename Protocol::endpoint*>(0);+ (void)tmp;++ Protocol protocol;+ asio::detail::socket_type sv[2];+ if (asio::detail::socket_ops::socketpair(protocol.family(),+ protocol.type(), protocol.protocol(), sv, ec)+ == asio::detail::socket_error_retval)+ ASIO_SYNC_OP_VOID_RETURN(ec);++ socket1.assign(protocol, sv[0], ec);+ if (ec)+ {+ asio::error_code temp_ec;+ asio::detail::socket_ops::state_type state[2] = { 0, 0 };+ asio::detail::socket_ops::close(sv[0], state[0], true, temp_ec);+ asio::detail::socket_ops::close(sv[1], state[1], true, temp_ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ socket2.assign(protocol, sv[1], ec);+ if (ec)+ {+ asio::error_code temp_ec;+ socket1.close(temp_ec);+ asio::detail::socket_ops::state_type state = 0;+ asio::detail::socket_ops::close(sv[1], state, true, temp_ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ ASIO_SYNC_OP_VOID_RETURN(ec);+}++} // namespace local+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_LOCAL_SOCKETS)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_LOCAL_CONNECT_PAIR_HPP
+ link/modules/asio-standalone/asio/include/asio/local/datagram_protocol.hpp view
@@ -0,0 +1,80 @@+//+// local/datagram_protocol.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_LOCAL_DATAGRAM_PROTOCOL_HPP+#define ASIO_LOCAL_DATAGRAM_PROTOCOL_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_LOCAL_SOCKETS) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/basic_datagram_socket.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/local/basic_endpoint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace local {++/// Encapsulates the flags needed for datagram-oriented UNIX sockets.+/**+ * The asio::local::datagram_protocol class contains flags necessary for+ * datagram-oriented UNIX domain sockets.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Safe.+ *+ * @par Concepts:+ * Protocol.+ */+class datagram_protocol+{+public:+ /// Obtain an identifier for the type of the protocol.+ int type() const ASIO_NOEXCEPT+ {+ return SOCK_DGRAM;+ }++ /// Obtain an identifier for the protocol.+ int protocol() const ASIO_NOEXCEPT+ {+ return 0;+ }++ /// Obtain an identifier for the protocol family.+ int family() const ASIO_NOEXCEPT+ {+ return AF_UNIX;+ }++ /// The type of a UNIX domain endpoint.+ typedef basic_endpoint<datagram_protocol> endpoint;++ /// The UNIX domain socket type.+ typedef basic_datagram_socket<datagram_protocol> socket;+};++} // namespace local+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_LOCAL_SOCKETS)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP
+ link/modules/asio-standalone/asio/include/asio/local/detail/endpoint.hpp view
@@ -0,0 +1,139 @@+//+// local/detail/endpoint.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Derived from a public domain implementation written by Daniel Casimiro.+//+// 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_LOCAL_DETAIL_ENDPOINT_HPP+#define ASIO_LOCAL_DETAIL_ENDPOINT_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_LOCAL_SOCKETS)++#include <cstddef>+#include <string>+#include "asio/detail/socket_types.hpp"+#include "asio/detail/string_view.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace local {+namespace detail {++// Helper class for implementing a UNIX domain endpoint.+class endpoint+{+public:+ // Default constructor.+ ASIO_DECL endpoint();++ // Construct an endpoint using the specified path name.+ ASIO_DECL endpoint(const char* path_name);++ // Construct an endpoint using the specified path name.+ ASIO_DECL endpoint(const std::string& path_name);++ #if defined(ASIO_HAS_STRING_VIEW)+ // Construct an endpoint using the specified path name.+ ASIO_DECL endpoint(string_view path_name);+ #endif // defined(ASIO_HAS_STRING_VIEW)++ // Copy constructor.+ endpoint(const endpoint& other)+ : data_(other.data_),+ path_length_(other.path_length_)+ {+ }++ // Assign from another endpoint.+ endpoint& operator=(const endpoint& other)+ {+ data_ = other.data_;+ path_length_ = other.path_length_;+ return *this;+ }++ // Get the underlying endpoint in the native type.+ asio::detail::socket_addr_type* data()+ {+ return &data_.base;+ }++ // Get the underlying endpoint in the native type.+ const asio::detail::socket_addr_type* data() const+ {+ return &data_.base;+ }++ // Get the underlying size of the endpoint in the native type.+ std::size_t size() const+ {+ return path_length_+ + offsetof(asio::detail::sockaddr_un_type, sun_path);+ }++ // Set the underlying size of the endpoint in the native type.+ ASIO_DECL void resize(std::size_t size);++ // Get the capacity of the endpoint in the native type.+ std::size_t capacity() const+ {+ return sizeof(asio::detail::sockaddr_un_type);+ }++ // Get the path associated with the endpoint.+ ASIO_DECL std::string path() const;++ // Set the path associated with the endpoint.+ ASIO_DECL void path(const char* p);++ // Set the path associated with the endpoint.+ ASIO_DECL void path(const std::string& p);++ // Compare two endpoints for equality.+ ASIO_DECL friend bool operator==(+ const endpoint& e1, const endpoint& e2);++ // Compare endpoints for ordering.+ ASIO_DECL friend bool operator<(+ const endpoint& e1, const endpoint& e2);++private:+ // The underlying UNIX socket address.+ union data_union+ {+ asio::detail::socket_addr_type base;+ asio::detail::sockaddr_un_type local;+ } data_;++ // The length of the path associated with the endpoint.+ std::size_t path_length_;++ // Initialise with a specified path.+ ASIO_DECL void init(const char* path, std::size_t path_length);+};++} // namespace detail+} // namespace local+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/local/detail/impl/endpoint.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_LOCAL_SOCKETS)++#endif // ASIO_LOCAL_DETAIL_ENDPOINT_HPP
+ link/modules/asio-standalone/asio/include/asio/local/detail/impl/endpoint.ipp view
@@ -0,0 +1,136 @@+//+// local/detail/impl/endpoint.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Derived from a public domain implementation written by Daniel Casimiro.+//+// 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_LOCAL_DETAIL_IMPL_ENDPOINT_IPP+#define ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP++#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_LOCAL_SOCKETS)++#include <cstring>+#include "asio/detail/socket_ops.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"+#include "asio/local/detail/endpoint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace local {+namespace detail {++endpoint::endpoint()+{+ init("", 0);+}++endpoint::endpoint(const char* path_name)+{+ using namespace std; // For strlen.+ init(path_name, strlen(path_name));+}++endpoint::endpoint(const std::string& path_name)+{+ init(path_name.data(), path_name.length());+}++#if defined(ASIO_HAS_STRING_VIEW)+endpoint::endpoint(string_view path_name)+{+ init(path_name.data(), path_name.length());+}+#endif // defined(ASIO_HAS_STRING_VIEW)++void endpoint::resize(std::size_t new_size)+{+ if (new_size > sizeof(asio::detail::sockaddr_un_type))+ {+ asio::error_code ec(asio::error::invalid_argument);+ asio::detail::throw_error(ec);+ }+ else if (new_size == 0)+ {+ path_length_ = 0;+ }+ else+ {+ path_length_ = new_size+ - offsetof(asio::detail::sockaddr_un_type, sun_path);++ // The path returned by the operating system may be NUL-terminated.+ if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0)+ --path_length_;+ }+}++std::string endpoint::path() const+{+ return std::string(data_.local.sun_path, path_length_);+}++void endpoint::path(const char* p)+{+ using namespace std; // For strlen.+ init(p, strlen(p));+}++void endpoint::path(const std::string& p)+{+ init(p.data(), p.length());+}++bool operator==(const endpoint& e1, const endpoint& e2)+{+ return e1.path() == e2.path();+}++bool operator<(const endpoint& e1, const endpoint& e2)+{+ return e1.path() < e2.path();+}++void endpoint::init(const char* path_name, std::size_t path_length)+{+ if (path_length > sizeof(data_.local.sun_path) - 1)+ {+ // The buffer is not large enough to store this address.+ asio::error_code ec(asio::error::name_too_long);+ asio::detail::throw_error(ec);+ }++ using namespace std; // For memcpy.+ data_.local = asio::detail::sockaddr_un_type();+ data_.local.sun_family = AF_UNIX;+ if (path_length > 0)+ memcpy(data_.local.sun_path, path_name, path_length);+ path_length_ = path_length;++ // NUL-terminate normal path names. Names that start with a NUL are in the+ // UNIX domain protocol's "abstract namespace" and are not NUL-terminated.+ if (path_length > 0 && data_.local.sun_path[0] == 0)+ data_.local.sun_path[path_length] = 0;+}++} // namespace detail+} // namespace local+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_LOCAL_SOCKETS)++#endif // ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP
+ link/modules/asio-standalone/asio/include/asio/local/stream_protocol.hpp view
@@ -0,0 +1,90 @@+//+// local/stream_protocol.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_LOCAL_STREAM_PROTOCOL_HPP+#define ASIO_LOCAL_STREAM_PROTOCOL_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_LOCAL_SOCKETS) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/basic_socket_acceptor.hpp"+#include "asio/basic_socket_iostream.hpp"+#include "asio/basic_stream_socket.hpp"+#include "asio/detail/socket_types.hpp"+#include "asio/local/basic_endpoint.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace local {++/// Encapsulates the flags needed for stream-oriented UNIX sockets.+/**+ * The asio::local::stream_protocol class contains flags necessary for+ * stream-oriented UNIX domain sockets.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Safe.+ *+ * @par Concepts:+ * Protocol.+ */+class stream_protocol+{+public:+ /// Obtain an identifier for the type of the protocol.+ int type() const ASIO_NOEXCEPT+ {+ return SOCK_STREAM;+ }++ /// Obtain an identifier for the protocol.+ int protocol() const ASIO_NOEXCEPT+ {+ return 0;+ }++ /// Obtain an identifier for the protocol family.+ int family() const ASIO_NOEXCEPT+ {+ return AF_UNIX;+ }++ /// The type of a UNIX domain endpoint.+ typedef basic_endpoint<stream_protocol> endpoint;++ /// The UNIX domain socket type.+ typedef basic_stream_socket<stream_protocol> socket;++ /// The UNIX domain acceptor type.+ typedef basic_socket_acceptor<stream_protocol> acceptor;++#if !defined(ASIO_NO_IOSTREAM)+ /// The UNIX domain iostream type.+ typedef basic_socket_iostream<stream_protocol> iostream;+#endif // !defined(ASIO_NO_IOSTREAM)+};++} // namespace local+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_LOCAL_SOCKETS)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_LOCAL_STREAM_PROTOCOL_HPP
+ link/modules/asio-standalone/asio/include/asio/multiple_exceptions.hpp view
@@ -0,0 +1,58 @@+//+// multiple_exceptions.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_MULTIPLE_EXCEPTIONS_HPP+#define ASIO_MULTIPLE_EXCEPTIONS_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <exception>+#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(ASIO_HAS_STD_EXCEPTION_PTR) \+ || defined(GENERATING_DOCUMENTATION)++/// Exception thrown when there are multiple pending exceptions to rethrow.+class multiple_exceptions+ : public std::exception+{+public:+ /// Constructor.+ ASIO_DECL multiple_exceptions(+ std::exception_ptr first) ASIO_NOEXCEPT;++ /// Obtain message associated with exception.+ ASIO_DECL virtual const char* what() const+ ASIO_NOEXCEPT_OR_NOTHROW;++ /// Obtain a pointer to the first exception.+ ASIO_DECL std::exception_ptr first_exception() const;++private:+ std::exception_ptr first_;+};++#endif // defined(ASIO_HAS_STD_EXCEPTION_PTR)+ // || defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/impl/multiple_exceptions.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_MULTIPLE_EXCEPTIONS_HPP
+ link/modules/asio-standalone/asio/include/asio/packaged_task.hpp view
@@ -0,0 +1,126 @@+//+// packaged_task.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_PACKAGED_TASK_HPP+#define ASIO_PACKAGED_TASK_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/future.hpp"++#if defined(ASIO_HAS_STD_FUTURE_CLASS) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/async_result.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/detail/variadic_templates.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \+ || defined(GENERATING_DOCUMENTATION)++/// Partial specialisation of @c async_result for @c std::packaged_task.+template <typename Result, typename... Args, typename Signature>+class async_result<std::packaged_task<Result(Args...)>, Signature>+{+public:+ /// The packaged task is the concrete completion handler type.+ typedef std::packaged_task<Result(Args...)> completion_handler_type;++ /// The return type of the initiating function is the future obtained from+ /// the packaged task.+ typedef std::future<Result> return_type;++ /// The constructor extracts the future from the packaged task.+ explicit async_result(completion_handler_type& h)+ : future_(h.get_future())+ {+ }++ /// Returns the packaged task's future.+ return_type get()+ {+ return std::move(future_);+ }++private:+ return_type future_;+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)++template <typename Result, typename Signature>+struct async_result<std::packaged_task<Result()>, Signature>+{+ typedef std::packaged_task<Result()> completion_handler_type;+ typedef std::future<Result> return_type;++ explicit async_result(completion_handler_type& h)+ : future_(h.get_future())+ {+ }++ return_type get()+ {+ return std::move(future_);+ }++private:+ return_type future_;+};++#define ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \+ template <typename Result, \+ ASIO_VARIADIC_TPARAMS(n), typename Signature> \+ class async_result< \+ std::packaged_task<Result(ASIO_VARIADIC_TARGS(n))>, Signature> \+ { \+ public: \+ typedef std::packaged_task< \+ Result(ASIO_VARIADIC_TARGS(n))> \+ completion_handler_type; \+ \+ typedef std::future<Result> return_type; \+ \+ explicit async_result(completion_handler_type& h) \+ : future_(h.get_future()) \+ { \+ } \+ \+ return_type get() \+ { \+ return std::move(future_); \+ } \+ \+ private: \+ return_type future_; \+ }; \+ /**/+ ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_RESULT_DEF)+#undef ASIO_PRIVATE_ASYNC_RESULT_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_STD_FUTURE_CLASS)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_PACKAGED_TASK_HPP
+ link/modules/asio-standalone/asio/include/asio/placeholders.hpp view
@@ -0,0 +1,151 @@+//+// placeholders.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_PLACEHOLDERS_HPP+#define ASIO_PLACEHOLDERS_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_BOOST_BIND)+# include <boost/bind/arg.hpp>+#endif // defined(ASIO_HAS_BOOST_BIND)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace placeholders {++#if defined(GENERATING_DOCUMENTATION)++/// An argument placeholder, for use with boost::bind(), that corresponds to+/// the error argument of a handler for any of the asynchronous functions.+unspecified error;++/// An argument placeholder, for use with boost::bind(), that corresponds to+/// the bytes_transferred argument of a handler for asynchronous functions such+/// as asio::basic_stream_socket::async_write_some or+/// asio::async_write.+unspecified bytes_transferred;++/// An argument placeholder, for use with boost::bind(), that corresponds to+/// the iterator argument of a handler for asynchronous functions such as+/// asio::async_connect.+unspecified iterator;++/// An argument placeholder, for use with boost::bind(), that corresponds to+/// the results argument of a handler for asynchronous functions such as+/// asio::basic_resolver::async_resolve.+unspecified results;++/// An argument placeholder, for use with boost::bind(), that corresponds to+/// the results argument of a handler for asynchronous functions such as+/// asio::async_connect.+unspecified endpoint;++/// An argument placeholder, for use with boost::bind(), that corresponds to+/// the signal_number argument of a handler for asynchronous functions such as+/// asio::signal_set::async_wait.+unspecified signal_number;++#elif defined(ASIO_HAS_BOOST_BIND)+# if defined(__BORLANDC__) || defined(__GNUC__)++inline boost::arg<1> error()+{+ return boost::arg<1>();+}++inline boost::arg<2> bytes_transferred()+{+ return boost::arg<2>();+}++inline boost::arg<2> iterator()+{+ return boost::arg<2>();+}++inline boost::arg<2> results()+{+ return boost::arg<2>();+}++inline boost::arg<2> endpoint()+{+ return boost::arg<2>();+}++inline boost::arg<2> signal_number()+{+ return boost::arg<2>();+}++# else++namespace detail+{+ template <int Number>+ struct placeholder+ {+ static boost::arg<Number>& get()+ {+ static boost::arg<Number> result;+ return result;+ }+ };+}++# if defined(ASIO_MSVC) && (ASIO_MSVC < 1400)++static boost::arg<1>& error+ = asio::placeholders::detail::placeholder<1>::get();+static boost::arg<2>& bytes_transferred+ = asio::placeholders::detail::placeholder<2>::get();+static boost::arg<2>& iterator+ = asio::placeholders::detail::placeholder<2>::get();+static boost::arg<2>& results+ = asio::placeholders::detail::placeholder<2>::get();+static boost::arg<2>& endpoint+ = asio::placeholders::detail::placeholder<2>::get();+static boost::arg<2>& signal_number+ = asio::placeholders::detail::placeholder<2>::get();++# else++namespace+{+ boost::arg<1>& error+ = asio::placeholders::detail::placeholder<1>::get();+ boost::arg<2>& bytes_transferred+ = asio::placeholders::detail::placeholder<2>::get();+ boost::arg<2>& iterator+ = asio::placeholders::detail::placeholder<2>::get();+ boost::arg<2>& results+ = asio::placeholders::detail::placeholder<2>::get();+ boost::arg<2>& endpoint+ = asio::placeholders::detail::placeholder<2>::get();+ boost::arg<2>& signal_number+ = asio::placeholders::detail::placeholder<2>::get();+} // namespace++# endif+# endif+#endif++} // namespace placeholders+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_PLACEHOLDERS_HPP
+ link/modules/asio-standalone/asio/include/asio/posix/basic_descriptor.hpp view
@@ -0,0 +1,697 @@+//+// posix/basic_descriptor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_BASIC_DESCRIPTOR_HPP+#define ASIO_POSIX_BASIC_DESCRIPTOR_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_POSIX_STREAM_DESCRIPTOR) \+ || defined(GENERATING_DOCUMENTATION)++#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/reactive_descriptor_service.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"+#include "asio/posix/descriptor_base.hpp"++#if defined(ASIO_HAS_MOVE)+# include <utility>+#endif // defined(ASIO_HAS_MOVE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace posix {++/// Provides POSIX descriptor functionality.+/**+ * The posix::basic_descriptor class template provides the ability to wrap a+ * POSIX descriptor.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename Executor = any_io_executor>+class basic_descriptor+ : public descriptor_base+{+public:+ /// The type of the executor associated with the object.+ typedef Executor executor_type;++ /// Rebinds the descriptor type to another executor.+ template <typename Executor1>+ struct rebind_executor+ {+ /// The descriptor type when rebound to the specified executor.+ typedef basic_descriptor<Executor1> other;+ };++ /// The native representation of a descriptor.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined native_handle_type;+#else+ typedef detail::reactive_descriptor_service::native_handle_type+ native_handle_type;+#endif++ /// A descriptor is always the lowest layer.+ typedef basic_descriptor lowest_layer_type;++ /// Construct a descriptor without opening it.+ /**+ * This constructor creates a descriptor without opening it.+ *+ * @param ex The I/O executor that the descriptor will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * descriptor.+ */+ explicit basic_descriptor(const executor_type& ex)+ : impl_(ex)+ {+ }++ /// Construct a descriptor without opening it.+ /**+ * This constructor creates a descriptor without opening it.+ *+ * @param context An execution context which provides the I/O executor that+ * the descriptor will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the descriptor.+ */+ template <typename ExecutionContext>+ explicit basic_descriptor(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ }++ /// Construct a descriptor on an existing native descriptor.+ /**+ * This constructor creates a descriptor object to hold an existing native+ * descriptor.+ *+ * @param ex The I/O executor that the descriptor will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * descriptor.+ *+ * @param native_descriptor A native descriptor.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_descriptor(const executor_type& ex,+ const native_handle_type& native_descriptor)+ : impl_(ex)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(),+ native_descriptor, ec);+ asio::detail::throw_error(ec, "assign");+ }++ /// Construct a descriptor on an existing native descriptor.+ /**+ * This constructor creates a descriptor object to hold an existing native+ * descriptor.+ *+ * @param context An execution context which provides the I/O executor that+ * the descriptor will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the descriptor.+ *+ * @param native_descriptor A native descriptor.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_descriptor(ExecutionContext& context,+ const native_handle_type& native_descriptor,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(),+ native_descriptor, ec);+ asio::detail::throw_error(ec, "assign");+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a descriptor from another.+ /**+ * This constructor moves a descriptor from one object to another.+ *+ * @param other The other descriptor 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_descriptor(const executor_type&)+ * constructor.+ */+ basic_descriptor(basic_descriptor&& other) ASIO_NOEXCEPT+ : impl_(std::move(other.impl_))+ {+ }++ /// Move-assign a descriptor from another.+ /**+ * This assignment operator moves a descriptor from one object to another.+ *+ * @param other The other descriptor 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_descriptor(const executor_type&)+ * constructor.+ */+ basic_descriptor& operator=(basic_descriptor&& other)+ {+ impl_ = std::move(other.impl_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_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 descriptor 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 descriptor 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 descriptor to the descriptor.+ /*+ * This function opens the descriptor to hold an existing native descriptor.+ *+ * @param native_descriptor A native descriptor.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void assign(const native_handle_type& native_descriptor)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(),+ native_descriptor, ec);+ asio::detail::throw_error(ec, "assign");+ }++ /// Assign an existing native descriptor to the descriptor.+ /*+ * This function opens the descriptor to hold an existing native descriptor.+ *+ * @param native_descriptor A native descriptor.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor,+ asio::error_code& ec)+ {+ impl_.get_service().assign(+ impl_.get_implementation(), native_descriptor, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Determine whether the descriptor is open.+ bool is_open() const+ {+ return impl_.get_service().is_open(impl_.get_implementation());+ }++ /// Close the descriptor.+ /**+ * This function is used to close the descriptor. 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 descriptor.+ /**+ * This function is used to close the descriptor. 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.+ */+ ASIO_SYNC_OP_VOID close(asio::error_code& ec)+ {+ impl_.get_service().close(impl_.get_implementation(), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Get the native descriptor representation.+ /**+ * This function may be used to obtain the underlying representation of the+ * descriptor. This is intended to allow access to native descriptor+ * functionality that is not otherwise provided.+ */+ native_handle_type native_handle()+ {+ return impl_.get_service().native_handle(impl_.get_implementation());+ }++ /// Release ownership of the native descriptor implementation.+ /**+ * This function may be used to obtain the underlying representation of the+ * descriptor. After calling this function, @c is_open() returns false. The+ * caller is responsible for closing the descriptor.+ *+ * All outstanding asynchronous read or write operations will finish+ * immediately, and the handlers for cancelled operations will be passed the+ * asio::error::operation_aborted error.+ */+ native_handle_type release()+ {+ return impl_.get_service().release(impl_.get_implementation());+ }++ /// Cancel all asynchronous operations associated with the descriptor.+ /**+ * This function causes all outstanding asynchronous read or 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 descriptor.+ /**+ * This function causes all outstanding asynchronous read or 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);+ }++ /// Perform an IO control command on the descriptor.+ /**+ * This function is used to execute an IO control command on the descriptor.+ *+ * @param command The IO control command to be performed on the descriptor.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @sa IoControlCommand @n+ * asio::posix::descriptor_base::bytes_readable @n+ * asio::posix::descriptor_base::non_blocking_io+ *+ * @par Example+ * Getting the number of bytes ready to read:+ * @code+ * asio::posix::stream_descriptor descriptor(my_context);+ * ...+ * asio::posix::stream_descriptor::bytes_readable command;+ * descriptor.io_control(command);+ * std::size_t bytes_readable = command.get();+ * @endcode+ */+ template <typename IoControlCommand>+ void io_control(IoControlCommand& command)+ {+ asio::error_code ec;+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);+ asio::detail::throw_error(ec, "io_control");+ }++ /// Perform an IO control command on the descriptor.+ /**+ * This function is used to execute an IO control command on the descriptor.+ *+ * @param command The IO control command to be performed on the descriptor.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @sa IoControlCommand @n+ * asio::posix::descriptor_base::bytes_readable @n+ * asio::posix::descriptor_base::non_blocking_io+ *+ * @par Example+ * Getting the number of bytes ready to read:+ * @code+ * asio::posix::stream_descriptor descriptor(my_context);+ * ...+ * asio::posix::stream_descriptor::bytes_readable command;+ * asio::error_code ec;+ * descriptor.io_control(command, ec);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * std::size_t bytes_readable = command.get();+ * @endcode+ */+ template <typename IoControlCommand>+ ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,+ asio::error_code& ec)+ {+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Gets the non-blocking mode of the descriptor.+ /**+ * @returns @c true if the descriptor's synchronous operations will fail with+ * asio::error::would_block if they are unable to perform the requested+ * operation immediately. If @c false, synchronous operations will block+ * until complete.+ *+ * @note The non-blocking mode has no effect on the behaviour of asynchronous+ * operations. Asynchronous operations will never fail with the error+ * asio::error::would_block.+ */+ bool non_blocking() const+ {+ return impl_.get_service().non_blocking(impl_.get_implementation());+ }++ /// Sets the non-blocking mode of the descriptor.+ /**+ * @param mode If @c true, the descriptor's synchronous operations will fail+ * with asio::error::would_block if they are unable to perform the+ * requested operation immediately. If @c false, synchronous operations will+ * block until complete.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note The non-blocking mode has no effect on the behaviour of asynchronous+ * operations. Asynchronous operations will never fail with the error+ * asio::error::would_block.+ */+ void non_blocking(bool mode)+ {+ asio::error_code ec;+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);+ asio::detail::throw_error(ec, "non_blocking");+ }++ /// Sets the non-blocking mode of the descriptor.+ /**+ * @param mode If @c true, the descriptor's synchronous operations will fail+ * with asio::error::would_block if they are unable to perform the+ * requested operation immediately. If @c false, synchronous operations will+ * block until complete.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note The non-blocking mode has no effect on the behaviour of asynchronous+ * operations. Asynchronous operations will never fail with the error+ * asio::error::would_block.+ */+ ASIO_SYNC_OP_VOID non_blocking(+ bool mode, asio::error_code& ec)+ {+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Gets the non-blocking mode of the native descriptor implementation.+ /**+ * This function is used to retrieve the non-blocking mode of the underlying+ * native descriptor. This mode has no effect on the behaviour of the+ * descriptor object's synchronous operations.+ *+ * @returns @c true if the underlying descriptor is in non-blocking mode and+ * direct system calls may fail with asio::error::would_block (or the+ * equivalent system error).+ *+ * @note The current non-blocking mode is cached by the descriptor object.+ * Consequently, the return value may be incorrect if the non-blocking mode+ * was set directly on the native descriptor.+ */+ bool native_non_blocking() const+ {+ return impl_.get_service().native_non_blocking(+ impl_.get_implementation());+ }++ /// Sets the non-blocking mode of the native descriptor implementation.+ /**+ * This function is used to modify the non-blocking mode of the underlying+ * native descriptor. It has no effect on the behaviour of the descriptor+ * object's synchronous operations.+ *+ * @param mode If @c true, the underlying descriptor is put into non-blocking+ * mode and direct system calls may fail with asio::error::would_block+ * (or the equivalent system error).+ *+ * @throws asio::system_error Thrown on failure. If the @c mode is+ * @c false, but the current value of @c non_blocking() is @c true, this+ * function fails with asio::error::invalid_argument, as the+ * combination does not make sense.+ */+ void native_non_blocking(bool mode)+ {+ asio::error_code ec;+ impl_.get_service().native_non_blocking(+ impl_.get_implementation(), mode, ec);+ asio::detail::throw_error(ec, "native_non_blocking");+ }++ /// Sets the non-blocking mode of the native descriptor implementation.+ /**+ * This function is used to modify the non-blocking mode of the underlying+ * native descriptor. It has no effect on the behaviour of the descriptor+ * object's synchronous operations.+ *+ * @param mode If @c true, the underlying descriptor is put into non-blocking+ * mode and direct system calls may fail with asio::error::would_block+ * (or the equivalent system error).+ *+ * @param ec Set to indicate what error occurred, if any. If the @c mode is+ * @c false, but the current value of @c non_blocking() is @c true, this+ * function fails with asio::error::invalid_argument, as the+ * combination does not make sense.+ */+ ASIO_SYNC_OP_VOID native_non_blocking(+ bool mode, asio::error_code& ec)+ {+ impl_.get_service().native_non_blocking(+ impl_.get_implementation(), mode, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Wait for the descriptor to become ready to read, ready to write, or to+ /// have pending error conditions.+ /**+ * This function is used to perform a blocking wait for a descriptor to enter+ * a ready to read, write or error condition state.+ *+ * @param w Specifies the desired descriptor state.+ *+ * @par Example+ * Waiting for a descriptor to become readable.+ * @code+ * asio::posix::stream_descriptor descriptor(my_context);+ * ...+ * descriptor.wait(asio::posix::stream_descriptor::wait_read);+ * @endcode+ */+ void wait(wait_type w)+ {+ asio::error_code ec;+ impl_.get_service().wait(impl_.get_implementation(), w, ec);+ asio::detail::throw_error(ec, "wait");+ }++ /// Wait for the descriptor to become ready to read, ready to write, or to+ /// have pending error conditions.+ /**+ * This function is used to perform a blocking wait for a descriptor to enter+ * a ready to read, write or error condition state.+ *+ * @param w Specifies the desired descriptor state.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @par Example+ * Waiting for a descriptor to become readable.+ * @code+ * asio::posix::stream_descriptor descriptor(my_context);+ * ...+ * asio::error_code ec;+ * descriptor.wait(asio::posix::stream_descriptor::wait_read, ec);+ * @endcode+ */+ ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec)+ {+ impl_.get_service().wait(impl_.get_implementation(), w, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Asynchronously wait for the descriptor to become ready to read, ready to+ /// write, or to have pending error conditions.+ /**+ * This function is used to perform an asynchronous wait for a descriptor to+ * enter a ready to read, write or error condition state.+ *+ * @param w Specifies the desired descriptor state.+ *+ * @param handler The handler to be called when the wait operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error // Result of operation+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * @code+ * void wait_handler(const asio::error_code& error)+ * {+ * if (!error)+ * {+ * // Wait succeeded.+ * }+ * }+ *+ * ...+ *+ * asio::posix::stream_descriptor descriptor(my_context);+ * ...+ * descriptor.async_wait(+ * asio::posix::stream_descriptor::wait_read,+ * wait_handler);+ * @endcode+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))+ WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,+ void (asio::error_code))+ async_wait(wait_type w,+ ASIO_MOVE_ARG(WaitHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WaitHandler, void (asio::error_code)>(+ initiate_async_wait(this), handler, w);+ }++protected:+ /// Protected destructor to prevent deletion through this type.+ /**+ * This function destroys the descriptor, cancelling any outstanding+ * asynchronous wait operations associated with the descriptor as if by+ * calling @c cancel.+ */+ ~basic_descriptor()+ {+ }++ detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;++private:+ // Disallow copying and assignment.+ basic_descriptor(const basic_descriptor&) ASIO_DELETED;+ basic_descriptor& operator=(const basic_descriptor&) ASIO_DELETED;++ class initiate_async_wait+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_wait(basic_descriptor* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WaitHandler>+ void operator()(ASIO_MOVE_ARG(WaitHandler) handler, wait_type w) 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(), w,+ handler2.value, self_->impl_.get_executor());+ }++ private:+ basic_descriptor* self_;+ };+};++} // namespace posix+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/posix/basic_stream_descriptor.hpp view
@@ -0,0 +1,470 @@+//+// posix/basic_stream_descriptor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_BASIC_STREAM_DESCRIPTOR_HPP+#define ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/posix/descriptor.hpp"++#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \+ || defined(GENERATING_DOCUMENTATION)++namespace asio {+namespace posix {++/// Provides stream-oriented descriptor functionality.+/**+ * The posix::basic_stream_descriptor class template provides asynchronous and+ * blocking stream-oriented descriptor 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 = any_io_executor>+class basic_stream_descriptor+ : public basic_descriptor<Executor>+{+public:+ /// The type of the executor associated with the object.+ typedef Executor executor_type;++ /// Rebinds the descriptor type to another executor.+ template <typename Executor1>+ struct rebind_executor+ {+ /// The descriptor type when rebound to the specified executor.+ typedef basic_stream_descriptor<Executor1> other;+ };++ /// The native representation of a descriptor.+ typedef typename basic_descriptor<Executor>::native_handle_type+ native_handle_type;++ /// Construct a stream descriptor without opening it.+ /**+ * This constructor creates a stream descriptor without opening it. The+ * descriptor needs to be opened and then connected or accepted before data+ * can be sent or received on it.+ *+ * @param ex The I/O executor that the descriptor will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * descriptor.+ */+ explicit basic_stream_descriptor(const executor_type& ex)+ : basic_descriptor<Executor>(ex)+ {+ }++ /// Construct a stream descriptor without opening it.+ /**+ * This constructor creates a stream descriptor without opening it. The+ * descriptor 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 descriptor will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the descriptor.+ */+ template <typename ExecutionContext>+ explicit basic_stream_descriptor(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_descriptor<Executor>(context)+ {+ }++ /// Construct a stream descriptor on an existing native descriptor.+ /**+ * This constructor creates a stream descriptor object to hold an existing+ * native descriptor.+ *+ * @param ex The I/O executor that the descriptor will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * descriptor.+ *+ * @param native_descriptor The new underlying descriptor implementation.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_stream_descriptor(const executor_type& ex,+ const native_handle_type& native_descriptor)+ : basic_descriptor<Executor>(ex, native_descriptor)+ {+ }++ /// Construct a stream descriptor on an existing native descriptor.+ /**+ * This constructor creates a stream descriptor object to hold an existing+ * native descriptor.+ *+ * @param context An execution context which provides the I/O executor that+ * the descriptor will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the descriptor.+ *+ * @param native_descriptor The new underlying descriptor implementation.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_stream_descriptor(ExecutionContext& context,+ const native_handle_type& native_descriptor,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_descriptor<Executor>(context, native_descriptor)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a stream descriptor from another.+ /**+ * This constructor moves a stream descriptor from one object to another.+ *+ * @param other The other stream descriptor 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_descriptor(const executor_type&)+ * constructor.+ */+ basic_stream_descriptor(basic_stream_descriptor&& other) ASIO_NOEXCEPT+ : descriptor(std::move(other))+ {+ }++ /// Move-assign a stream descriptor from another.+ /**+ * This assignment operator moves a stream descriptor from one object to+ * another.+ *+ * @param other The other stream descriptor 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_descriptor(const executor_type&)+ * constructor.+ */+ basic_stream_descriptor& operator=(basic_stream_descriptor&& other)+ {+ descriptor::operator=(std::move(other));+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Write some data to the descriptor.+ /**+ * This function is used to write data to the stream descriptor. 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 descriptor.+ *+ * @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+ * descriptor.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 descriptor.+ /**+ * This function is used to write data to the stream descriptor. 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 descriptor.+ *+ * @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+ * descriptor. The function call always returns immediately.+ *+ * @param buffers One or more data buffers to be written to the descriptor.+ * 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 handler is called.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the 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 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().+ *+ * @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+ * descriptor.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)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_write_some(const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_write_some(this), handler, buffers);+ }++ /// Read some data from the descriptor.+ /**+ * This function is used to read data from the stream descriptor. 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+ * descriptor.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 descriptor.+ /**+ * This function is used to read data from the stream descriptor. 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+ * descriptor. The function call 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 handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the 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 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().+ *+ * @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+ * descriptor.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)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_read_some(const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_read_some(this), handler, buffers);+ }++private:+ class initiate_async_write_some+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_write_some(basic_stream_descriptor* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(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_descriptor* self_;+ };++ class initiate_async_read_some+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_read_some(basic_stream_descriptor* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(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_descriptor* self_;+ };+};++} // namespace posix+} // namespace asio++#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/posix/descriptor.hpp view
@@ -0,0 +1,37 @@+//+// posix/descriptor.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_DESCRIPTOR_HPP+#define ASIO_POSIX_DESCRIPTOR_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_POSIX_STREAM_DESCRIPTOR) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/posix/basic_descriptor.hpp"++namespace asio {+namespace posix {++/// Typedef for the typical usage of basic_descriptor.+typedef basic_descriptor<> descriptor;++} // namespace posix+} // namespace asio++#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_POSIX_DESCRIPTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/posix/descriptor_base.hpp view
@@ -0,0 +1,90 @@+//+// posix/descriptor_base.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_DESCRIPTOR_BASE_HPP+#define ASIO_POSIX_DESCRIPTOR_BASE_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_POSIX_STREAM_DESCRIPTOR) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/detail/io_control.hpp"+#include "asio/detail/socket_option.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace posix {++/// The descriptor_base class is used as a base for the descriptor class as a+/// place to define the associated IO control commands.+class descriptor_base+{+public:+ /// Wait types.+ /**+ * For use with descriptor::wait() and descriptor::async_wait().+ */+ enum wait_type+ {+ /// Wait for a descriptor to become ready to read.+ wait_read,++ /// Wait for a descriptor to become ready to write.+ wait_write,++ /// Wait for a descriptor to have error conditions pending.+ wait_error+ };++ /// IO control command to get the amount of data that can be read without+ /// blocking.+ /**+ * Implements the FIONREAD IO control command.+ *+ * @par Example+ * @code+ * asio::posix::stream_descriptor descriptor(my_context);+ * ...+ * asio::descriptor_base::bytes_readable command(true);+ * descriptor.io_control(command);+ * std::size_t bytes_readable = command.get();+ * @endcode+ *+ * @par Concepts:+ * IoControlCommand.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined bytes_readable;+#else+ typedef asio::detail::io_control::bytes_readable bytes_readable;+#endif++protected:+ /// Protected destructor to prevent deletion through this type.+ ~descriptor_base()+ {+ }+};++} // namespace posix+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_POSIX_DESCRIPTOR_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/posix/stream_descriptor.hpp view
@@ -0,0 +1,37 @@+//+// posix/stream_descriptor.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_POSIX_STREAM_DESCRIPTOR_HPP+#define ASIO_POSIX_STREAM_DESCRIPTOR_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_POSIX_STREAM_DESCRIPTOR) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/posix/basic_stream_descriptor.hpp"++namespace asio {+namespace posix {++/// Typedef for the typical usage of a stream-oriented descriptor.+typedef basic_stream_descriptor<> stream_descriptor;++} // namespace posix+} // namespace asio++#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_POSIX_STREAM_DESCRIPTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/post.hpp view
@@ -0,0 +1,126 @@+//+// post.hpp+// ~~~~~~~~+//+// Copyright (c) 2003-2020 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_POST_HPP+#define ASIO_POST_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/async_result.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution_context.hpp"+#include "asio/execution/executor.hpp"+#include "asio/is_executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Submits a completion token or function object for execution.+/**+ * This function submits an object for execution using the object's associated+ * executor. The function object is queued for execution, and is never called+ * from the current thread prior to returning from <tt>post()</tt>.+ *+ * The use of @c post(), rather than @ref defer(), indicates the caller's+ * preference that the function object be eagerly queued for execution.+ *+ * This function has the following effects:+ *+ * @li Constructs a function object handler of type @c Handler, initialized+ * with <tt>handler(forward<CompletionToken>(token))</tt>.+ *+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,+ * initializing the object as <tt>result(handler)</tt>.+ *+ * @li Obtains the handler's associated executor object @c ex by performing+ * <tt>get_associated_executor(handler)</tt>.+ *+ * @li Obtains the handler's associated allocator object @c alloc by performing+ * <tt>get_associated_allocator(handler)</tt>.+ *+ * @li Performs <tt>ex.post(std::move(handler), alloc)</tt>.+ *+ * @li Returns <tt>result.get()</tt>.+ */+template <ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(+ ASIO_MOVE_ARG(CompletionToken) token);++/// Submits a completion token or function object for execution.+/**+ * This function submits an object for execution using the specified executor.+ * The function object is queued for execution, and is never called from the+ * current thread prior to returning from <tt>post()</tt>.+ *+ * The use of @c post(), rather than @ref defer(), indicates the caller's+ * preference that the function object be eagerly queued for execution.+ *+ * This function has the following effects:+ *+ * @li Constructs a function object handler of type @c Handler, initialized+ * with <tt>handler(forward<CompletionToken>(token))</tt>.+ *+ * @li Constructs an object @c result of type <tt>async_result<Handler></tt>,+ * initializing the object as <tt>result(handler)</tt>.+ *+ * @li Obtains the handler's associated executor object @c ex1 by performing+ * <tt>get_associated_executor(handler)</tt>.+ *+ * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>.+ *+ * @li Obtains the handler's associated allocator object @c alloc by performing+ * <tt>get_associated_allocator(handler)</tt>.+ *+ * @li Constructs a function object @c f with a function call operator that+ * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by+ * <tt>w.reset()</tt>.+ *+ * @li Performs <tt>Executor(ex).post(std::move(f), alloc)</tt>.+ *+ * @li Returns <tt>result.get()</tt>.+ */+template <typename Executor,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(+ const Executor& ex,+ ASIO_MOVE_ARG(CompletionToken) token+ ASIO_DEFAULT_COMPLETION_TOKEN(Executor),+ typename enable_if<+ execution::is_executor<Executor>::value || is_executor<Executor>::value+ >::type* = 0);++/// Submits a completion token or function object for execution.+/**+ * @returns <tt>post(ctx.get_executor(), forward<CompletionToken>(token))</tt>.+ */+template <typename ExecutionContext,+ ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename ExecutionContext::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post(+ ExecutionContext& ctx,+ ASIO_MOVE_ARG(CompletionToken) token+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename ExecutionContext::executor_type),+ typename enable_if<is_convertible<+ ExecutionContext&, execution_context&>::value>::type* = 0);++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/post.hpp"++#endif // ASIO_POST_HPP
+ link/modules/asio-standalone/asio/include/asio/prefer.hpp view
@@ -0,0 +1,656 @@+//+// prefer.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_PREFER_HPP+#define ASIO_PREFER_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/is_applicable_property.hpp"+#include "asio/traits/prefer_free.hpp"+#include "asio/traits/prefer_member.hpp"+#include "asio/traits/require_free.hpp"+#include "asio/traits/require_member.hpp"+#include "asio/traits/static_require.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {++/// A customisation point that attempts to apply a property to an object.+/**+ * The name <tt>prefer</tt> denotes a customisation point object. The+ * expression <tt>asio::prefer(E, P0, Pn...)</tt> for some subexpressions+ * <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt> represents <tt>N</tt>+ * subexpressions (where <tt>N</tt> is 0 or more, and with types <tt>T =+ * decay_t<decltype(E)></tt> and <tt>Prop0 = decay_t<decltype(P0)></tt>) is+ * expression-equivalent to:+ *+ * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_preferable</tt> is+ * not a well-formed constant expression with value <tt>true</tt>,+ * <tt>asio::prefer(E, P0, Pn...)</tt> is ill-formed.+ *+ * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression+ * <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a+ * well-formed constant expression with value <tt>true</tt>.+ *+ * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression+ * <tt>(E).require(P0)</tt> is a valid expression.+ *+ * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression+ * <tt>require(E, P0)</tt> is a valid expression with overload resolution+ * performed in a context that does not include the declaration of the+ * <tt>require</tt> customization point object.+ *+ * @li Otherwise, <tt>(E).prefer(P0)</tt> if <tt>N == 0</tt> and the expression+ * <tt>(E).prefer(P0)</tt> is a valid expression.+ *+ * @li Otherwise, <tt>prefer(E, P0)</tt> if <tt>N == 0</tt> and the expression+ * <tt>prefer(E, P0)</tt> is a valid expression with overload resolution+ * performed in a context that does not include the declaration of the+ * <tt>prefer</tt> customization point object.+ *+ * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt>.+ *+ * @li Otherwise,+ * <tt>asio::prefer(asio::prefer(E, P0), Pn...)</tt>+ * if <tt>N > 0</tt> and the expression+ * <tt>asio::prefer(asio::prefer(E, P0), Pn...)</tt>+ * is a valid expression.+ *+ * @li Otherwise, <tt>asio::prefer(E, P0, Pn...)</tt> is ill-formed.+ */+inline constexpr unspecified prefer = unspecified;++/// A type trait that determines whether a @c prefer expression is well-formed.+/**+ * Class template @c can_prefer is a trait that is derived from+ * @c true_type if the expression <tt>asio::prefer(std::declval<T>(),+ * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type.+ */+template <typename T, typename... Properties>+struct can_prefer :+ integral_constant<bool, automatically_determined>+{+};++/// A type trait that determines whether a @c prefer expression will not throw.+/**+ * Class template @c is_nothrow_prefer is a trait that is derived from+ * @c true_type if the expression <tt>asio::prefer(std::declval<T>(),+ * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type.+ */+template <typename T, typename... Properties>+struct is_nothrow_prefer :+ integral_constant<bool, automatically_determined>+{+};++/// A type trait that determines the result type of a @c prefer expression.+/**+ * Class template @c prefer_result is a trait that determines the result+ * type of the expression <tt>asio::prefer(std::declval<T>(),+ * std::declval<Properties>()...)</tt>.+ */+template <typename T, typename... Properties>+struct prefer_result+{+ /// The result of the @c prefer expression.+ typedef automatically_determined type;+};++} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_prefer_fn {++using asio::decay;+using asio::declval;+using asio::enable_if;+using asio::is_applicable_property;+using asio::traits::prefer_free;+using asio::traits::prefer_member;+using asio::traits::require_free;+using asio::traits::require_member;+using asio::traits::static_require;++void prefer();+void require();++enum overload_type+{+ identity,+ call_require_member,+ call_require_free,+ call_prefer_member,+ call_prefer_free,+ two_props,+ n_props,+ ill_formed+};++template <typename T, typename Properties, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_preferable+ &&+ static_require<T, Property>::is_valid+ )+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++#if defined(ASIO_HAS_MOVE)+ typedef ASIO_MOVE_ARG(T) result_type;+#else // defined(ASIO_HAS_MOVE)+ typedef ASIO_MOVE_ARG(typename decay<T>::type) result_type;+#endif // defined(ASIO_HAS_MOVE)+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_preferable+ &&+ !static_require<T, Property>::is_valid+ &&+ require_member<T, Property>::is_valid+ )+ >::type> :+ require_member<T, Property>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_member);+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_preferable+ &&+ !static_require<T, Property>::is_valid+ &&+ !require_member<T, Property>::is_valid+ &&+ require_free<T, Property>::is_valid+ )+ >::type> :+ require_free<T, Property>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_free);+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_preferable+ &&+ !static_require<T, Property>::is_valid+ &&+ !require_member<T, Property>::is_valid+ &&+ !require_free<T, Property>::is_valid+ &&+ prefer_member<T, Property>::is_valid+ )+ >::type> :+ prefer_member<T, Property>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_member);+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_preferable+ &&+ !static_require<T, Property>::is_valid+ &&+ !require_member<T, Property>::is_valid+ &&+ !require_free<T, Property>::is_valid+ &&+ !prefer_member<T, Property>::is_valid+ &&+ prefer_free<T, Property>::is_valid+ )+ >::type> :+ prefer_free<T, Property>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_free);+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_preferable+ &&+ !static_require<T, Property>::is_valid+ &&+ !require_member<T, Property>::is_valid+ &&+ !require_free<T, Property>::is_valid+ &&+ !prefer_member<T, Property>::is_valid+ &&+ !prefer_free<T, Property>::is_valid+ )+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++#if defined(ASIO_HAS_MOVE)+ typedef ASIO_MOVE_ARG(T) result_type;+#else // defined(ASIO_HAS_MOVE)+ typedef ASIO_MOVE_ARG(typename decay<T>::type) result_type;+#endif // defined(ASIO_HAS_MOVE)+};++template <typename T, typename P0, typename P1>+struct call_traits<T, void(P0, P1),+ typename enable_if<+ call_traits<T, void(P0)>::overload != ill_formed+ &&+ call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1)+ >::overload != ill_formed+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = two_props);++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (+ call_traits<T, void(P0)>::is_noexcept+ &&+ call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1)+ >::is_noexcept+ ));++ typedef typename decay<+ typename call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1)+ >::result_type+ >::type result_type;+};++template <typename T, typename P0, typename P1, typename ASIO_ELLIPSIS PN>+struct call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS),+ typename enable_if<+ call_traits<T, void(P0)>::overload != ill_formed+ &&+ call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1, PN ASIO_ELLIPSIS)+ >::overload != ill_formed+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = n_props);++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (+ call_traits<T, void(P0)>::is_noexcept+ &&+ call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1, PN ASIO_ELLIPSIS)+ >::is_noexcept+ ));++ typedef typename decay<+ typename call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1, PN ASIO_ELLIPSIS)+ >::result_type+ >::type result_type;+};++struct impl+{+ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == identity,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property)) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(T)(t);+ }++ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == call_require_member,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property) p) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(T)(t).require(+ ASIO_MOVE_CAST(Property)(p));+ }++ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == call_require_free,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property) p) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return require(+ ASIO_MOVE_CAST(T)(t),+ ASIO_MOVE_CAST(Property)(p));+ }++ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == call_prefer_member,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property) p) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(T)(t).prefer(+ ASIO_MOVE_CAST(Property)(p));+ }++ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == call_prefer_free,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property) p) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return prefer(+ ASIO_MOVE_CAST(T)(t),+ ASIO_MOVE_CAST(Property)(p));+ }++ template <typename T, typename P0, typename P1>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(P0, P1)>::overload == two_props,+ typename call_traits<T, void(P0, P1)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(P0) p0,+ ASIO_MOVE_ARG(P1) p1) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(P0, P1)>::is_noexcept))+ {+ return (*this)(+ (*this)(+ ASIO_MOVE_CAST(T)(t),+ ASIO_MOVE_CAST(P0)(p0)),+ ASIO_MOVE_CAST(P1)(p1));+ }++ template <typename T, typename P0, typename P1,+ typename ASIO_ELLIPSIS PN>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::overload == n_props,+ typename call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(P0) p0,+ ASIO_MOVE_ARG(P1) p1,+ ASIO_MOVE_ARG(PN) ASIO_ELLIPSIS pn) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::is_noexcept))+ {+ return (*this)(+ (*this)(+ ASIO_MOVE_CAST(T)(t),+ ASIO_MOVE_CAST(P0)(p0)),+ ASIO_MOVE_CAST(P1)(p1),+ ASIO_MOVE_CAST(PN)(pn) ASIO_ELLIPSIS);+ }+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_prefer_fn+namespace asio {+namespace {++static ASIO_CONSTEXPR const asio_prefer_fn::impl&+ prefer = asio_prefer_fn::static_instance<>::instance;++} // namespace++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename... Properties>+struct can_prefer :+ integral_constant<bool,+ asio_prefer_fn::call_traits<T, void(Properties...)>::overload+ != asio_prefer_fn::ill_formed>+{+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename P0 = void,+ typename P1 = void, typename P2 = void>+struct can_prefer :+ integral_constant<bool,+ asio_prefer_fn::call_traits<T, void(P0, P1, P2)>::overload+ != asio_prefer_fn::ill_formed>+{+};++template <typename T, typename P0, typename P1>+struct can_prefer<T, P0, P1> :+ integral_constant<bool,+ asio_prefer_fn::call_traits<T, void(P0, P1)>::overload+ != asio_prefer_fn::ill_formed>+{+};++template <typename T, typename P0>+struct can_prefer<T, P0> :+ integral_constant<bool,+ asio_prefer_fn::call_traits<T, void(P0)>::overload+ != asio_prefer_fn::ill_formed>+{+};++template <typename T>+struct can_prefer<T> :+ false_type+{+};++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename ASIO_ELLIPSIS Properties>+constexpr bool can_prefer_v+ = can_prefer<T, Properties ASIO_ELLIPSIS>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename... Properties>+struct is_nothrow_prefer :+ integral_constant<bool,+ asio_prefer_fn::call_traits<T, void(Properties...)>::is_noexcept>+{+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename P0 = void,+ typename P1 = void, typename P2 = void>+struct is_nothrow_prefer :+ integral_constant<bool,+ asio_prefer_fn::call_traits<T, void(P0, P1, P2)>::is_noexcept>+{+};++template <typename T, typename P0, typename P1>+struct is_nothrow_prefer<T, P0, P1> :+ integral_constant<bool,+ asio_prefer_fn::call_traits<T, void(P0, P1)>::is_noexcept>+{+};++template <typename T, typename P0>+struct is_nothrow_prefer<T, P0> :+ integral_constant<bool,+ asio_prefer_fn::call_traits<T, void(P0)>::is_noexcept>+{+};++template <typename T>+struct is_nothrow_prefer<T> :+ false_type+{+};++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename ASIO_ELLIPSIS Properties>+constexpr bool is_nothrow_prefer_v+ = is_nothrow_prefer<T, Properties ASIO_ELLIPSIS>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename... Properties>+struct prefer_result+{+ typedef typename asio_prefer_fn::call_traits<+ T, void(Properties...)>::result_type type;+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename P0 = void,+ typename P1 = void, typename P2 = void>+struct prefer_result+{+ typedef typename asio_prefer_fn::call_traits<+ T, void(P0, P1, P2)>::result_type type;+};++template <typename T, typename P0, typename P1>+struct prefer_result<T, P0, P1>+{+ typedef typename asio_prefer_fn::call_traits<+ T, void(P0, P1)>::result_type type;+};++template <typename T, typename P0>+struct prefer_result<T, P0>+{+ typedef typename asio_prefer_fn::call_traits<+ T, void(P0)>::result_type type;+};++template <typename T>+struct prefer_result<T>+{+};++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_PREFER_HPP
+ link/modules/asio-standalone/asio/include/asio/query.hpp view
@@ -0,0 +1,296 @@+//+// query.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 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_QUERY_HPP+#define ASIO_QUERY_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/is_applicable_property.hpp"+#include "asio/traits/query_member.hpp"+#include "asio/traits/query_free.hpp"+#include "asio/traits/static_query.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {++/// A customisation point that queries the value of a property.+/**+ * The name <tt>query</tt> denotes a customization point object. The+ * expression <tt>asio::query(E, P)</tt> for some+ * subexpressions <tt>E</tt> and <tt>P</tt> (with types <tt>T =+ * decay_t<decltype(E)></tt> and <tt>Prop = decay_t<decltype(P)></tt>) is+ * expression-equivalent to:+ *+ * @li If <tt>is_applicable_property_v<T, Prop></tt> is not a well-formed+ * constant expression with value <tt>true</tt>, <tt>asio::query(E,+ * P)</tt> is ill-formed.+ *+ * @li Otherwise, <tt>Prop::template static_query_v<T></tt> if the expression+ * <tt>Prop::template static_query_v<T></tt> is a well-formed constant+ * expression.+ *+ * @li Otherwise, <tt>(E).query(P)</tt> if the expression+ * <tt>(E).query(P)</tt> is well-formed.+ *+ * @li Otherwise, <tt>query(E, P)</tt> if the expression+ * <tt>query(E, P)</tt> is a valid expression with overload+ * resolution performed in a context that does not include the declaration+ * of the <tt>query</tt> customization point object.+ *+ * @li Otherwise, <tt>asio::query(E, P)</tt> is ill-formed.+ */+inline constexpr unspecified query = unspecified;++/// A type trait that determines whether a @c query expression is well-formed.+/**+ * Class template @c can_query is a trait that is derived from+ * @c true_type if the expression <tt>asio::query(std::declval<T>(),+ * std::declval<Property>())</tt> is well formed; otherwise @c false_type.+ */+template <typename T, typename Property>+struct can_query :+ integral_constant<bool, automatically_determined>+{+};++/// A type trait that determines whether a @c query expression will+/// not throw.+/**+ * Class template @c is_nothrow_query is a trait that is derived from+ * @c true_type if the expression <tt>asio::query(std::declval<T>(),+ * std::declval<Property>())</tt> is @c noexcept; otherwise @c false_type.+ */+template <typename T, typename Property>+struct is_nothrow_query :+ integral_constant<bool, automatically_determined>+{+};++/// A type trait that determines the result type of a @c query expression.+/**+ * Class template @c query_result is a trait that determines the result+ * type of the expression <tt>asio::query(std::declval<T>(),+ * std::declval<Property>())</tt>.+ */+template <typename T, typename Property>+struct query_result+{+ /// The result of the @c query expression.+ typedef automatically_determined type;+};++} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_query_fn {++using asio::decay;+using asio::declval;+using asio::enable_if;+using asio::is_applicable_property;+using asio::traits::query_free;+using asio::traits::query_member;+using asio::traits::static_query;++void query();++enum overload_type+{+ static_value,+ call_member,+ call_free,+ ill_formed+};++template <typename T, typename Properties, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ static_query<T, Property>::is_valid+ )+ >::type> :+ static_query<T, Property>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = static_value);+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ !static_query<T, Property>::is_valid+ &&+ query_member<T, Property>::is_valid+ )+ >::type> :+ query_member<T, Property>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ !static_query<T, Property>::is_valid+ &&+ !query_member<T, Property>::is_valid+ &&+ query_free<T, Property>::is_valid+ )+ >::type> :+ query_free<T, Property>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++struct impl+{+ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == static_value,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T),+ ASIO_MOVE_ARG(Property)) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return static_query<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value();+ }++ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == call_member,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property) p) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(T)(t).query(ASIO_MOVE_CAST(Property)(p));+ }++ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == call_free,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property) p) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return query(ASIO_MOVE_CAST(T)(t), ASIO_MOVE_CAST(Property)(p));+ }+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_query_fn+namespace asio {+namespace {++static ASIO_CONSTEXPR const asio_query_fn::impl&+ query = asio_query_fn::static_instance<>::instance;++} // namespace++template <typename T, typename Property>+struct can_query :+ integral_constant<bool,+ asio_query_fn::call_traits<T, void(Property)>::overload !=+ asio_query_fn::ill_formed>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename Property>+constexpr bool can_query_v+ = can_query<T, Property>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename Property>+struct is_nothrow_query :+ integral_constant<bool,+ asio_query_fn::call_traits<T, void(Property)>::is_noexcept>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename Property>+constexpr bool is_nothrow_query_v+ = is_nothrow_query<T, Property>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename Property>+struct query_result+{+ typedef typename asio_query_fn::call_traits<+ T, void(Property)>::result_type type;+};++} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_QUERY_HPP
+ link/modules/asio-standalone/asio/include/asio/read.hpp view
@@ -0,0 +1,1288 @@+//+// read.hpp+// ~~~~~~~~+//+// Copyright (c) 2003-2020 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_READ_HPP+#define ASIO_READ_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/async_result.hpp"+#include "asio/buffer.hpp"+#include "asio/error.hpp"++#if !defined(ASIO_NO_EXTENSIONS)+# include "asio/basic_streambuf_fwd.hpp"+#endif // !defined(ASIO_NO_EXTENSIONS)++#include "asio/detail/push_options.hpp"++namespace asio {++/**+ * @defgroup read asio::read+ *+ * @brief The @c read function is a composed operation that reads a certain+ * amount of data from a stream before returning.+ */+/*@{*/++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * stream.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To read into a single data buffer use the @ref buffer function as follows:+ * @code asio::read(s, 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.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read(+ * s, buffers,+ * asio::transfer_all()); @endcode+ */+template <typename SyncReadStream, typename MutableBufferSequence>+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type* = 0);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * stream.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @par Example+ * To read into a single data buffer use the @ref buffer function as follows:+ * @code asio::read(s, asio::buffer(data, size), ec); @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.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read(+ * s, buffers,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncReadStream, typename MutableBufferSequence>+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,+ asio::error_code& ec,+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type* = 0);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * stream.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's read_some function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To read into a single data buffer use the @ref buffer function as follows:+ * @code asio::read(s, asio::buffer(data, size),+ * asio::transfer_at_least(32)); @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 SyncReadStream, typename MutableBufferSequence,+ typename CompletionCondition>+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type* = 0);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * stream.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's read_some function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes read. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncReadStream, typename MutableBufferSequence,+ typename CompletionCondition>+std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type* = 0);++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The specified dynamic buffer sequence is full (that is, it has reached+ * maximum size).+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read(+ * s, buffers,+ * asio::transfer_all()); @endcode+ */+template <typename SyncReadStream, typename DynamicBuffer_v1>+std::size_t read(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The supplied buffer is full (that is, it has reached maximum size).+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read(+ * s, buffers,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncReadStream, typename DynamicBuffer_v1>+std::size_t read(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The specified dynamic buffer sequence is full (that is, it has reached+ * maximum size).+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's read_some function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ */+template <typename SyncReadStream, typename DynamicBuffer_v1,+ typename CompletionCondition>+std::size_t read(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The specified dynamic buffer sequence is full (that is, it has reached+ * maximum size).+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's read_some function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes read. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncReadStream, typename DynamicBuffer_v1,+ typename CompletionCondition>+std::size_t read(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The supplied buffer is full (that is, it has reached maximum size).+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b The basic_streambuf object into which the data will be read.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read(+ * s, b,+ * asio::transfer_all()); @endcode+ */+template <typename SyncReadStream, typename Allocator>+std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The supplied buffer is full (that is, it has reached maximum size).+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b The basic_streambuf object into which the data will be read.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read(+ * s, b,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncReadStream, typename Allocator>+std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,+ asio::error_code& ec);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The supplied buffer is full (that is, it has reached maximum size).+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b The basic_streambuf object into which the data will be read.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's read_some function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ */+template <typename SyncReadStream, typename Allocator,+ typename CompletionCondition>+std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The supplied buffer is full (that is, it has reached maximum size).+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b The basic_streambuf object into which the data will be read.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's read_some function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes read. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncReadStream, typename Allocator,+ typename CompletionCondition>+std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition, asio::error_code& ec);++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The specified dynamic buffer sequence is full (that is, it has reached+ * maximum size).+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read(+ * s, buffers,+ * asio::transfer_all()); @endcode+ */+template <typename SyncReadStream, typename DynamicBuffer_v2>+std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The supplied buffer is full (that is, it has reached maximum size).+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read(+ * s, buffers,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncReadStream, typename DynamicBuffer_v2>+std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,+ asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The specified dynamic buffer sequence is full (that is, it has reached+ * maximum size).+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's read_some function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ */+template <typename SyncReadStream, typename DynamicBuffer_v2,+ typename CompletionCondition>+std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Attempt to read a certain amount of data from a stream before returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * stream. The call will block until one of the following conditions is true:+ *+ * @li The specified dynamic buffer sequence is full (that is, it has reached+ * maximum size).+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's read_some function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes read. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncReadStream, typename DynamicBuffer_v2,+ typename CompletionCondition>+std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/*@}*/+/**+ * @defgroup async_read asio::async_read+ *+ * @brief The @c async_read function is a composed asynchronous operation that+ * reads a certain amount of data from a stream before completion.+ */+/*@{*/++/// Start an asynchronous operation to read a certain amount of data from a+/// stream.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions is+ * true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other read operations (such+ * as async_read, the stream's async_read_some function, or any other composed+ * operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * stream. 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 handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes copied into the+ * // buffers. If an error occurred,+ * // this will be the number of+ * // bytes successfully transferred+ * // prior to the error.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To read into a single data buffer use the @ref buffer function as follows:+ * @code+ * asio::async_read(s, 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.+ *+ * @note This overload is equivalent to calling:+ * @code asio::async_read(+ * s, buffers,+ * asio::transfer_all(),+ * handler); @endcode+ */+template <typename AsyncReadStream, typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type* = 0);++/// Start an asynchronous operation to read a certain amount of data from a+/// stream.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions is+ * true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * stream. 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 handler is called.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's async_read_some function.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes copied into the+ * // buffers. If an error occurred,+ * // this will be the number of+ * // bytes successfully transferred+ * // prior to the error.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To read into a single data buffer use the @ref buffer function as follows:+ * @code asio::async_read(s,+ * asio::buffer(data, size),+ * asio::transfer_at_least(32),+ * 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 AsyncReadStream,+ typename MutableBufferSequence, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_mutable_buffer_sequence<MutableBufferSequence>::value+ >::type* = 0);++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Start an asynchronous operation to read a certain amount of data from a+/// stream.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions is+ * true:+ *+ * @li The specified dynamic buffer sequence is full (that is, it has reached+ * maximum size).+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other read operations (such+ * as async_read, the stream's async_read_some function, or any other composed+ * operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes copied into the+ * // buffers. If an error occurred,+ * // this will be the number of+ * // bytes successfully transferred+ * // prior to the error.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note This overload is equivalent to calling:+ * @code asio::async_read(+ * s, buffers,+ * asio::transfer_all(),+ * handler); @endcode+ */+template <typename AsyncReadStream, typename DynamicBuffer_v1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Start an asynchronous operation to read a certain amount of data from a+/// stream.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions is+ * true:+ *+ * @li The specified dynamic buffer sequence is full (that is, it has reached+ * maximum size).+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other read operations (such+ * as async_read, the stream's async_read_some function, or any other composed+ * operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's async_read_some function.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes copied into the+ * // buffers. If an error occurred,+ * // this will be the number of+ * // bytes successfully transferred+ * // prior to the error.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++/// Start an asynchronous operation to read a certain amount of data from a+/// stream.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions is+ * true:+ *+ * @li The supplied buffer is full (that is, it has reached maximum size).+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other read operations (such+ * as async_read, the stream's async_read_some function, or any other composed+ * operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param b A basic_streambuf object into which the data will be read. Ownership+ * of the streambuf is retained by the caller, which must guarantee that it+ * remains valid until the handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes copied into the+ * // buffers. If an error occurred,+ * // this will be the number of+ * // bytes successfully transferred+ * // prior to the error.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note This overload is equivalent to calling:+ * @code asio::async_read(+ * s, b,+ * asio::transfer_all(),+ * handler); @endcode+ */+template <typename AsyncReadStream, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type));++/// Start an asynchronous operation to read a certain amount of data from a+/// stream.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions is+ * true:+ *+ * @li The supplied buffer is full (that is, it has reached maximum size).+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other read operations (such+ * as async_read, the stream's async_read_some function, or any other composed+ * operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param b A basic_streambuf object into which the data will be read. Ownership+ * of the streambuf is retained by the caller, which must guarantee that it+ * remains valid until the handler is called.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's async_read_some function.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes copied into the+ * // buffers. If an error occurred,+ * // this will be the number of+ * // bytes successfully transferred+ * // prior to the error.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncReadStream,+ typename Allocator, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type));++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Start an asynchronous operation to read a certain amount of data from a+/// stream.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions is+ * true:+ *+ * @li The specified dynamic buffer sequence is full (that is, it has reached+ * maximum size).+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other read operations (such+ * as async_read, the stream's async_read_some function, or any other composed+ * operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes copied into the+ * // buffers. If an error occurred,+ * // this will be the number of+ * // bytes successfully transferred+ * // prior to the error.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note This overload is equivalent to calling:+ * @code asio::async_read(+ * s, buffers,+ * asio::transfer_all(),+ * handler); @endcode+ */+template <typename AsyncReadStream, typename DynamicBuffer_v2,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Start an asynchronous operation to read a certain amount of data from a+/// stream.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions is+ * true:+ *+ * @li The specified dynamic buffer sequence is full (that is, it has reached+ * maximum size).+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other read operations (such+ * as async_read, the stream's async_read_some function, or any other composed+ * operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_read_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the stream's async_read_some function.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes copied into the+ * // buffers. If an error occurred,+ * // this will be the number of+ * // bytes successfully transferred+ * // prior to the error.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/*@}*/++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/read.hpp"++#endif // ASIO_READ_HPP
+ link/modules/asio-standalone/asio/include/asio/read_at.hpp view
@@ -0,0 +1,694 @@+//+// read_at.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_READ_AT_HPP+#define ASIO_READ_AT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/async_result.hpp"+#include "asio/detail/cstdint.hpp"+#include "asio/error.hpp"++#if !defined(ASIO_NO_EXTENSIONS)+# include "asio/basic_streambuf_fwd.hpp"+#endif // !defined(ASIO_NO_EXTENSIONS)++#include "asio/detail/push_options.hpp"++namespace asio {++/**+ * @defgroup read_at asio::read_at+ *+ * @brief The @c read_at function is a composed operation that reads a certain+ * amount of data at the specified offset before returning.+ */+/*@{*/++/// Attempt to read a certain amount of data at the specified offset before+/// returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * random access device at the specified offset. The call will block until one+ * of the following conditions is true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * read_some_at function.+ *+ * @param d The device from which the data is to be read. The type must support+ * the SyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * device.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To read into a single data buffer use the @ref buffer function as follows:+ * @code asio::read_at(d, 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.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read_at(+ * d, 42, buffers,+ * asio::transfer_all()); @endcode+ */+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>+std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers);++/// Attempt to read a certain amount of data at the specified offset before+/// returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * random access device at the specified offset. The call will block until one+ * of the following conditions is true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * read_some_at function.+ *+ * @param d The device from which the data is to be read. The type must support+ * the SyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * device.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @par Example+ * To read into a single data buffer use the @ref buffer function as follows:+ * @code asio::read_at(d, 42,+ * asio::buffer(data, size), ec); @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.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read_at(+ * d, 42, buffers,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>+std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers,+ asio::error_code& ec);++/// Attempt to read a certain amount of data at the specified offset before+/// returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * random access device at the specified offset. The call will block until one+ * of the following conditions is true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * read_some_at function.+ *+ * @param d The device from which the data is to be read. The type must support+ * the SyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * device.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the device's read_some_at function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To read into a single data buffer use the @ref buffer function as follows:+ * @code asio::read_at(d, 42, asio::buffer(data, size),+ * asio::transfer_at_least(32)); @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 SyncRandomAccessReadDevice, typename MutableBufferSequence,+ typename CompletionCondition>+std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition);++/// Attempt to read a certain amount of data at the specified offset before+/// returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * random access device at the specified offset. The call will block until one+ * of the following conditions is true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * read_some_at function.+ *+ * @param d The device from which the data is to be read. The type must support+ * the SyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * device.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the device's read_some_at function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes read. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,+ typename CompletionCondition>+std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition, asio::error_code& ec);++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++/// Attempt to read a certain amount of data at the specified offset before+/// returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * random access device at the specified offset. The call will block until one+ * of the following conditions is true:+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * read_some_at function.+ *+ * @param d The device from which the data is to be read. The type must support+ * the SyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param b The basic_streambuf object into which the data will be read.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read_at(+ * d, 42, b,+ * asio::transfer_all()); @endcode+ */+template <typename SyncRandomAccessReadDevice, typename Allocator>+std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, basic_streambuf<Allocator>& b);++/// Attempt to read a certain amount of data at the specified offset before+/// returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * random access device at the specified offset. The call will block until one+ * of the following conditions is true:+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * read_some_at function.+ *+ * @param d The device from which the data is to be read. The type must support+ * the SyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param b The basic_streambuf object into which the data will be read.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @note This overload is equivalent to calling:+ * @code asio::read_at(+ * d, 42, b,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncRandomAccessReadDevice, typename Allocator>+std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, basic_streambuf<Allocator>& b,+ asio::error_code& ec);++/// Attempt to read a certain amount of data at the specified offset before+/// returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * random access device at the specified offset. The call will block until one+ * of the following conditions is true:+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * read_some_at function.+ *+ * @param d The device from which the data is to be read. The type must support+ * the SyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param b The basic_streambuf object into which the data will be read.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the device's read_some_at function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ */+template <typename SyncRandomAccessReadDevice, typename Allocator,+ typename CompletionCondition>+std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition);++/// Attempt to read a certain amount of data at the specified offset before+/// returning.+/**+ * This function is used to read a certain number of bytes of data from a+ * random access device at the specified offset. The call will block until one+ * of the following conditions is true:+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * read_some_at function.+ *+ * @param d The device from which the data is to be read. The type must support+ * the SyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param b The basic_streambuf object into which the data will be read.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest read_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the device's read_some_at function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes read. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncRandomAccessReadDevice, typename Allocator,+ typename CompletionCondition>+std::size_t read_at(SyncRandomAccessReadDevice& d,+ uint64_t offset, basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition, asio::error_code& ec);++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)++/*@}*/+/**+ * @defgroup async_read_at asio::async_read_at+ *+ * @brief The @c async_read_at function is a composed asynchronous operation+ * that reads a certain amount of data at the specified offset.+ */+/*@{*/++/// Start an asynchronous operation to read a certain amount of data at the+/// specified offset.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a random access device at the specified offset. The function call+ * always returns immediately. The asynchronous operation will continue until+ * one of the following conditions is true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * async_read_some_at function.+ *+ * @param d The device from which the data is to be read. The type must support+ * the AsyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * device. 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 handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // Number of bytes copied into the buffers. If an error+ * // occurred, this will be the number of bytes successfully+ * // transferred prior to the error.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To read into a single data buffer use the @ref buffer function as follows:+ * @code+ * asio::async_read_at(d, 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.+ *+ * @note This overload is equivalent to calling:+ * @code asio::async_read_at(+ * d, 42, buffers,+ * asio::transfer_all(),+ * handler); @endcode+ */+template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncRandomAccessReadDevice::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset,+ const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncRandomAccessReadDevice::executor_type));++/// Start an asynchronous operation to read a certain amount of data at the+/// specified offset.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a random access device at the specified offset. The function call+ * always returns immediately. The asynchronous operation will continue until+ * one of the following conditions is true:+ *+ * @li The supplied buffers are full. That is, the bytes transferred is equal to+ * the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * @param d The device from which the data is to be read. The type must support+ * the AsyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param buffers One or more buffers into which the data will be read. The sum+ * of the buffer sizes indicates the maximum number of bytes to read from the+ * device. 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 handler is called.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_read_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the device's async_read_some_at function.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // Number of bytes copied into the buffers. If an error+ * // occurred, this will be the number of bytes successfully+ * // transferred prior to the error.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To read into a single data buffer use the @ref buffer function as follows:+ * @code asio::async_read_at(d, 42,+ * asio::buffer(data, size),+ * asio::transfer_at_least(32),+ * 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 AsyncRandomAccessReadDevice,+ typename MutableBufferSequence, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncRandomAccessReadDevice::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_at(AsyncRandomAccessReadDevice& d,+ uint64_t offset, const MutableBufferSequence& buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncRandomAccessReadDevice::executor_type));++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++/// Start an asynchronous operation to read a certain amount of data at the+/// specified offset.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a random access device at the specified offset. The function call+ * always returns immediately. The asynchronous operation will continue until+ * one of the following conditions is true:+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * async_read_some_at function.+ *+ * @param d The device from which the data is to be read. The type must support+ * the AsyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param b A basic_streambuf object into which the data will be read. Ownership+ * of the streambuf is retained by the caller, which must guarantee that it+ * remains valid until the handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // Number of bytes copied into the buffers. If an error+ * // occurred, this will be the number of bytes successfully+ * // transferred prior to the error.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note This overload is equivalent to calling:+ * @code asio::async_read_at(+ * d, 42, b,+ * asio::transfer_all(),+ * handler); @endcode+ */+template <typename AsyncRandomAccessReadDevice, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncRandomAccessReadDevice::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_at(AsyncRandomAccessReadDevice& d,+ uint64_t offset, basic_streambuf<Allocator>& b,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncRandomAccessReadDevice::executor_type));++/// Start an asynchronous operation to read a certain amount of data at the+/// specified offset.+/**+ * This function is used to asynchronously read a certain number of bytes of+ * data from a random access device at the specified offset. The function call+ * always returns immediately. The asynchronous operation will continue until+ * one of the following conditions is true:+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * async_read_some_at function.+ *+ * @param d The device from which the data is to be read. The type must support+ * the AsyncRandomAccessReadDevice concept.+ *+ * @param offset The offset at which the data will be read.+ *+ * @param b A basic_streambuf object into which the data will be read. Ownership+ * of the streambuf is retained by the caller, which must guarantee that it+ * remains valid until the handler is called.+ *+ * @param completion_condition The function object to be called to determine+ * whether the read operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_read_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the read operation is complete. A non-zero+ * return value indicates the maximum number of bytes to be read on the next+ * call to the device's async_read_some_at function.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // Number of bytes copied into the buffers. If an error+ * // occurred, this will be the number of bytes successfully+ * // transferred prior to the error.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncRandomAccessReadDevice,+ typename Allocator, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncRandomAccessReadDevice::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_at(AsyncRandomAccessReadDevice& d,+ uint64_t offset, basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncRandomAccessReadDevice::executor_type));++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)++/*@}*/++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/read_at.hpp"++#endif // ASIO_READ_AT_HPP
+ link/modules/asio-standalone/asio/include/asio/read_until.hpp view
@@ -0,0 +1,2863 @@+//+// read_until.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_READ_UNTIL_HPP+#define ASIO_READ_UNTIL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include <string>+#include "asio/async_result.hpp"+#include "asio/buffer.hpp"+#include "asio/detail/regex_fwd.hpp"+#include "asio/detail/string_view.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/error.hpp"++#if !defined(ASIO_NO_EXTENSIONS)+# include "asio/basic_streambuf_fwd.hpp"+#endif // !defined(ASIO_NO_EXTENSIONS)++#include "asio/detail/push_options.hpp"++namespace asio {++namespace detail+{+ char (&has_result_type_helper(...))[2];++ template <typename T>+ char has_result_type_helper(T*, typename T::result_type* = 0);++ template <typename T>+ struct has_result_type+ {+ enum { value = (sizeof((has_result_type_helper)((T*)(0))) == 1) };+ };+} // namespace detail++/// Type trait used to determine whether a type can be used as a match condition+/// function with read_until and async_read_until.+template <typename T>+struct is_match_condition+{+#if defined(GENERATING_DOCUMENTATION)+ /// The value member is true if the type may be used as a match condition.+ static const bool value;+#else+ enum+ {+ value = asio::is_function<+ typename asio::remove_pointer<T>::type>::value+ || detail::has_result_type<T>::value+ };+#endif+};++/**+ * @defgroup read_until asio::read_until+ *+ * @brief The @c read_until function is a composed operation that reads data+ * into a dynamic buffer sequence, or into a streambuf, until it contains a+ * delimiter, matches a regular expression, or a function object indicates a+ * match.+ */+/*@{*/++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Read data into a dynamic buffer sequence until it contains a specified+/// delimiter.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains the specified+ * delimiter. The call will block until one of the following conditions is+ * true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains the delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param delim The delimiter character.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the delimiter.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond the delimiter. An application will+ * typically leave that data in the dynamic buffer sequence for a subsequent+ * read_until operation to examine.+ *+ * @par Example+ * To read data into a @c std::string until a newline is encountered:+ * @code std::string data;+ * std::size_t n = asio::read_until(s,+ * asio::dynamic_buffer(data), '\n');+ * std::string line = data.substr(0, n);+ * data.erase(0, n); @endcode+ * After the @c read_until operation completes successfully, the string @c data+ * contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the+ * delimiter, so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the buffer @c b as+ * follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c read_until operation.+ */+template <typename SyncReadStream, typename DynamicBuffer_v1>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Read data into a dynamic buffer sequence until it contains a specified+/// delimiter.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains the specified+ * delimiter. The call will block until one of the following conditions is+ * true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains the delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param delim The delimiter character.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the delimiter. Returns 0 if an error occurred.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond the delimiter. An application will+ * typically leave that data in the dynamic buffer sequence for a subsequent+ * read_until operation to examine.+ */+template <typename SyncReadStream, typename DynamicBuffer_v1>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ char delim, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Read data into a dynamic buffer sequence until it contains a specified+/// delimiter.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains the specified+ * delimiter. The call will block until one of the following conditions is+ * true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains the delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param delim The delimiter string.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the delimiter.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond the delimiter. An application will+ * typically leave that data in the dynamic buffer sequence for a subsequent+ * read_until operation to examine.+ *+ * @par Example+ * To read data into a @c std::string until a CR-LF sequence is encountered:+ * @code std::string data;+ * std::size_t n = asio::read_until(s,+ * asio::dynamic_buffer(data), "\r\n");+ * std::string line = data.substr(0, n);+ * data.erase(0, n); @endcode+ * After the @c read_until operation completes successfully, the string @c data+ * contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the+ * delimiter, so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the buffer @c b as+ * follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c read_until operation.+ */+template <typename SyncReadStream, typename DynamicBuffer_v1>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_STRING_VIEW_PARAM delim,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Read data into a dynamic buffer sequence until it contains a specified+/// delimiter.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains the specified+ * delimiter. The call will block until one of the following conditions is+ * true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains the delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param delim The delimiter string.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the delimiter. Returns 0 if an error occurred.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond the delimiter. An application will+ * typically leave that data in the dynamic buffer sequence for a subsequent+ * read_until operation to examine.+ */+template <typename SyncReadStream, typename DynamicBuffer_v1>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_STRING_VIEW_PARAM delim,+ asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++#if !defined(ASIO_NO_EXTENSIONS)+#if defined(ASIO_HAS_BOOST_REGEX) \+ || defined(GENERATING_DOCUMENTATION)++/// Read data into a dynamic buffer sequence until some part of the data it+/// contains matches a regular expression.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains some data+ * that matches a regular expression. The call will block until one of the+ * following conditions is true:+ *+ * @li A substring of the dynamic buffer sequence's get area matches the+ * regular expression.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains data that matches the regular expression, the function returns+ * immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers A dynamic buffer sequence into which the data will be read.+ *+ * @param expr The regular expression.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the substring that matches the regular expression.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond that which matched the regular+ * expression. An application will typically leave that data in the dynamic+ * buffer sequence for a subsequent read_until operation to examine.+ *+ * @par Example+ * To read data into a @c std::string until a CR-LF sequence is encountered:+ * @code std::string data;+ * std::size_t n = asio::read_until(s,+ * asio::dynamic_buffer(data), boost::regex("\r\n"));+ * std::string line = data.substr(0, n);+ * data.erase(0, n); @endcode+ * After the @c read_until operation completes successfully, the string @c data+ * contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the+ * delimiter, so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the buffer @c b as+ * follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c read_until operation.+ */+template <typename SyncReadStream, typename DynamicBuffer_v1>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ const boost::regex& expr,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Read data into a dynamic buffer sequence until some part of the data it+/// contains matches a regular expression.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains some data+ * that matches a regular expression. The call will block until one of the+ * following conditions is true:+ *+ * @li A substring of the dynamic buffer sequence's get area matches the+ * regular expression.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains data that matches the regular expression, the function returns+ * immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers A dynamic buffer sequence into which the data will be read.+ *+ * @param expr The regular expression.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the substring that matches the regular expression. Returns 0+ * if an error occurred.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond that which matched the regular+ * expression. An application will typically leave that data in the dynamic+ * buffer sequence for a subsequent read_until operation to examine.+ */+template <typename SyncReadStream, typename DynamicBuffer_v1>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ const boost::regex& expr, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++#endif // defined(ASIO_HAS_BOOST_REGEX)+ // || defined(GENERATING_DOCUMENTATION)++/// Read data into a dynamic buffer sequence until a function object indicates a+/// match.++/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until a user-defined match condition function object, when applied+ * to the data contained in the dynamic buffer sequence, indicates a successful+ * match. The call will block until one of the following conditions is true:+ *+ * @li The match condition function object returns a std::pair where the second+ * element evaluates to true.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the match condition function object already indicates+ * a match, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers A dynamic buffer sequence into which the data will be read.+ *+ * @param match_condition The function object to be called to determine whether+ * a match exists. The signature of the function object must be:+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);+ * @endcode+ * where @c iterator represents the type:+ * @code buffers_iterator<typename DynamicBuffer_v1::const_buffers_type>+ * @endcode+ * The iterator parameters @c begin and @c end define the range of bytes to be+ * scanned to determine whether there is a match. The @c first member of the+ * return value is an iterator marking one-past-the-end of the bytes that have+ * been consumed by the match function. This iterator is used to calculate the+ * @c begin parameter for any subsequent invocation of the match condition. The+ * @c second member of the return value is true if a match has been found, false+ * otherwise.+ *+ * @returns The number of bytes in the dynamic_buffer's get area that+ * have been fully consumed by the match function.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond that which matched the function object.+ * An application will typically leave that data in the dynamic buffer sequence+ * for a subsequent read_until operation to examine.++ * @note The default implementation of the @c is_match_condition type trait+ * evaluates to true for function pointers and function objects with a+ * @c result_type typedef. It must be specialised for other user-defined+ * function objects.+ *+ * @par Examples+ * To read data into a dynamic buffer sequence until whitespace is encountered:+ * @code typedef asio::buffers_iterator<+ * asio::const_buffers_1> iterator;+ *+ * std::pair<iterator, bool>+ * match_whitespace(iterator begin, iterator end)+ * {+ * iterator i = begin;+ * while (i != end)+ * if (std::isspace(*i++))+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ * ...+ * std::string data;+ * asio::read_until(s, data, match_whitespace);+ * @endcode+ *+ * To read data into a @c std::string until a matching character is found:+ * @code class match_char+ * {+ * public:+ * explicit match_char(char c) : c_(c) {}+ *+ * template <typename Iterator>+ * std::pair<Iterator, bool> operator()(+ * Iterator begin, Iterator end) const+ * {+ * Iterator i = begin;+ * while (i != end)+ * if (c_ == *i++)+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ *+ * private:+ * char c_;+ * };+ *+ * namespace asio {+ * template <> struct is_match_condition<match_char>+ * : public boost::true_type {};+ * } // namespace asio+ * ...+ * std::string data;+ * asio::read_until(s, data, match_char('a'));+ * @endcode+ */+template <typename SyncReadStream,+ typename DynamicBuffer_v1, typename MatchCondition>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ MatchCondition match_condition,+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Read data into a dynamic buffer sequence until a function object indicates a+/// match.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until a user-defined match condition function object, when applied+ * to the data contained in the dynamic buffer sequence, indicates a successful+ * match. The call will block until one of the following conditions is true:+ *+ * @li The match condition function object returns a std::pair where the second+ * element evaluates to true.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the match condition function object already indicates+ * a match, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers A dynamic buffer sequence into which the data will be read.+ *+ * @param match_condition The function object to be called to determine whether+ * a match exists. The signature of the function object must be:+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);+ * @endcode+ * where @c iterator represents the type:+ * @code buffers_iterator<DynamicBuffer_v1::const_buffers_type>+ * @endcode+ * The iterator parameters @c begin and @c end define the range of bytes to be+ * scanned to determine whether there is a match. The @c first member of the+ * return value is an iterator marking one-past-the-end of the bytes that have+ * been consumed by the match function. This iterator is used to calculate the+ * @c begin parameter for any subsequent invocation of the match condition. The+ * @c second member of the return value is true if a match has been found, false+ * otherwise.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area that+ * have been fully consumed by the match function. Returns 0 if an error+ * occurred.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond that which matched the function object.+ * An application will typically leave that data in the dynamic buffer sequence+ * for a subsequent read_until operation to examine.+ *+ * @note The default implementation of the @c is_match_condition type trait+ * evaluates to true for function pointers and function objects with a+ * @c result_type typedef. It must be specialised for other user-defined+ * function objects.+ */+template <typename SyncReadStream,+ typename DynamicBuffer_v1, typename MatchCondition>+std::size_t read_until(SyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ MatchCondition match_condition, asio::error_code& ec,+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++#if !defined(ASIO_NO_IOSTREAM)++/// Read data into a streambuf until it contains a specified delimiter.+/**+ * This function is used to read data into the specified streambuf until the+ * streambuf's get area contains the specified delimiter. The call will block+ * until one of the following conditions is true:+ *+ * @li The get area of the streambuf contains the specified delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the streambuf's get area already contains the+ * delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read.+ *+ * @param delim The delimiter character.+ *+ * @returns The number of bytes in the streambuf's get area up to and including+ * the delimiter.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note After a successful read_until operation, the streambuf may contain+ * additional data beyond the delimiter. An application will typically leave+ * that data in the streambuf for a subsequent read_until operation to examine.+ *+ * @par Example+ * To read data into a streambuf until a newline is encountered:+ * @code asio::streambuf b;+ * asio::read_until(s, b, '\n');+ * std::istream is(&b);+ * std::string line;+ * std::getline(is, line); @endcode+ * After the @c read_until operation completes successfully, the buffer @c b+ * contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode+ * The call to @c std::getline then extracts the data up to and including the+ * newline (which is discarded), so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c' } @endcode+ * The remaining data is left in the buffer @c b as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c read_until operation.+ */+template <typename SyncReadStream, typename Allocator>+std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, char delim);++/// Read data into a streambuf until it contains a specified delimiter.+/**+ * This function is used to read data into the specified streambuf until the+ * streambuf's get area contains the specified delimiter. The call will block+ * until one of the following conditions is true:+ *+ * @li The get area of the streambuf contains the specified delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the streambuf's get area already contains the+ * delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read.+ *+ * @param delim The delimiter character.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the streambuf's get area up to and including+ * the delimiter. Returns 0 if an error occurred.+ *+ * @note After a successful read_until operation, the streambuf may contain+ * additional data beyond the delimiter. An application will typically leave+ * that data in the streambuf for a subsequent read_until operation to examine.+ */+template <typename SyncReadStream, typename Allocator>+std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, char delim,+ asio::error_code& ec);++/// Read data into a streambuf until it contains a specified delimiter.+/**+ * This function is used to read data into the specified streambuf until the+ * streambuf's get area contains the specified delimiter. The call will block+ * until one of the following conditions is true:+ *+ * @li The get area of the streambuf contains the specified delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the streambuf's get area already contains the+ * delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read.+ *+ * @param delim The delimiter string.+ *+ * @returns The number of bytes in the streambuf's get area up to and including+ * the delimiter.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note After a successful read_until operation, the streambuf may contain+ * additional data beyond the delimiter. An application will typically leave+ * that data in the streambuf for a subsequent read_until operation to examine.+ *+ * @par Example+ * To read data into a streambuf until a newline is encountered:+ * @code asio::streambuf b;+ * asio::read_until(s, b, "\r\n");+ * std::istream is(&b);+ * std::string line;+ * std::getline(is, line); @endcode+ * After the @c read_until operation completes successfully, the buffer @c b+ * contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c std::getline then extracts the data up to and including the+ * newline (which is discarded), so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r' } @endcode+ * The remaining data is left in the buffer @c b as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c read_until operation.+ */+template <typename SyncReadStream, typename Allocator>+std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ ASIO_STRING_VIEW_PARAM delim);++/// Read data into a streambuf until it contains a specified delimiter.+/**+ * This function is used to read data into the specified streambuf until the+ * streambuf's get area contains the specified delimiter. The call will block+ * until one of the following conditions is true:+ *+ * @li The get area of the streambuf contains the specified delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the streambuf's get area already contains the+ * delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read.+ *+ * @param delim The delimiter string.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the streambuf's get area up to and including+ * the delimiter. Returns 0 if an error occurred.+ *+ * @note After a successful read_until operation, the streambuf may contain+ * additional data beyond the delimiter. An application will typically leave+ * that data in the streambuf for a subsequent read_until operation to examine.+ */+template <typename SyncReadStream, typename Allocator>+std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec);++#if defined(ASIO_HAS_BOOST_REGEX) \+ || defined(GENERATING_DOCUMENTATION)++/// Read data into a streambuf until some part of the data it contains matches+/// a regular expression.+/**+ * This function is used to read data into the specified streambuf until the+ * streambuf's get area contains some data that matches a regular expression.+ * The call will block until one of the following conditions is true:+ *+ * @li A substring of the streambuf's get area matches the regular expression.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the streambuf's get area already contains data that+ * matches the regular expression, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read.+ *+ * @param expr The regular expression.+ *+ * @returns The number of bytes in the streambuf's get area up to and including+ * the substring that matches the regular expression.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note After a successful read_until operation, the streambuf may contain+ * additional data beyond that which matched the regular expression. An+ * application will typically leave that data in the streambuf for a subsequent+ * read_until operation to examine.+ *+ * @par Example+ * To read data into a streambuf until a CR-LF sequence is encountered:+ * @code asio::streambuf b;+ * asio::read_until(s, b, boost::regex("\r\n"));+ * std::istream is(&b);+ * std::string line;+ * std::getline(is, line); @endcode+ * After the @c read_until operation completes successfully, the buffer @c b+ * contains the data which matched the regular expression:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c std::getline then extracts the data up to and including the+ * newline (which is discarded), so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r' } @endcode+ * The remaining data is left in the buffer @c b as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c read_until operation.+ */+template <typename SyncReadStream, typename Allocator>+std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr);++/// Read data into a streambuf until some part of the data it contains matches+/// a regular expression.+/**+ * This function is used to read data into the specified streambuf until the+ * streambuf's get area contains some data that matches a regular expression.+ * The call will block until one of the following conditions is true:+ *+ * @li A substring of the streambuf's get area matches the regular expression.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the streambuf's get area already contains data that+ * matches the regular expression, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read.+ *+ * @param expr The regular expression.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the streambuf's get area up to and including+ * the substring that matches the regular expression. Returns 0 if an error+ * occurred.+ *+ * @note After a successful read_until operation, the streambuf may contain+ * additional data beyond that which matched the regular expression. An+ * application will typically leave that data in the streambuf for a subsequent+ * read_until operation to examine.+ */+template <typename SyncReadStream, typename Allocator>+std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr,+ asio::error_code& ec);++#endif // defined(ASIO_HAS_BOOST_REGEX)+ // || defined(GENERATING_DOCUMENTATION)++/// Read data into a streambuf until a function object indicates a match.+/**+ * This function is used to read data into the specified streambuf until a+ * user-defined match condition function object, when applied to the data+ * contained in the streambuf, indicates a successful match. The call will+ * block until one of the following conditions is true:+ *+ * @li The match condition function object returns a std::pair where the second+ * element evaluates to true.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the match condition function object already indicates+ * a match, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read.+ *+ * @param match_condition The function object to be called to determine whether+ * a match exists. The signature of the function object must be:+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);+ * @endcode+ * where @c iterator represents the type:+ * @code buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>+ * @endcode+ * The iterator parameters @c begin and @c end define the range of bytes to be+ * scanned to determine whether there is a match. The @c first member of the+ * return value is an iterator marking one-past-the-end of the bytes that have+ * been consumed by the match function. This iterator is used to calculate the+ * @c begin parameter for any subsequent invocation of the match condition. The+ * @c second member of the return value is true if a match has been found, false+ * otherwise.+ *+ * @returns The number of bytes in the streambuf's get area that have been fully+ * consumed by the match function.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note After a successful read_until operation, the streambuf may contain+ * additional data beyond that which matched the function object. An application+ * will typically leave that data in the streambuf for a subsequent read_until+ * operation to examine.+ *+ * @note The default implementation of the @c is_match_condition type trait+ * evaluates to true for function pointers and function objects with a+ * @c result_type typedef. It must be specialised for other user-defined+ * function objects.+ *+ * @par Examples+ * To read data into a streambuf until whitespace is encountered:+ * @code typedef asio::buffers_iterator<+ * asio::streambuf::const_buffers_type> iterator;+ *+ * std::pair<iterator, bool>+ * match_whitespace(iterator begin, iterator end)+ * {+ * iterator i = begin;+ * while (i != end)+ * if (std::isspace(*i++))+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ * ...+ * asio::streambuf b;+ * asio::read_until(s, b, match_whitespace);+ * @endcode+ *+ * To read data into a streambuf until a matching character is found:+ * @code class match_char+ * {+ * public:+ * explicit match_char(char c) : c_(c) {}+ *+ * template <typename Iterator>+ * std::pair<Iterator, bool> operator()(+ * Iterator begin, Iterator end) const+ * {+ * Iterator i = begin;+ * while (i != end)+ * if (c_ == *i++)+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ *+ * private:+ * char c_;+ * };+ *+ * namespace asio {+ * template <> struct is_match_condition<match_char>+ * : public boost::true_type {};+ * } // namespace asio+ * ...+ * asio::streambuf b;+ * asio::read_until(s, b, match_char('a'));+ * @endcode+ */+template <typename SyncReadStream, typename Allocator, typename MatchCondition>+std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, MatchCondition match_condition,+ typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0);++/// Read data into a streambuf until a function object indicates a match.+/**+ * This function is used to read data into the specified streambuf until a+ * user-defined match condition function object, when applied to the data+ * contained in the streambuf, indicates a successful match. The call will+ * block until one of the following conditions is true:+ *+ * @li The match condition function object returns a std::pair where the second+ * element evaluates to true.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the match condition function object already indicates+ * a match, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read.+ *+ * @param match_condition The function object to be called to determine whether+ * a match exists. The signature of the function object must be:+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);+ * @endcode+ * where @c iterator represents the type:+ * @code buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>+ * @endcode+ * The iterator parameters @c begin and @c end define the range of bytes to be+ * scanned to determine whether there is a match. The @c first member of the+ * return value is an iterator marking one-past-the-end of the bytes that have+ * been consumed by the match function. This iterator is used to calculate the+ * @c begin parameter for any subsequent invocation of the match condition. The+ * @c second member of the return value is true if a match has been found, false+ * otherwise.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the streambuf's get area that have been fully+ * consumed by the match function. Returns 0 if an error occurred.+ *+ * @note After a successful read_until operation, the streambuf may contain+ * additional data beyond that which matched the function object. An application+ * will typically leave that data in the streambuf for a subsequent read_until+ * operation to examine.+ *+ * @note The default implementation of the @c is_match_condition type trait+ * evaluates to true for function pointers and function objects with a+ * @c result_type typedef. It must be specialised for other user-defined+ * function objects.+ */+template <typename SyncReadStream, typename Allocator, typename MatchCondition>+std::size_t read_until(SyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ MatchCondition match_condition, asio::error_code& ec,+ typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0);++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Read data into a dynamic buffer sequence until it contains a specified+/// delimiter.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains the specified+ * delimiter. The call will block until one of the following conditions is+ * true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains the delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param delim The delimiter character.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the delimiter.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond the delimiter. An application will+ * typically leave that data in the dynamic buffer sequence for a subsequent+ * read_until operation to examine.+ *+ * @par Example+ * To read data into a @c std::string until a newline is encountered:+ * @code std::string data;+ * std::size_t n = asio::read_until(s,+ * asio::dynamic_buffer(data), '\n');+ * std::string line = data.substr(0, n);+ * data.erase(0, n); @endcode+ * After the @c read_until operation completes successfully, the string @c data+ * contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the+ * delimiter, so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the buffer @c b as+ * follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c read_until operation.+ */+template <typename SyncReadStream, typename DynamicBuffer_v2>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, char delim,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Read data into a dynamic buffer sequence until it contains a specified+/// delimiter.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains the specified+ * delimiter. The call will block until one of the following conditions is+ * true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains the delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param delim The delimiter character.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the delimiter. Returns 0 if an error occurred.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond the delimiter. An application will+ * typically leave that data in the dynamic buffer sequence for a subsequent+ * read_until operation to examine.+ */+template <typename SyncReadStream, typename DynamicBuffer_v2>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,+ char delim, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Read data into a dynamic buffer sequence until it contains a specified+/// delimiter.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains the specified+ * delimiter. The call will block until one of the following conditions is+ * true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains the delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param delim The delimiter string.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the delimiter.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond the delimiter. An application will+ * typically leave that data in the dynamic buffer sequence for a subsequent+ * read_until operation to examine.+ *+ * @par Example+ * To read data into a @c std::string until a CR-LF sequence is encountered:+ * @code std::string data;+ * std::size_t n = asio::read_until(s,+ * asio::dynamic_buffer(data), "\r\n");+ * std::string line = data.substr(0, n);+ * data.erase(0, n); @endcode+ * After the @c read_until operation completes successfully, the string @c data+ * contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the+ * delimiter, so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the buffer @c b as+ * follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c read_until operation.+ */+template <typename SyncReadStream, typename DynamicBuffer_v2>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,+ ASIO_STRING_VIEW_PARAM delim,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Read data into a dynamic buffer sequence until it contains a specified+/// delimiter.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains the specified+ * delimiter. The call will block until one of the following conditions is+ * true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains the delimiter, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence into which the data will be read.+ *+ * @param delim The delimiter string.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the delimiter. Returns 0 if an error occurred.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond the delimiter. An application will+ * typically leave that data in the dynamic buffer sequence for a subsequent+ * read_until operation to examine.+ */+template <typename SyncReadStream, typename DynamicBuffer_v2>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,+ ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++#if !defined(ASIO_NO_EXTENSIONS)+#if defined(ASIO_HAS_BOOST_REGEX) \+ || defined(GENERATING_DOCUMENTATION)++/// Read data into a dynamic buffer sequence until some part of the data it+/// contains matches a regular expression.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains some data+ * that matches a regular expression. The call will block until one of the+ * following conditions is true:+ *+ * @li A substring of the dynamic buffer sequence's get area matches the+ * regular expression.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains data that matches the regular expression, the function returns+ * immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers A dynamic buffer sequence into which the data will be read.+ *+ * @param expr The regular expression.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the substring that matches the regular expression.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond that which matched the regular+ * expression. An application will typically leave that data in the dynamic+ * buffer sequence for a subsequent read_until operation to examine.+ *+ * @par Example+ * To read data into a @c std::string until a CR-LF sequence is encountered:+ * @code std::string data;+ * std::size_t n = asio::read_until(s,+ * asio::dynamic_buffer(data), boost::regex("\r\n"));+ * std::string line = data.substr(0, n);+ * data.erase(0, n); @endcode+ * After the @c read_until operation completes successfully, the string @c data+ * contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the+ * delimiter, so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the buffer @c b as+ * follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c read_until operation.+ */+template <typename SyncReadStream, typename DynamicBuffer_v2>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,+ const boost::regex& expr,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Read data into a dynamic buffer sequence until some part of the data it+/// contains matches a regular expression.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until the dynamic buffer sequence's get area contains some data+ * that matches a regular expression. The call will block until one of the+ * following conditions is true:+ *+ * @li A substring of the dynamic buffer sequence's get area matches the+ * regular expression.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the dynamic buffer sequence's get area already+ * contains data that matches the regular expression, the function returns+ * immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers A dynamic buffer sequence into which the data will be read.+ *+ * @param expr The regular expression.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area up to+ * and including the substring that matches the regular expression. Returns 0+ * if an error occurred.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond that which matched the regular+ * expression. An application will typically leave that data in the dynamic+ * buffer sequence for a subsequent read_until operation to examine.+ */+template <typename SyncReadStream, typename DynamicBuffer_v2>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,+ const boost::regex& expr, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++#endif // defined(ASIO_HAS_BOOST_REGEX)+ // || defined(GENERATING_DOCUMENTATION)++/// Read data into a dynamic buffer sequence until a function object indicates a+/// match.++/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until a user-defined match condition function object, when applied+ * to the data contained in the dynamic buffer sequence, indicates a successful+ * match. The call will block until one of the following conditions is true:+ *+ * @li The match condition function object returns a std::pair where the second+ * element evaluates to true.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the match condition function object already indicates+ * a match, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers A dynamic buffer sequence into which the data will be read.+ *+ * @param match_condition The function object to be called to determine whether+ * a match exists. The signature of the function object must be:+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);+ * @endcode+ * where @c iterator represents the type:+ * @code buffers_iterator<typename DynamicBuffer_v2::const_buffers_type>+ * @endcode+ * The iterator parameters @c begin and @c end define the range of bytes to be+ * scanned to determine whether there is a match. The @c first member of the+ * return value is an iterator marking one-past-the-end of the bytes that have+ * been consumed by the match function. This iterator is used to calculate the+ * @c begin parameter for any subsequent invocation of the match condition. The+ * @c second member of the return value is true if a match has been found, false+ * otherwise.+ *+ * @returns The number of bytes in the dynamic_buffer's get area that+ * have been fully consumed by the match function.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond that which matched the function object.+ * An application will typically leave that data in the dynamic buffer sequence+ * for a subsequent read_until operation to examine.++ * @note The default implementation of the @c is_match_condition type trait+ * evaluates to true for function pointers and function objects with a+ * @c result_type typedef. It must be specialised for other user-defined+ * function objects.+ *+ * @par Examples+ * To read data into a dynamic buffer sequence until whitespace is encountered:+ * @code typedef asio::buffers_iterator<+ * asio::const_buffers_1> iterator;+ *+ * std::pair<iterator, bool>+ * match_whitespace(iterator begin, iterator end)+ * {+ * iterator i = begin;+ * while (i != end)+ * if (std::isspace(*i++))+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ * ...+ * std::string data;+ * asio::read_until(s, data, match_whitespace);+ * @endcode+ *+ * To read data into a @c std::string until a matching character is found:+ * @code class match_char+ * {+ * public:+ * explicit match_char(char c) : c_(c) {}+ *+ * template <typename Iterator>+ * std::pair<Iterator, bool> operator()(+ * Iterator begin, Iterator end) const+ * {+ * Iterator i = begin;+ * while (i != end)+ * if (c_ == *i++)+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ *+ * private:+ * char c_;+ * };+ *+ * namespace asio {+ * template <> struct is_match_condition<match_char>+ * : public boost::true_type {};+ * } // namespace asio+ * ...+ * std::string data;+ * asio::read_until(s, data, match_char('a'));+ * @endcode+ */+template <typename SyncReadStream,+ typename DynamicBuffer_v2, typename MatchCondition>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,+ MatchCondition match_condition,+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Read data into a dynamic buffer sequence until a function object indicates a+/// match.+/**+ * This function is used to read data into the specified dynamic buffer+ * sequence until a user-defined match condition function object, when applied+ * to the data contained in the dynamic buffer sequence, indicates a successful+ * match. The call will block until one of the following conditions is true:+ *+ * @li The match condition function object returns a std::pair where the second+ * element evaluates to true.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * read_some function. If the match condition function object already indicates+ * a match, the function returns immediately.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the SyncReadStream concept.+ *+ * @param buffers A dynamic buffer sequence into which the data will be read.+ *+ * @param match_condition The function object to be called to determine whether+ * a match exists. The signature of the function object must be:+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);+ * @endcode+ * where @c iterator represents the type:+ * @code buffers_iterator<DynamicBuffer_v2::const_buffers_type>+ * @endcode+ * The iterator parameters @c begin and @c end define the range of bytes to be+ * scanned to determine whether there is a match. The @c first member of the+ * return value is an iterator marking one-past-the-end of the bytes that have+ * been consumed by the match function. This iterator is used to calculate the+ * @c begin parameter for any subsequent invocation of the match condition. The+ * @c second member of the return value is true if a match has been found, false+ * otherwise.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes in the dynamic buffer sequence's get area that+ * have been fully consumed by the match function. Returns 0 if an error+ * occurred.+ *+ * @note After a successful read_until operation, the dynamic buffer sequence+ * may contain additional data beyond that which matched the function object.+ * An application will typically leave that data in the dynamic buffer sequence+ * for a subsequent read_until operation to examine.+ *+ * @note The default implementation of the @c is_match_condition type trait+ * evaluates to true for function pointers and function objects with a+ * @c result_type typedef. It must be specialised for other user-defined+ * function objects.+ */+template <typename SyncReadStream,+ typename DynamicBuffer_v2, typename MatchCondition>+std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers,+ MatchCondition match_condition, asio::error_code& ec,+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++#endif // !defined(ASIO_NO_EXTENSIONS)++/*@}*/+/**+ * @defgroup async_read_until asio::async_read_until+ *+ * @brief The @c async_read_until function is a composed asynchronous operation+ * that reads data into a dynamic buffer sequence, or into a streambuf, until+ * it contains a delimiter, matches a regular expression, or a function object+ * indicates a match.+ */+/*@{*/++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Start an asynchronous operation to read data into a dynamic buffer sequence+/// until it contains a specified delimiter.+/**+ * This function is used to asynchronously read data into the specified dynamic+ * buffer sequence until the dynamic buffer sequence's get area contains the+ * specified delimiter. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the dynamic buffer sequence's get area already contains the delimiter, this+ * asynchronous operation completes immediately. The program must ensure that+ * the stream performs no other read operations (such as async_read,+ * async_read_until, the stream's async_read_some function, or any other+ * composed operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param delim The delimiter character.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the dynamic buffer sequence's+ * // get area up to and including the delimiter.+ * // 0 if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the dynamic buffer+ * sequence may contain additional data beyond the delimiter. An application+ * will typically leave that data in the dynamic buffer sequence for a+ * subsequent async_read_until operation to examine.+ *+ * @par Example+ * To asynchronously read data into a @c std::string until a newline is+ * encountered:+ * @code std::string data;+ * ...+ * void handler(const asio::error_code& e, std::size_t size)+ * {+ * if (!e)+ * {+ * std::string line = data.substr(0, n);+ * data.erase(0, n);+ * ...+ * }+ * }+ * ...+ * asio::async_read_until(s, data, '\n', handler); @endcode+ * After the @c async_read_until operation completes successfully, the buffer+ * @c data contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the+ * delimiter, so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the buffer @c data+ * as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c async_read_until operation.+ */+template <typename AsyncReadStream, typename DynamicBuffer_v1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Start an asynchronous operation to read data into a dynamic buffer sequence+/// until it contains a specified delimiter.+/**+ * This function is used to asynchronously read data into the specified dynamic+ * buffer sequence until the dynamic buffer sequence's get area contains the+ * specified delimiter. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the dynamic buffer sequence's get area already contains the delimiter, this+ * asynchronous operation completes immediately. The program must ensure that+ * the stream performs no other read operations (such as async_read,+ * async_read_until, the stream's async_read_some function, or any other+ * composed operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param delim The delimiter string.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the dynamic buffer sequence's+ * // get area up to and including the delimiter.+ * // 0 if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the dynamic buffer+ * sequence may contain additional data beyond the delimiter. An application+ * will typically leave that data in the dynamic buffer sequence for a+ * subsequent async_read_until operation to examine.+ *+ * @par Example+ * To asynchronously read data into a @c std::string until a CR-LF sequence is+ * encountered:+ * @code std::string data;+ * ...+ * void handler(const asio::error_code& e, std::size_t size)+ * {+ * if (!e)+ * {+ * std::string line = data.substr(0, n);+ * data.erase(0, n);+ * ...+ * }+ * }+ * ...+ * asio::async_read_until(s, data, "\r\n", handler); @endcode+ * After the @c async_read_until operation completes successfully, the string+ * @c data contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the+ * delimiter, so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the string @c data+ * as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c async_read_until operation.+ */+template <typename AsyncReadStream, typename DynamicBuffer_v1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_STRING_VIEW_PARAM delim,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++#if !defined(ASIO_NO_EXTENSIONS)+#if defined(ASIO_HAS_BOOST_REGEX) \+ || defined(GENERATING_DOCUMENTATION)++/// Start an asynchronous operation to read data into a dynamic buffer sequence+/// until some part of its data matches a regular expression.+/**+ * This function is used to asynchronously read data into the specified dynamic+ * buffer sequence until the dynamic buffer sequence's get area contains some+ * data that matches a regular expression. The function call always returns+ * immediately. The asynchronous operation will continue until one of the+ * following conditions is true:+ *+ * @li A substring of the dynamic buffer sequence's get area matches the regular+ * expression.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the dynamic buffer sequence's get area already contains data that matches+ * the regular expression, this asynchronous operation completes immediately.+ * The program must ensure that the stream performs no other read operations+ * (such as async_read, async_read_until, the stream's async_read_some+ * function, or any other composed operations that perform reads) until this+ * operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param expr The regular expression.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the dynamic buffer+ * // sequence's get area up to and including the+ * // substring that matches the regular expression.+ * // 0 if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the dynamic buffer+ * sequence may contain additional data beyond that which matched the regular+ * expression. An application will typically leave that data in the dynamic+ * buffer sequence for a subsequent async_read_until operation to examine.+ *+ * @par Example+ * To asynchronously read data into a @c std::string until a CR-LF sequence is+ * encountered:+ * @code std::string data;+ * ...+ * void handler(const asio::error_code& e, std::size_t size)+ * {+ * if (!e)+ * {+ * std::string line = data.substr(0, n);+ * data.erase(0, n);+ * ...+ * }+ * }+ * ...+ * asio::async_read_until(s, data,+ * boost::regex("\r\n"), handler); @endcode+ * After the @c async_read_until operation completes successfully, the string+ * @c data contains the data which matched the regular expression:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the match,+ * so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the string @c data+ * as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c async_read_until operation.+ */+template <typename AsyncReadStream, typename DynamicBuffer_v1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ const boost::regex& expr,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++#endif // defined(ASIO_HAS_BOOST_REGEX)+ // || defined(GENERATING_DOCUMENTATION)++/// Start an asynchronous operation to read data into a dynamic buffer sequence+/// until a function object indicates a match.+/**+ * This function is used to asynchronously read data into the specified dynamic+ * buffer sequence until a user-defined match condition function object, when+ * applied to the data contained in the dynamic buffer sequence, indicates a+ * successful match. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li The match condition function object returns a std::pair where the second+ * element evaluates to true.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the match condition function object already indicates a match, this+ * asynchronous operation completes immediately. The program must ensure that+ * the stream performs no other read operations (such as async_read,+ * async_read_until, the stream's async_read_some function, or any other+ * composed operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param match_condition The function object to be called to determine whether+ * a match exists. The signature of the function object must be:+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);+ * @endcode+ * where @c iterator represents the type:+ * @code buffers_iterator<typename DynamicBuffer_v1::const_buffers_type>+ * @endcode+ * The iterator parameters @c begin and @c end define the range of bytes to be+ * scanned to determine whether there is a match. The @c first member of the+ * return value is an iterator marking one-past-the-end of the bytes that have+ * been consumed by the match function. This iterator is used to calculate the+ * @c begin parameter for any subsequent invocation of the match condition. The+ * @c second member of the return value is true if a match has been found, false+ * otherwise.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the dynamic buffer sequence's+ * // get area that have been fully consumed by the match+ * // function. O if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the dynamic buffer+ * sequence may contain additional data beyond that which matched the function+ * object. An application will typically leave that data in the dynamic buffer+ * sequence for a subsequent async_read_until operation to examine.+ *+ * @note The default implementation of the @c is_match_condition type trait+ * evaluates to true for function pointers and function objects with a+ * @c result_type typedef. It must be specialised for other user-defined+ * function objects.+ *+ * @par Examples+ * To asynchronously read data into a @c std::string until whitespace is+ * encountered:+ * @code typedef asio::buffers_iterator<+ * asio::const_buffers_1> iterator;+ *+ * std::pair<iterator, bool>+ * match_whitespace(iterator begin, iterator end)+ * {+ * iterator i = begin;+ * while (i != end)+ * if (std::isspace(*i++))+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ * ...+ * void handler(const asio::error_code& e, std::size_t size);+ * ...+ * std::string data;+ * asio::async_read_until(s, data, match_whitespace, handler);+ * @endcode+ *+ * To asynchronously read data into a @c std::string until a matching character+ * is found:+ * @code class match_char+ * {+ * public:+ * explicit match_char(char c) : c_(c) {}+ *+ * template <typename Iterator>+ * std::pair<Iterator, bool> operator()(+ * Iterator begin, Iterator end) const+ * {+ * Iterator i = begin;+ * while (i != end)+ * if (c_ == *i++)+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ *+ * private:+ * char c_;+ * };+ *+ * namespace asio {+ * template <> struct is_match_condition<match_char>+ * : public boost::true_type {};+ * } // namespace asio+ * ...+ * void handler(const asio::error_code& e, std::size_t size);+ * ...+ * std::string data;+ * asio::async_read_until(s, data, match_char('a'), handler);+ * @endcode+ */+template <typename AsyncReadStream,+ typename DynamicBuffer_v1, typename MatchCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ MatchCondition match_condition,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++#if !defined(ASIO_NO_IOSTREAM)++/// Start an asynchronous operation to read data into a streambuf until it+/// contains a specified delimiter.+/**+ * This function is used to asynchronously read data into the specified+ * streambuf until the streambuf's get area contains the specified delimiter.+ * The function call always returns immediately. The asynchronous operation+ * will continue until one of the following conditions is true:+ *+ * @li The get area of the streambuf contains the specified delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the streambuf's get area already contains the delimiter, this asynchronous+ * operation completes immediately. The program must ensure that the stream+ * performs no other read operations (such as async_read, async_read_until, the+ * stream's async_read_some function, or any other composed operations that+ * perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read. Ownership of+ * the streambuf is retained by the caller, which must guarantee that it remains+ * valid until the handler is called.+ *+ * @param delim The delimiter character.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the streambuf's get+ * // area up to and including the delimiter.+ * // 0 if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the streambuf may+ * contain additional data beyond the delimiter. An application will typically+ * leave that data in the streambuf for a subsequent async_read_until operation+ * to examine.+ *+ * @par Example+ * To asynchronously read data into a streambuf until a newline is encountered:+ * @code asio::streambuf b;+ * ...+ * void handler(const asio::error_code& e, std::size_t size)+ * {+ * if (!e)+ * {+ * std::istream is(&b);+ * std::string line;+ * std::getline(is, line);+ * ...+ * }+ * }+ * ...+ * asio::async_read_until(s, b, '\n', handler); @endcode+ * After the @c async_read_until operation completes successfully, the buffer+ * @c b contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode+ * The call to @c std::getline then extracts the data up to and including the+ * newline (which is discarded), so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c' } @endcode+ * The remaining data is left in the buffer @c b as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c async_read_until operation.+ */+template <typename AsyncReadStream, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, char delim,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type));++/// Start an asynchronous operation to read data into a streambuf until it+/// contains a specified delimiter.+/**+ * This function is used to asynchronously read data into the specified+ * streambuf until the streambuf's get area contains the specified delimiter.+ * The function call always returns immediately. The asynchronous operation+ * will continue until one of the following conditions is true:+ *+ * @li The get area of the streambuf contains the specified delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the streambuf's get area already contains the delimiter, this asynchronous+ * operation completes immediately. The program must ensure that the stream+ * performs no other read operations (such as async_read, async_read_until, the+ * stream's async_read_some function, or any other composed operations that+ * perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read. Ownership of+ * the streambuf is retained by the caller, which must guarantee that it remains+ * valid until the handler is called.+ *+ * @param delim The delimiter string.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the streambuf's get+ * // area up to and including the delimiter.+ * // 0 if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the streambuf may+ * contain additional data beyond the delimiter. An application will typically+ * leave that data in the streambuf for a subsequent async_read_until operation+ * to examine.+ *+ * @par Example+ * To asynchronously read data into a streambuf until a newline is encountered:+ * @code asio::streambuf b;+ * ...+ * void handler(const asio::error_code& e, std::size_t size)+ * {+ * if (!e)+ * {+ * std::istream is(&b);+ * std::string line;+ * std::getline(is, line);+ * ...+ * }+ * }+ * ...+ * asio::async_read_until(s, b, "\r\n", handler); @endcode+ * After the @c async_read_until operation completes successfully, the buffer+ * @c b contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c std::getline then extracts the data up to and including the+ * newline (which is discarded), so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r' } @endcode+ * The remaining data is left in the buffer @c b as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c async_read_until operation.+ */+template <typename AsyncReadStream, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ ASIO_STRING_VIEW_PARAM delim,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type));++#if defined(ASIO_HAS_BOOST_REGEX) \+ || defined(GENERATING_DOCUMENTATION)++/// Start an asynchronous operation to read data into a streambuf until some+/// part of its data matches a regular expression.+/**+ * This function is used to asynchronously read data into the specified+ * streambuf until the streambuf's get area contains some data that matches a+ * regular expression. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li A substring of the streambuf's get area matches the regular expression.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the streambuf's get area already contains data that matches the regular+ * expression, this asynchronous operation completes immediately. The program+ * must ensure that the stream performs no other read operations (such as+ * async_read, async_read_until, the stream's async_read_some function, or any+ * other composed operations that perform reads) until this operation+ * completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read. Ownership of+ * the streambuf is retained by the caller, which must guarantee that it remains+ * valid until the handler is called.+ *+ * @param expr The regular expression.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the streambuf's get+ * // area up to and including the substring+ * // that matches the regular. expression.+ * // 0 if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the streambuf may+ * contain additional data beyond that which matched the regular expression. An+ * application will typically leave that data in the streambuf for a subsequent+ * async_read_until operation to examine.+ *+ * @par Example+ * To asynchronously read data into a streambuf until a CR-LF sequence is+ * encountered:+ * @code asio::streambuf b;+ * ...+ * void handler(const asio::error_code& e, std::size_t size)+ * {+ * if (!e)+ * {+ * std::istream is(&b);+ * std::string line;+ * std::getline(is, line);+ * ...+ * }+ * }+ * ...+ * asio::async_read_until(s, b, boost::regex("\r\n"), handler); @endcode+ * After the @c async_read_until operation completes successfully, the buffer+ * @c b contains the data which matched the regular expression:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c std::getline then extracts the data up to and including the+ * newline (which is discarded), so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r' } @endcode+ * The remaining data is left in the buffer @c b as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c async_read_until operation.+ */+template <typename AsyncReadStream, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ asio::basic_streambuf<Allocator>& b, const boost::regex& expr,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type));++#endif // defined(ASIO_HAS_BOOST_REGEX)+ // || defined(GENERATING_DOCUMENTATION)++/// Start an asynchronous operation to read data into a streambuf until a+/// function object indicates a match.+/**+ * This function is used to asynchronously read data into the specified+ * streambuf until a user-defined match condition function object, when applied+ * to the data contained in the streambuf, indicates a successful match. The+ * function call always returns immediately. The asynchronous operation will+ * continue until one of the following conditions is true:+ *+ * @li The match condition function object returns a std::pair where the second+ * element evaluates to true.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the match condition function object already indicates a match, this+ * asynchronous operation completes immediately. The program must ensure that+ * the stream performs no other read operations (such as async_read,+ * async_read_until, the stream's async_read_some function, or any other+ * composed operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param b A streambuf object into which the data will be read.+ *+ * @param match_condition The function object to be called to determine whether+ * a match exists. The signature of the function object must be:+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);+ * @endcode+ * where @c iterator represents the type:+ * @code buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>+ * @endcode+ * The iterator parameters @c begin and @c end define the range of bytes to be+ * scanned to determine whether there is a match. The @c first member of the+ * return value is an iterator marking one-past-the-end of the bytes that have+ * been consumed by the match function. This iterator is used to calculate the+ * @c begin parameter for any subsequent invocation of the match condition. The+ * @c second member of the return value is true if a match has been found, false+ * otherwise.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the streambuf's get+ * // area that have been fully consumed by the+ * // match function. O if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the streambuf may+ * contain additional data beyond that which matched the function object. An+ * application will typically leave that data in the streambuf for a subsequent+ * async_read_until operation to examine.+ *+ * @note The default implementation of the @c is_match_condition type trait+ * evaluates to true for function pointers and function objects with a+ * @c result_type typedef. It must be specialised for other user-defined+ * function objects.+ *+ * @par Examples+ * To asynchronously read data into a streambuf until whitespace is encountered:+ * @code typedef asio::buffers_iterator<+ * asio::streambuf::const_buffers_type> iterator;+ *+ * std::pair<iterator, bool>+ * match_whitespace(iterator begin, iterator end)+ * {+ * iterator i = begin;+ * while (i != end)+ * if (std::isspace(*i++))+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ * ...+ * void handler(const asio::error_code& e, std::size_t size);+ * ...+ * asio::streambuf b;+ * asio::async_read_until(s, b, match_whitespace, handler);+ * @endcode+ *+ * To asynchronously read data into a streambuf until a matching character is+ * found:+ * @code class match_char+ * {+ * public:+ * explicit match_char(char c) : c_(c) {}+ *+ * template <typename Iterator>+ * std::pair<Iterator, bool> operator()(+ * Iterator begin, Iterator end) const+ * {+ * Iterator i = begin;+ * while (i != end)+ * if (c_ == *i++)+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ *+ * private:+ * char c_;+ * };+ *+ * namespace asio {+ * template <> struct is_match_condition<match_char>+ * : public boost::true_type {};+ * } // namespace asio+ * ...+ * void handler(const asio::error_code& e, std::size_t size);+ * ...+ * asio::streambuf b;+ * asio::async_read_until(s, b, match_char('a'), handler);+ * @endcode+ */+template <typename AsyncReadStream, typename Allocator, typename MatchCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s,+ asio::basic_streambuf<Allocator>& b,+ MatchCondition match_condition,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0);++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Start an asynchronous operation to read data into a dynamic buffer sequence+/// until it contains a specified delimiter.+/**+ * This function is used to asynchronously read data into the specified dynamic+ * buffer sequence until the dynamic buffer sequence's get area contains the+ * specified delimiter. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the dynamic buffer sequence's get area already contains the delimiter, this+ * asynchronous operation completes immediately. The program must ensure that+ * the stream performs no other read operations (such as async_read,+ * async_read_until, the stream's async_read_some function, or any other+ * composed operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param delim The delimiter character.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the dynamic buffer sequence's+ * // get area up to and including the delimiter.+ * // 0 if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the dynamic buffer+ * sequence may contain additional data beyond the delimiter. An application+ * will typically leave that data in the dynamic buffer sequence for a+ * subsequent async_read_until operation to examine.+ *+ * @par Example+ * To asynchronously read data into a @c std::string until a newline is+ * encountered:+ * @code std::string data;+ * ...+ * void handler(const asio::error_code& e, std::size_t size)+ * {+ * if (!e)+ * {+ * std::string line = data.substr(0, n);+ * data.erase(0, n);+ * ...+ * }+ * }+ * ...+ * asio::async_read_until(s, data, '\n', handler); @endcode+ * After the @c async_read_until operation completes successfully, the buffer+ * @c data contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the+ * delimiter, so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the buffer @c data+ * as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c async_read_until operation.+ */+template <typename AsyncReadStream, typename DynamicBuffer_v2,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, char delim,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Start an asynchronous operation to read data into a dynamic buffer sequence+/// until it contains a specified delimiter.+/**+ * This function is used to asynchronously read data into the specified dynamic+ * buffer sequence until the dynamic buffer sequence's get area contains the+ * specified delimiter. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li The get area of the dynamic buffer sequence contains the specified+ * delimiter.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the dynamic buffer sequence's get area already contains the delimiter, this+ * asynchronous operation completes immediately. The program must ensure that+ * the stream performs no other read operations (such as async_read,+ * async_read_until, the stream's async_read_some function, or any other+ * composed operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param delim The delimiter string.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the dynamic buffer sequence's+ * // get area up to and including the delimiter.+ * // 0 if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the dynamic buffer+ * sequence may contain additional data beyond the delimiter. An application+ * will typically leave that data in the dynamic buffer sequence for a+ * subsequent async_read_until operation to examine.+ *+ * @par Example+ * To asynchronously read data into a @c std::string until a CR-LF sequence is+ * encountered:+ * @code std::string data;+ * ...+ * void handler(const asio::error_code& e, std::size_t size)+ * {+ * if (!e)+ * {+ * std::string line = data.substr(0, n);+ * data.erase(0, n);+ * ...+ * }+ * }+ * ...+ * asio::async_read_until(s, data, "\r\n", handler); @endcode+ * After the @c async_read_until operation completes successfully, the string+ * @c data contains the delimiter:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the+ * delimiter, so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the string @c data+ * as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c async_read_until operation.+ */+template <typename AsyncReadStream, typename DynamicBuffer_v2,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,+ ASIO_STRING_VIEW_PARAM delim,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++#if !defined(ASIO_NO_EXTENSIONS)+#if defined(ASIO_HAS_BOOST_REGEX) \+ || defined(GENERATING_DOCUMENTATION)++/// Start an asynchronous operation to read data into a dynamic buffer sequence+/// until some part of its data matches a regular expression.+/**+ * This function is used to asynchronously read data into the specified dynamic+ * buffer sequence until the dynamic buffer sequence's get area contains some+ * data that matches a regular expression. The function call always returns+ * immediately. The asynchronous operation will continue until one of the+ * following conditions is true:+ *+ * @li A substring of the dynamic buffer sequence's get area matches the regular+ * expression.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the dynamic buffer sequence's get area already contains data that matches+ * the regular expression, this asynchronous operation completes immediately.+ * The program must ensure that the stream performs no other read operations+ * (such as async_read, async_read_until, the stream's async_read_some+ * function, or any other composed operations that perform reads) until this+ * operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param expr The regular expression.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the dynamic buffer+ * // sequence's get area up to and including the+ * // substring that matches the regular expression.+ * // 0 if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the dynamic buffer+ * sequence may contain additional data beyond that which matched the regular+ * expression. An application will typically leave that data in the dynamic+ * buffer sequence for a subsequent async_read_until operation to examine.+ *+ * @par Example+ * To asynchronously read data into a @c std::string until a CR-LF sequence is+ * encountered:+ * @code std::string data;+ * ...+ * void handler(const asio::error_code& e, std::size_t size)+ * {+ * if (!e)+ * {+ * std::string line = data.substr(0, n);+ * data.erase(0, n);+ * ...+ * }+ * }+ * ...+ * asio::async_read_until(s, data,+ * boost::regex("\r\n"), handler); @endcode+ * After the @c async_read_until operation completes successfully, the string+ * @c data contains the data which matched the regular expression:+ * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode+ * The call to @c substr then extracts the data up to and including the match,+ * so that the string @c line contains:+ * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode+ * After the call to @c erase, the remaining data is left in the string @c data+ * as follows:+ * @code { 'd', 'e', ... } @endcode+ * This data may be the start of a new line, to be extracted by a subsequent+ * @c async_read_until operation.+ */+template <typename AsyncReadStream, typename DynamicBuffer_v2,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,+ const boost::regex& expr,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++#endif // defined(ASIO_HAS_BOOST_REGEX)+ // || defined(GENERATING_DOCUMENTATION)++/// Start an asynchronous operation to read data into a dynamic buffer sequence+/// until a function object indicates a match.+/**+ * This function is used to asynchronously read data into the specified dynamic+ * buffer sequence until a user-defined match condition function object, when+ * applied to the data contained in the dynamic buffer sequence, indicates a+ * successful match. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li The match condition function object returns a std::pair where the second+ * element evaluates to true.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_read_some function, and is known as a <em>composed operation</em>. If+ * the match condition function object already indicates a match, this+ * asynchronous operation completes immediately. The program must ensure that+ * the stream performs no other read operations (such as async_read,+ * async_read_until, the stream's async_read_some function, or any other+ * composed operations that perform reads) until this operation completes.+ *+ * @param s The stream from which the data is to be read. The type must support+ * the AsyncReadStream concept.+ *+ * @param buffers The dynamic buffer sequence 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 handler is called.+ *+ * @param match_condition The function object to be called to determine whether+ * a match exists. The signature of the function object must be:+ * @code pair<iterator, bool> match_condition(iterator begin, iterator end);+ * @endcode+ * where @c iterator represents the type:+ * @code buffers_iterator<typename DynamicBuffer_v2::const_buffers_type>+ * @endcode+ * The iterator parameters @c begin and @c end define the range of bytes to be+ * scanned to determine whether there is a match. The @c first member of the+ * return value is an iterator marking one-past-the-end of the bytes that have+ * been consumed by the match function. This iterator is used to calculate the+ * @c begin parameter for any subsequent invocation of the match condition. The+ * @c second member of the return value is true if a match has been found, false+ * otherwise.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // The number of bytes in the dynamic buffer sequence's+ * // get area that have been fully consumed by the match+ * // function. O if an error occurred.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ *+ * @note After a successful async_read_until operation, the dynamic buffer+ * sequence may contain additional data beyond that which matched the function+ * object. An application will typically leave that data in the dynamic buffer+ * sequence for a subsequent async_read_until operation to examine.+ *+ * @note The default implementation of the @c is_match_condition type trait+ * evaluates to true for function pointers and function objects with a+ * @c result_type typedef. It must be specialised for other user-defined+ * function objects.+ *+ * @par Examples+ * To asynchronously read data into a @c std::string until whitespace is+ * encountered:+ * @code typedef asio::buffers_iterator<+ * asio::const_buffers_1> iterator;+ *+ * std::pair<iterator, bool>+ * match_whitespace(iterator begin, iterator end)+ * {+ * iterator i = begin;+ * while (i != end)+ * if (std::isspace(*i++))+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ * ...+ * void handler(const asio::error_code& e, std::size_t size);+ * ...+ * std::string data;+ * asio::async_read_until(s, data, match_whitespace, handler);+ * @endcode+ *+ * To asynchronously read data into a @c std::string until a matching character+ * is found:+ * @code class match_char+ * {+ * public:+ * explicit match_char(char c) : c_(c) {}+ *+ * template <typename Iterator>+ * std::pair<Iterator, bool> operator()(+ * Iterator begin, Iterator end) const+ * {+ * Iterator i = begin;+ * while (i != end)+ * if (c_ == *i++)+ * return std::make_pair(i, true);+ * return std::make_pair(i, false);+ * }+ *+ * private:+ * char c_;+ * };+ *+ * namespace asio {+ * template <> struct is_match_condition<match_char>+ * : public boost::true_type {};+ * } // namespace asio+ * ...+ * void handler(const asio::error_code& e, std::size_t size);+ * ...+ * std::string data;+ * asio::async_read_until(s, data, match_char('a'), handler);+ * @endcode+ */+template <typename AsyncReadStream,+ typename DynamicBuffer_v2, typename MatchCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncReadStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers,+ MatchCondition match_condition,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncReadStream::executor_type),+ typename enable_if<+ is_match_condition<MatchCondition>::value+ && is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++#endif // !defined(ASIO_NO_EXTENSIONS)++/*@}*/++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/read_until.hpp"++#endif // ASIO_READ_UNTIL_HPP
+ link/modules/asio-standalone/asio/include/asio/redirect_error.hpp view
@@ -0,0 +1,66 @@+//+// redirect_error.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REDIRECT_ERROR_HPP+#define ASIO_REDIRECT_ERROR_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/error_code.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Completion token type used to specify that an error produced by an+/// asynchronous operation is captured to an error_code variable.+/**+ * The redirect_error_t class is used to indicate that any error_code produced+ * by an asynchronous operation is captured to a specified variable.+ */+template <typename CompletionToken>+class redirect_error_t+{+public:+ /// Constructor. + template <typename T>+ redirect_error_t(ASIO_MOVE_ARG(T) completion_token,+ asio::error_code& ec)+ : token_(ASIO_MOVE_CAST(T)(completion_token)),+ ec_(ec)+ {+ }++//private:+ CompletionToken token_;+ asio::error_code& ec_;+};++/// Create a completion token to capture error_code values to a variable.+template <typename CompletionToken>+inline redirect_error_t<typename decay<CompletionToken>::type> redirect_error(+ ASIO_MOVE_ARG(CompletionToken) completion_token,+ asio::error_code& ec)+{+ return redirect_error_t<typename decay<CompletionToken>::type>(+ ASIO_MOVE_CAST(CompletionToken)(completion_token), ec);+}++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/redirect_error.hpp"++#endif // ASIO_REDIRECT_ERROR_HPP
+ link/modules/asio-standalone/asio/include/asio/require.hpp view
@@ -0,0 +1,524 @@+//+// require.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REQUIRE_HPP+#define ASIO_REQUIRE_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/is_applicable_property.hpp"+#include "asio/traits/require_member.hpp"+#include "asio/traits/require_free.hpp"+#include "asio/traits/static_require.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {++/// A customisation point that applies a concept-preserving property to an+/// object.+/**+ * The name <tt>require</tt> denotes a customisation point object. The+ * expression <tt>asio::require(E, P0, Pn...)</tt> for some+ * subexpressions <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt>+ * represents <tt>N</tt> subexpressions (where <tt>N</tt> is 0 or more, and with+ * types <tt>T = decay_t<decltype(E)></tt> and <tt>Prop0 =+ * decay_t<decltype(P0)></tt>) is expression-equivalent to:+ *+ * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_requirable</tt> is+ * not a well-formed constant expression with value <tt>true</tt>,+ * <tt>asio::require(E, P0, Pn...)</tt> is ill-formed.+ *+ * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression+ * <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a+ * well-formed constant expression with value <tt>true</tt>.+ *+ * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression+ * <tt>(E).require(P0)</tt> is a valid expression.+ *+ * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression+ * <tt>require(E, P0)</tt> is a valid expression with overload resolution+ * performed in a context that does not include the declaration of the+ * <tt>require</tt> customization point object.+ *+ * @li Otherwise,+ * <tt>asio::require(asio::require(E, P0), Pn...)</tt>+ * if <tt>N > 0</tt> and the expression+ * <tt>asio::require(asio::require(E, P0), Pn...)</tt>+ * is a valid expression.+ *+ * @li Otherwise, <tt>asio::require(E, P0, Pn...)</tt> is ill-formed.+ */+inline constexpr unspecified require = unspecified;++/// A type trait that determines whether a @c require expression is well-formed.+/**+ * Class template @c can_require is a trait that is derived from+ * @c true_type if the expression <tt>asio::require(std::declval<T>(),+ * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type.+ */+template <typename T, typename... Properties>+struct can_require :+ integral_constant<bool, automatically_determined>+{+};++/// A type trait that determines whether a @c require expression will not throw.+/**+ * Class template @c is_nothrow_require is a trait that is derived from+ * @c true_type if the expression <tt>asio::require(std::declval<T>(),+ * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type.+ */+template <typename T, typename... Properties>+struct is_nothrow_require :+ integral_constant<bool, automatically_determined>+{+};++/// A type trait that determines the result type of a @c require expression.+/**+ * Class template @c require_result is a trait that determines the result+ * type of the expression <tt>asio::require(std::declval<T>(),+ * std::declval<Properties>()...)</tt>.+ */+template <typename T, typename... Properties>+struct require_result+{+ /// The result of the @c require expression.+ typedef automatically_determined type;+};++} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_require_fn {++using asio::decay;+using asio::declval;+using asio::enable_if;+using asio::is_applicable_property;+using asio::traits::require_free;+using asio::traits::require_member;+using asio::traits::static_require;++void require();++enum overload_type+{+ identity,+ call_member,+ call_free,+ two_props,+ n_props,+ ill_formed+};++template <typename T, typename Properties, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_requirable+ &&+ static_require<T, Property>::is_valid+ )+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);++#if defined(ASIO_HAS_MOVE)+ typedef ASIO_MOVE_ARG(T) result_type;+#else // defined(ASIO_HAS_MOVE)+ typedef ASIO_MOVE_ARG(typename decay<T>::type) result_type;+#endif // defined(ASIO_HAS_MOVE)+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_requirable+ &&+ !static_require<T, Property>::is_valid+ &&+ require_member<T, Property>::is_valid+ )+ >::type> :+ require_member<T, Property>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_requirable+ &&+ !static_require<T, Property>::is_valid+ &&+ !require_member<T, Property>::is_valid+ &&+ require_free<T, Property>::is_valid+ )+ >::type> :+ require_free<T, Property>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++template <typename T, typename P0, typename P1>+struct call_traits<T, void(P0, P1),+ typename enable_if<+ call_traits<T, void(P0)>::overload != ill_formed+ &&+ call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1)+ >::overload != ill_formed+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = two_props);++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (+ call_traits<T, void(P0)>::is_noexcept+ &&+ call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1)+ >::is_noexcept+ ));++ typedef typename decay<+ typename call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1)+ >::result_type+ >::type result_type;+};++template <typename T, typename P0, typename P1, typename ASIO_ELLIPSIS PN>+struct call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS),+ typename enable_if<+ call_traits<T, void(P0)>::overload != ill_formed+ &&+ call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1, PN ASIO_ELLIPSIS)+ >::overload != ill_formed+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = n_props);++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (+ call_traits<T, void(P0)>::is_noexcept+ &&+ call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1, PN ASIO_ELLIPSIS)+ >::is_noexcept+ ));++ typedef typename decay<+ typename call_traits<+ typename call_traits<T, void(P0)>::result_type,+ void(P1, PN ASIO_ELLIPSIS)+ >::result_type+ >::type result_type;+};++struct impl+{+ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == identity,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property)) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(T)(t);+ }++ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == call_member,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property) p) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(T)(t).require(+ ASIO_MOVE_CAST(Property)(p));+ }++ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == call_free,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property) p) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return require(+ ASIO_MOVE_CAST(T)(t),+ ASIO_MOVE_CAST(Property)(p));+ }++ template <typename T, typename P0, typename P1>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(P0, P1)>::overload == two_props,+ typename call_traits<T, void(P0, P1)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(P0) p0,+ ASIO_MOVE_ARG(P1) p1) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(P0, P1)>::is_noexcept))+ {+ return (*this)(+ (*this)(+ ASIO_MOVE_CAST(T)(t),+ ASIO_MOVE_CAST(P0)(p0)),+ ASIO_MOVE_CAST(P1)(p1));+ }++ template <typename T, typename P0, typename P1,+ typename ASIO_ELLIPSIS PN>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::overload == n_props,+ typename call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(P0) p0,+ ASIO_MOVE_ARG(P1) p1,+ ASIO_MOVE_ARG(PN) ASIO_ELLIPSIS pn) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(P0, P1, PN ASIO_ELLIPSIS)>::is_noexcept))+ {+ return (*this)(+ (*this)(+ ASIO_MOVE_CAST(T)(t),+ ASIO_MOVE_CAST(P0)(p0)),+ ASIO_MOVE_CAST(P1)(p1),+ ASIO_MOVE_CAST(PN)(pn) ASIO_ELLIPSIS);+ }+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_require_fn+namespace asio {+namespace {++static ASIO_CONSTEXPR const asio_require_fn::impl&+ require = asio_require_fn::static_instance<>::instance;++} // namespace++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename... Properties>+struct can_require :+ integral_constant<bool,+ asio_require_fn::call_traits<T, void(Properties...)>::overload+ != asio_require_fn::ill_formed>+{+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename P0 = void,+ typename P1 = void, typename P2 = void>+struct can_require :+ integral_constant<bool,+ asio_require_fn::call_traits<T, void(P0, P1, P2)>::overload+ != asio_require_fn::ill_formed>+{+};++template <typename T, typename P0, typename P1>+struct can_require<T, P0, P1> :+ integral_constant<bool,+ asio_require_fn::call_traits<T, void(P0, P1)>::overload+ != asio_require_fn::ill_formed>+{+};++template <typename T, typename P0>+struct can_require<T, P0> :+ integral_constant<bool,+ asio_require_fn::call_traits<T, void(P0)>::overload+ != asio_require_fn::ill_formed>+{+};++template <typename T>+struct can_require<T> :+ false_type+{+};++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename ASIO_ELLIPSIS Properties>+constexpr bool can_require_v+ = can_require<T, Properties ASIO_ELLIPSIS>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename... Properties>+struct is_nothrow_require :+ integral_constant<bool,+ asio_require_fn::call_traits<T, void(Properties...)>::is_noexcept>+{+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename P0 = void,+ typename P1 = void, typename P2 = void>+struct is_nothrow_require :+ integral_constant<bool,+ asio_require_fn::call_traits<T, void(P0, P1, P2)>::is_noexcept>+{+};++template <typename T, typename P0, typename P1>+struct is_nothrow_require<T, P0, P1> :+ integral_constant<bool,+ asio_require_fn::call_traits<T, void(P0, P1)>::is_noexcept>+{+};++template <typename T, typename P0>+struct is_nothrow_require<T, P0> :+ integral_constant<bool,+ asio_require_fn::call_traits<T, void(P0)>::is_noexcept>+{+};++template <typename T>+struct is_nothrow_require<T> :+ false_type+{+};++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename ASIO_ELLIPSIS Properties>+constexpr bool is_nothrow_require_v+ = is_nothrow_require<T, Properties ASIO_ELLIPSIS>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename... Properties>+struct require_result+{+ typedef typename asio_require_fn::call_traits<+ T, void(Properties...)>::result_type type;+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename P0 = void,+ typename P1 = void, typename P2 = void>+struct require_result+{+ typedef typename asio_require_fn::call_traits<+ T, void(P0, P1, P2)>::result_type type;+};++template <typename T, typename P0, typename P1>+struct require_result<T, P0, P1>+{+ typedef typename asio_require_fn::call_traits<+ T, void(P0, P1)>::result_type type;+};++template <typename T, typename P0>+struct require_result<T, P0>+{+ typedef typename asio_require_fn::call_traits<+ T, void(P0)>::result_type type;+};++template <typename T>+struct require_result<T>+{+};++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_REQUIRE_HPP
+ link/modules/asio-standalone/asio/include/asio/require_concept.hpp view
@@ -0,0 +1,310 @@+//+// require_concept.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_REQUIRE_CONCEPT_HPP+#define ASIO_REQUIRE_CONCEPT_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/is_applicable_property.hpp"+#include "asio/traits/require_concept_member.hpp"+#include "asio/traits/require_concept_free.hpp"+#include "asio/traits/static_require_concept.hpp"++#include "asio/detail/push_options.hpp"++#if defined(GENERATING_DOCUMENTATION)++namespace asio {++/// A customisation point that applies a concept-enforcing property to an+/// object.+/**+ * The name <tt>require_concept</tt> denotes a customization point object. The+ * expression <tt>asio::require_concept(E, P)</tt> for some+ * subexpressions <tt>E</tt> and <tt>P</tt> (with types <tt>T =+ * decay_t<decltype(E)></tt> and <tt>Prop = decay_t<decltype(P)></tt>) is+ * expression-equivalent to:+ *+ * @li If <tt>is_applicable_property_v<T, Prop> &&+ * Prop::is_requirable_concept</tt> is not a well-formed constant expression+ * with value <tt>true</tt>, <tt>asio::require_concept(E, P)</tt> is+ * ill-formed.+ *+ * @li Otherwise, <tt>E</tt> if the expression <tt>Prop::template+ * static_query_v<T> == Prop::value()</tt> is a well-formed constant+ * expression with value <tt>true</tt>.+ *+ * @li Otherwise, <tt>(E).require_concept(P)</tt> if the expression+ * <tt>(E).require_concept(P)</tt> is well-formed.+ *+ * @li Otherwise, <tt>require_concept(E, P)</tt> if the expression+ * <tt>require_concept(E, P)</tt> is a valid expression with overload+ * resolution performed in a context that does not include the declaration+ * of the <tt>require_concept</tt> customization point object.+ *+ * @li Otherwise, <tt>asio::require_concept(E, P)</tt> is ill-formed.+ */+inline constexpr unspecified require_concept = unspecified;++/// A type trait that determines whether a @c require_concept expression is+/// well-formed.+/**+ * Class template @c can_require_concept is a trait that is derived from+ * @c true_type if the expression+ * <tt>asio::require_concept(std::declval<T>(),+ * std::declval<Property>())</tt> is well formed; otherwise @c false_type.+ */+template <typename T, typename Property>+struct can_require_concept :+ integral_constant<bool, automatically_determined>+{+};++/// A type trait that determines whether a @c require_concept expression will+/// not throw.+/**+ * Class template @c is_nothrow_require_concept is a trait that is derived from+ * @c true_type if the expression+ * <tt>asio::require_concept(std::declval<T>(),+ * std::declval<Property>())</tt> is @c noexcept; otherwise @c false_type.+ */+template <typename T, typename Property>+struct is_nothrow_require_concept :+ integral_constant<bool, automatically_determined>+{+};++/// A type trait that determines the result type of a @c require_concept+/// expression.+/**+ * Class template @c require_concept_result is a trait that determines the+ * result type of the expression+ * <tt>asio::require_concept(std::declval<T>(),+ * std::declval<Property>())</tt>.+ */+template <typename T, typename Property>+struct require_concept_result+{+ /// The result of the @c require_concept expression.+ typedef automatically_determined type;+};++} // namespace asio++#else // defined(GENERATING_DOCUMENTATION)++namespace asio_require_concept_fn {++using asio::decay;+using asio::declval;+using asio::enable_if;+using asio::is_applicable_property;+using asio::traits::require_concept_free;+using asio::traits::require_concept_member;+using asio::traits::static_require_concept;++void require_concept();++enum overload_type+{+ identity,+ call_member,+ call_free,+ ill_formed+};++template <typename T, typename Properties, typename = void>+struct call_traits+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_requirable_concept+ &&+ static_require_concept<T, Property>::is_valid+ )+ >::type>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = identity);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef ASIO_MOVE_ARG(T) result_type;+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_requirable_concept+ &&+ !static_require_concept<T, Property>::is_valid+ &&+ require_concept_member<T, Property>::is_valid+ )+ >::type> :+ require_concept_member<T, Property>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);+};++template <typename T, typename Property>+struct call_traits<T, void(Property),+ typename enable_if<+ (+ is_applicable_property<+ typename decay<T>::type,+ typename decay<Property>::type+ >::value+ &&+ decay<Property>::type::is_requirable_concept+ &&+ !static_require_concept<T, Property>::is_valid+ &&+ !require_concept_member<T, Property>::is_valid+ &&+ require_concept_free<T, Property>::is_valid+ )+ >::type> :+ require_concept_free<T, Property>+{+ ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);+};++struct impl+{+ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == identity,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property)) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(T)(t);+ }++ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == call_member,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property) p) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return ASIO_MOVE_CAST(T)(t).require_concept(+ ASIO_MOVE_CAST(Property)(p));+ }++ template <typename T, typename Property>+ ASIO_NODISCARD ASIO_CONSTEXPR typename enable_if<+ call_traits<T, void(Property)>::overload == call_free,+ typename call_traits<T, void(Property)>::result_type+ >::type+ operator()(+ ASIO_MOVE_ARG(T) t,+ ASIO_MOVE_ARG(Property) p) const+ ASIO_NOEXCEPT_IF((+ call_traits<T, void(Property)>::is_noexcept))+ {+ return require_concept(+ ASIO_MOVE_CAST(T)(t),+ ASIO_MOVE_CAST(Property)(p));+ }+};++template <typename T = impl>+struct static_instance+{+ static const T instance;+};++template <typename T>+const T static_instance<T>::instance = {};++} // namespace asio_require_concept_fn+namespace asio {+namespace {++static ASIO_CONSTEXPR const asio_require_concept_fn::impl&+ require_concept = asio_require_concept_fn::static_instance<>::instance;++} // namespace++template <typename T, typename Property>+struct can_require_concept :+ integral_constant<bool,+ asio_require_concept_fn::call_traits<T, void(Property)>::overload !=+ asio_require_concept_fn::ill_formed>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename Property>+constexpr bool can_require_concept_v+ = can_require_concept<T, Property>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename Property>+struct is_nothrow_require_concept :+ integral_constant<bool,+ asio_require_concept_fn::call_traits<T, void(Property)>::is_noexcept>+{+};++#if defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename Property>+constexpr bool is_nothrow_require_concept_v+ = is_nothrow_require_concept<T, Property>::value;++#endif // defined(ASIO_HAS_VARIABLE_TEMPLATES)++template <typename T, typename Property>+struct require_concept_result+{+ typedef typename asio_require_concept_fn::call_traits<+ T, void(Property)>::result_type type;+};++} // namespace asio++#endif // defined(GENERATING_DOCUMENTATION)++#include "asio/detail/pop_options.hpp"++#endif // ASIO_REQUIRE_CONCEPT_HPP
+ link/modules/asio-standalone/asio/include/asio/serial_port.hpp view
@@ -0,0 +1,36 @@+//+// serial_port.hpp+// ~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_SERIAL_PORT_HPP+#define ASIO_SERIAL_PORT_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_SERIAL_PORT) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/basic_serial_port.hpp"++namespace asio {++/// Typedef for the typical usage of a serial port.+typedef basic_serial_port<> serial_port;++} // namespace asio++#endif // defined(ASIO_HAS_SERIAL_PORT)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_SERIAL_PORT_HPP
+ link/modules/asio-standalone/asio/include/asio/serial_port_base.hpp view
@@ -0,0 +1,167 @@+//+// serial_port_base.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_SERIAL_PORT_BASE_HPP+#define ASIO_SERIAL_PORT_BASE_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_SERIAL_PORT) \+ || defined(GENERATING_DOCUMENTATION)++#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)+# include <termios.h>+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)++#include "asio/detail/socket_types.hpp"+#include "asio/error_code.hpp"++#if defined(GENERATING_DOCUMENTATION)+# define ASIO_OPTION_STORAGE implementation_defined+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)+# define ASIO_OPTION_STORAGE DCB+#else+# define ASIO_OPTION_STORAGE termios+#endif++#include "asio/detail/push_options.hpp"++namespace asio {++/// The serial_port_base class is used as a base for the basic_serial_port class+/// template so that we have a common place to define the serial port options.+class serial_port_base+{+public:+ /// Serial port option to permit changing the baud rate.+ /**+ * Implements changing the baud rate for a given serial port.+ */+ class baud_rate+ {+ public:+ explicit baud_rate(unsigned int rate = 0);+ unsigned int value() const;+ ASIO_DECL ASIO_SYNC_OP_VOID store(+ ASIO_OPTION_STORAGE& storage,+ asio::error_code& ec) const;+ ASIO_DECL ASIO_SYNC_OP_VOID load(+ const ASIO_OPTION_STORAGE& storage,+ asio::error_code& ec);+ private:+ unsigned int value_;+ };++ /// Serial port option to permit changing the flow control.+ /**+ * Implements changing the flow control for a given serial port.+ */+ class flow_control+ {+ public:+ enum type { none, software, hardware };+ ASIO_DECL explicit flow_control(type t = none);+ type value() const;+ ASIO_DECL ASIO_SYNC_OP_VOID store(+ ASIO_OPTION_STORAGE& storage,+ asio::error_code& ec) const;+ ASIO_DECL ASIO_SYNC_OP_VOID load(+ const ASIO_OPTION_STORAGE& storage,+ asio::error_code& ec);+ private:+ type value_;+ };++ /// Serial port option to permit changing the parity.+ /**+ * Implements changing the parity for a given serial port.+ */+ class parity+ {+ public:+ enum type { none, odd, even };+ ASIO_DECL explicit parity(type t = none);+ type value() const;+ ASIO_DECL ASIO_SYNC_OP_VOID store(+ ASIO_OPTION_STORAGE& storage,+ asio::error_code& ec) const;+ ASIO_DECL ASIO_SYNC_OP_VOID load(+ const ASIO_OPTION_STORAGE& storage,+ asio::error_code& ec);+ private:+ type value_;+ };++ /// Serial port option to permit changing the number of stop bits.+ /**+ * Implements changing the number of stop bits for a given serial port.+ */+ class stop_bits+ {+ public:+ enum type { one, onepointfive, two };+ ASIO_DECL explicit stop_bits(type t = one);+ type value() const;+ ASIO_DECL ASIO_SYNC_OP_VOID store(+ ASIO_OPTION_STORAGE& storage,+ asio::error_code& ec) const;+ ASIO_DECL ASIO_SYNC_OP_VOID load(+ const ASIO_OPTION_STORAGE& storage,+ asio::error_code& ec);+ private:+ type value_;+ };++ /// Serial port option to permit changing the character size.+ /**+ * Implements changing the character size for a given serial port.+ */+ class character_size+ {+ public:+ ASIO_DECL explicit character_size(unsigned int t = 8);+ unsigned int value() const;+ ASIO_DECL ASIO_SYNC_OP_VOID store(+ ASIO_OPTION_STORAGE& storage,+ asio::error_code& ec) const;+ ASIO_DECL ASIO_SYNC_OP_VOID load(+ const ASIO_OPTION_STORAGE& storage,+ asio::error_code& ec);+ private:+ unsigned int value_;+ };++protected:+ /// Protected destructor to prevent deletion through this type.+ ~serial_port_base()+ {+ }+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#undef ASIO_OPTION_STORAGE++#include "asio/impl/serial_port_base.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/impl/serial_port_base.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // defined(ASIO_HAS_SERIAL_PORT)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_SERIAL_PORT_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/signal_set.hpp view
@@ -0,0 +1,28 @@+//+// signal_set.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SIGNAL_SET_HPP+#define ASIO_SIGNAL_SET_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/basic_signal_set.hpp"++namespace asio {++/// Typedef for the typical usage of a signal set.+typedef basic_signal_set<> signal_set;++} // namespace asio++#endif // ASIO_SIGNAL_SET_HPP
+ link/modules/asio-standalone/asio/include/asio/socket_base.hpp view
@@ -0,0 +1,559 @@+//+// socket_base.hpp+// ~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SOCKET_BASE_HPP+#define ASIO_SOCKET_BASE_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/io_control.hpp"+#include "asio/detail/socket_option.hpp"+#include "asio/detail/socket_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// The socket_base class is used as a base for the basic_stream_socket and+/// basic_datagram_socket class templates so that we have a common place to+/// define the shutdown_type and enum.+class socket_base+{+public:+ /// Different ways a socket may be shutdown.+ enum shutdown_type+ {+#if defined(GENERATING_DOCUMENTATION)+ /// Shutdown the receive side of the socket.+ shutdown_receive = implementation_defined,++ /// Shutdown the send side of the socket.+ shutdown_send = implementation_defined,++ /// Shutdown both send and receive on the socket.+ shutdown_both = implementation_defined+#else+ shutdown_receive = ASIO_OS_DEF(SHUT_RD),+ shutdown_send = ASIO_OS_DEF(SHUT_WR),+ shutdown_both = ASIO_OS_DEF(SHUT_RDWR)+#endif+ };++ /// Bitmask type for flags that can be passed to send and receive operations.+ typedef int message_flags;++#if defined(GENERATING_DOCUMENTATION)+ /// Peek at incoming data without removing it from the input queue.+ static const int message_peek = implementation_defined;++ /// Process out-of-band data.+ static const int message_out_of_band = implementation_defined;++ /// Specify that the data should not be subject to routing.+ static const int message_do_not_route = implementation_defined;++ /// Specifies that the data marks the end of a record.+ static const int message_end_of_record = implementation_defined;+#else+ ASIO_STATIC_CONSTANT(int,+ message_peek = ASIO_OS_DEF(MSG_PEEK));+ ASIO_STATIC_CONSTANT(int,+ message_out_of_band = ASIO_OS_DEF(MSG_OOB));+ ASIO_STATIC_CONSTANT(int,+ message_do_not_route = ASIO_OS_DEF(MSG_DONTROUTE));+ ASIO_STATIC_CONSTANT(int,+ message_end_of_record = ASIO_OS_DEF(MSG_EOR));+#endif++ /// Wait types.+ /**+ * For use with basic_socket::wait() and basic_socket::async_wait().+ */+ enum wait_type+ {+ /// Wait for a socket to become ready to read.+ wait_read,++ /// Wait for a socket to become ready to write.+ wait_write,++ /// Wait for a socket to have error conditions pending.+ wait_error+ };++ /// Socket option to permit sending of broadcast messages.+ /**+ * Implements the SOL_SOCKET/SO_BROADCAST socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::socket_base::broadcast option(true);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::socket_base::broadcast option;+ * socket.get_option(option);+ * bool is_set = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Boolean_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined broadcast;+#else+ typedef asio::detail::socket_option::boolean<+ ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_BROADCAST)>+ broadcast;+#endif++ /// Socket option to enable socket-level debugging.+ /**+ * Implements the SOL_SOCKET/SO_DEBUG socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::debug option(true);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::debug option;+ * socket.get_option(option);+ * bool is_set = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Boolean_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined debug;+#else+ typedef asio::detail::socket_option::boolean<+ ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_DEBUG)> debug;+#endif++ /// Socket option to prevent routing, use local interfaces only.+ /**+ * Implements the SOL_SOCKET/SO_DONTROUTE socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::socket_base::do_not_route option(true);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::udp::socket socket(my_context);+ * ...+ * asio::socket_base::do_not_route option;+ * socket.get_option(option);+ * bool is_set = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Boolean_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined do_not_route;+#else+ typedef asio::detail::socket_option::boolean<+ ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_DONTROUTE)>+ do_not_route;+#endif++ /// Socket option to send keep-alives.+ /**+ * Implements the SOL_SOCKET/SO_KEEPALIVE socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::keep_alive option(true);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::keep_alive option;+ * socket.get_option(option);+ * bool is_set = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Boolean_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined keep_alive;+#else+ typedef asio::detail::socket_option::boolean<+ ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_KEEPALIVE)> keep_alive;+#endif++ /// Socket option for the send buffer size of a socket.+ /**+ * Implements the SOL_SOCKET/SO_SNDBUF socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::send_buffer_size option(8192);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::send_buffer_size option;+ * socket.get_option(option);+ * int size = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Integer_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined send_buffer_size;+#else+ typedef asio::detail::socket_option::integer<+ ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_SNDBUF)>+ send_buffer_size;+#endif++ /// Socket option for the send low watermark.+ /**+ * Implements the SOL_SOCKET/SO_SNDLOWAT socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::send_low_watermark option(1024);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::send_low_watermark option;+ * socket.get_option(option);+ * int size = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Integer_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined send_low_watermark;+#else+ typedef asio::detail::socket_option::integer<+ ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_SNDLOWAT)>+ send_low_watermark;+#endif++ /// Socket option for the receive buffer size of a socket.+ /**+ * Implements the SOL_SOCKET/SO_RCVBUF socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::receive_buffer_size option(8192);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::receive_buffer_size option;+ * socket.get_option(option);+ * int size = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Integer_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined receive_buffer_size;+#else+ typedef asio::detail::socket_option::integer<+ ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_RCVBUF)>+ receive_buffer_size;+#endif++ /// Socket option for the receive low watermark.+ /**+ * Implements the SOL_SOCKET/SO_RCVLOWAT socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::receive_low_watermark option(1024);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::receive_low_watermark option;+ * socket.get_option(option);+ * int size = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Integer_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined receive_low_watermark;+#else+ typedef asio::detail::socket_option::integer<+ ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_RCVLOWAT)>+ receive_low_watermark;+#endif++ /// Socket option to allow the socket to be bound to an address that is+ /// already in use.+ /**+ * Implements the SOL_SOCKET/SO_REUSEADDR socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::socket_base::reuse_address option(true);+ * acceptor.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::socket_base::reuse_address option;+ * acceptor.get_option(option);+ * bool is_set = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Boolean_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined reuse_address;+#else+ typedef asio::detail::socket_option::boolean<+ ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_REUSEADDR)>+ reuse_address;+#endif++ /// Socket option to specify whether the socket lingers on close if unsent+ /// data is present.+ /**+ * Implements the SOL_SOCKET/SO_LINGER socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::linger option(true, 30);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::linger option;+ * socket.get_option(option);+ * bool is_set = option.enabled();+ * unsigned short timeout = option.timeout();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Linger_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined linger;+#else+ typedef asio::detail::socket_option::linger<+ ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_LINGER)>+ linger;+#endif++ /// Socket option for putting received out-of-band data inline.+ /**+ * Implements the SOL_SOCKET/SO_OOBINLINE socket option.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::out_of_band_inline option(true);+ * socket.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::out_of_band_inline option;+ * socket.get_option(option);+ * bool value = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Boolean_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined out_of_band_inline;+#else+ typedef asio::detail::socket_option::boolean<+ ASIO_OS_DEF(SOL_SOCKET), ASIO_OS_DEF(SO_OOBINLINE)>+ out_of_band_inline;+#endif++ /// Socket option to report aborted connections on accept.+ /**+ * Implements a custom socket option that determines whether or not an accept+ * operation is permitted to fail with asio::error::connection_aborted.+ * By default the option is false.+ *+ * @par Examples+ * Setting the option:+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::socket_base::enable_connection_aborted option(true);+ * acceptor.set_option(option);+ * @endcode+ *+ * @par+ * Getting the current option value:+ * @code+ * asio::ip::tcp::acceptor acceptor(my_context);+ * ...+ * asio::socket_base::enable_connection_aborted option;+ * acceptor.get_option(option);+ * bool is_set = option.value();+ * @endcode+ *+ * @par Concepts:+ * Socket_Option, Boolean_Socket_Option.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined enable_connection_aborted;+#else+ typedef asio::detail::socket_option::boolean<+ asio::detail::custom_socket_option_level,+ asio::detail::enable_connection_aborted_option>+ enable_connection_aborted;+#endif++ /// IO control command to get the amount of data that can be read without+ /// blocking.+ /**+ * Implements the FIONREAD IO control command.+ *+ * @par Example+ * @code+ * asio::ip::tcp::socket socket(my_context);+ * ...+ * asio::socket_base::bytes_readable command(true);+ * socket.io_control(command);+ * std::size_t bytes_readable = command.get();+ * @endcode+ *+ * @par Concepts:+ * IO_Control_Command, Size_IO_Control_Command.+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined bytes_readable;+#else+ typedef asio::detail::io_control::bytes_readable bytes_readable;+#endif++ /// The maximum length of the queue of pending incoming connections.+#if defined(GENERATING_DOCUMENTATION)+ static const int max_listen_connections = implementation_defined;+#else+ ASIO_STATIC_CONSTANT(int, max_listen_connections+ = ASIO_OS_DEF(SOMAXCONN));+#endif++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use max_listen_connections.) The maximum length of the queue+ /// of pending incoming connections.+#if defined(GENERATING_DOCUMENTATION)+ static const int max_connections = implementation_defined;+#else+ ASIO_STATIC_CONSTANT(int, max_connections+ = ASIO_OS_DEF(SOMAXCONN));+#endif+#endif // !defined(ASIO_NO_DEPRECATED)++protected:+ /// Protected destructor to prevent deletion through this type.+ ~socket_base()+ {+ }+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SOCKET_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/spawn.hpp view
@@ -0,0 +1,344 @@+//+// spawn.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SPAWN_HPP+#define ASIO_SPAWN_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <boost/coroutine/all.hpp>+#include "asio/any_io_executor.hpp"+#include "asio/bind_executor.hpp"+#include "asio/detail/memory.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/detail/wrapped_handler.hpp"+#include "asio/io_context.hpp"+#include "asio/is_executor.hpp"+#include "asio/strand.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Context object the represents the currently executing coroutine.+/**+ * The basic_yield_context class is used to represent the currently executing+ * stackful coroutine. A basic_yield_context may be passed as a handler to an+ * asynchronous operation. For example:+ *+ * @code template <typename Handler>+ * void my_coroutine(basic_yield_context<Handler> yield)+ * {+ * ...+ * std::size_t n = my_socket.async_read_some(buffer, yield);+ * ...+ * } @endcode+ *+ * The initiating function (async_read_some in the above example) suspends the+ * current coroutine. The coroutine is resumed when the asynchronous operation+ * completes, and the result of the operation is returned.+ */+template <typename Handler>+class basic_yield_context+{+public:+ /// The coroutine callee type, used by the implementation.+ /**+ * When using Boost.Coroutine v1, this type is:+ * @code typename coroutine<void()> @endcode+ * When using Boost.Coroutine v2 (unidirectional coroutines), this type is:+ * @code push_coroutine<void> @endcode+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined callee_type;+#elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2)+ typedef boost::coroutines::push_coroutine<void> callee_type;+#else+ typedef boost::coroutines::coroutine<void()> callee_type;+#endif+ + /// The coroutine caller type, used by the implementation.+ /**+ * When using Boost.Coroutine v1, this type is:+ * @code typename coroutine<void()>::caller_type @endcode+ * When using Boost.Coroutine v2 (unidirectional coroutines), this type is:+ * @code pull_coroutine<void> @endcode+ */+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined caller_type;+#elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2)+ typedef boost::coroutines::pull_coroutine<void> caller_type;+#else+ typedef boost::coroutines::coroutine<void()>::caller_type caller_type;+#endif++ /// Construct a yield context to represent the specified coroutine.+ /**+ * Most applications do not need to use this constructor. Instead, the+ * spawn() function passes a yield context as an argument to the coroutine+ * function.+ */+ basic_yield_context(+ const detail::weak_ptr<callee_type>& coro,+ caller_type& ca, Handler& handler)+ : coro_(coro),+ ca_(ca),+ handler_(handler),+ ec_(0)+ {+ }++ /// Construct a yield context from another yield context type.+ /**+ * Requires that OtherHandler be convertible to Handler.+ */+ template <typename OtherHandler>+ basic_yield_context(const basic_yield_context<OtherHandler>& other)+ : coro_(other.coro_),+ ca_(other.ca_),+ handler_(other.handler_),+ ec_(other.ec_)+ {+ }++ /// Return a yield context that sets the specified error_code.+ /**+ * By default, when a yield context is used with an asynchronous operation, a+ * non-success error_code is converted to system_error and thrown. This+ * operator may be used to specify an error_code object that should instead be+ * set with the asynchronous operation's result. For example:+ *+ * @code template <typename Handler>+ * void my_coroutine(basic_yield_context<Handler> yield)+ * {+ * ...+ * std::size_t n = my_socket.async_read_some(buffer, yield[ec]);+ * if (ec)+ * {+ * // An error occurred.+ * }+ * ...+ * } @endcode+ */+ basic_yield_context operator[](asio::error_code& ec) const+ {+ basic_yield_context tmp(*this);+ tmp.ec_ = &ec;+ return tmp;+ }++#if defined(GENERATING_DOCUMENTATION)+private:+#endif // defined(GENERATING_DOCUMENTATION)+ detail::weak_ptr<callee_type> coro_;+ caller_type& ca_;+ Handler handler_;+ asio::error_code* ec_;+};++#if defined(GENERATING_DOCUMENTATION)+/// Context object that represents the currently executing coroutine.+typedef basic_yield_context<unspecified> yield_context;+#else // defined(GENERATING_DOCUMENTATION)+typedef basic_yield_context<+ executor_binder<void(*)(), any_io_executor> > yield_context;+#endif // defined(GENERATING_DOCUMENTATION)++/**+ * @defgroup spawn asio::spawn+ *+ * @brief Start a new stackful coroutine.+ *+ * The spawn() function is a high-level wrapper over the Boost.Coroutine+ * library. This function enables programs to implement asynchronous logic in a+ * synchronous manner, as illustrated by the following example:+ *+ * @code asio::spawn(my_strand, do_echo);+ *+ * // ...+ *+ * void do_echo(asio::yield_context yield)+ * {+ * try+ * {+ * char data[128];+ * for (;;)+ * {+ * std::size_t length =+ * my_socket.async_read_some(+ * asio::buffer(data), yield);+ *+ * asio::async_write(my_socket,+ * asio::buffer(data, length), yield);+ * }+ * }+ * catch (std::exception& e)+ * {+ * // ...+ * }+ * } @endcode+ */+/*@{*/++/// Start a new stackful coroutine, calling the specified handler when it+/// completes.+/**+ * This function is used to launch a new coroutine.+ *+ * @param function The coroutine function. The function must have the signature:+ * @code void function(basic_yield_context<Handler> yield); @endcode+ *+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.+ */+template <typename Function>+void spawn(ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes+ = boost::coroutines::attributes());++/// Start a new stackful coroutine, calling the specified handler when it+/// completes.+/**+ * This function is used to launch a new coroutine.+ *+ * @param handler A handler to be called when the coroutine exits. More+ * importantly, the handler provides an execution context (via the the handler+ * invocation hook) for the coroutine. The handler must have the signature:+ * @code void handler(); @endcode+ *+ * @param function The coroutine function. The function must have the signature:+ * @code void function(basic_yield_context<Handler> yield); @endcode+ *+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.+ */+template <typename Handler, typename Function>+void spawn(ASIO_MOVE_ARG(Handler) handler,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes+ = boost::coroutines::attributes(),+ typename enable_if<+ !is_executor<typename decay<Handler>::type>::value &&+ !execution::is_executor<typename decay<Handler>::type>::value &&+ !is_convertible<Handler&, execution_context&>::value>::type* = 0);++/// Start a new stackful coroutine, inheriting the execution context of another.+/**+ * This function is used to launch a new coroutine.+ *+ * @param ctx Identifies the current coroutine as a parent of the new+ * coroutine. This specifies that the new coroutine should inherit the+ * execution context of the parent. For example, if the parent coroutine is+ * executing in a particular strand, then the new coroutine will execute in the+ * same strand.+ *+ * @param function The coroutine function. The function must have the signature:+ * @code void function(basic_yield_context<Handler> yield); @endcode+ *+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.+ */+template <typename Handler, typename Function>+void spawn(basic_yield_context<Handler> ctx,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes+ = boost::coroutines::attributes());++/// Start a new stackful coroutine that executes on a given executor.+/**+ * This function is used to launch a new coroutine.+ *+ * @param ex Identifies the executor that will run the coroutine. The new+ * coroutine is implicitly given its own strand within this executor.+ *+ * @param function The coroutine function. The function must have the signature:+ * @code void function(yield_context yield); @endcode+ *+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.+ */+template <typename Function, typename Executor>+void spawn(const Executor& ex,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes+ = boost::coroutines::attributes(),+ typename enable_if<+ is_executor<Executor>::value || execution::is_executor<Executor>::value+ >::type* = 0);++/// Start a new stackful coroutine that executes on a given strand.+/**+ * This function is used to launch a new coroutine.+ *+ * @param ex Identifies the strand that will run the coroutine.+ *+ * @param function The coroutine function. The function must have the signature:+ * @code void function(yield_context yield); @endcode+ *+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.+ */+template <typename Function, typename Executor>+void spawn(const strand<Executor>& ex,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes+ = boost::coroutines::attributes());++#if !defined(ASIO_NO_TS_EXECUTORS)++/// Start a new stackful coroutine that executes in the context of a strand.+/**+ * This function is used to launch a new coroutine.+ *+ * @param s Identifies a strand. By starting multiple coroutines on the same+ * strand, the implementation ensures that none of those coroutines can execute+ * simultaneously.+ *+ * @param function The coroutine function. The function must have the signature:+ * @code void function(yield_context yield); @endcode+ *+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.+ */+template <typename Function>+void spawn(const asio::io_context::strand& s,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes+ = boost::coroutines::attributes());++#endif // !defined(ASIO_NO_TS_EXECUTORS)++/// Start a new stackful coroutine that executes on a given execution context.+/**+ * This function is used to launch a new coroutine.+ *+ * @param ctx Identifies the execution context that will run the coroutine. The+ * new coroutine is implicitly given its own strand within this execution+ * context.+ *+ * @param function The coroutine function. The function must have the signature:+ * @code void function(yield_context yield); @endcode+ *+ * @param attributes Boost.Coroutine attributes used to customise the coroutine.+ */+template <typename Function, typename ExecutionContext>+void spawn(ExecutionContext& ctx,+ ASIO_MOVE_ARG(Function) function,+ const boost::coroutines::attributes& attributes+ = boost::coroutines::attributes(),+ typename enable_if<is_convertible<+ ExecutionContext&, execution_context&>::value>::type* = 0);++/*@}*/++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/spawn.hpp"++#endif // ASIO_SPAWN_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl.hpp view
@@ -0,0 +1,28 @@+//+// ssl.hpp+// ~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_HPP+#define ASIO_SSL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/ssl/context.hpp"+#include "asio/ssl/context_base.hpp"+#include "asio/ssl/error.hpp"+#include "asio/ssl/rfc2818_verification.hpp"+#include "asio/ssl/host_name_verification.hpp"+#include "asio/ssl/stream.hpp"+#include "asio/ssl/stream_base.hpp"+#include "asio/ssl/verify_context.hpp"+#include "asio/ssl/verify_mode.hpp"++#endif // ASIO_SSL_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/context.hpp view
@@ -0,0 +1,761 @@+//+// ssl/context.hpp+// ~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_CONTEXT_HPP+#define ASIO_SSL_CONTEXT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <string>+#include "asio/buffer.hpp"+#include "asio/io_context.hpp"+#include "asio/ssl/context_base.hpp"+#include "asio/ssl/detail/openssl_types.hpp"+#include "asio/ssl/detail/openssl_init.hpp"+#include "asio/ssl/detail/password_callback.hpp"+#include "asio/ssl/detail/verify_callback.hpp"+#include "asio/ssl/verify_mode.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {++class context+ : public context_base,+ private noncopyable+{+public:+ /// The native handle type of the SSL context.+ typedef SSL_CTX* native_handle_type;++ /// Constructor.+ ASIO_DECL explicit context(method m);++ /// Construct to take ownership of a native handle.+ ASIO_DECL explicit context(native_handle_type native_handle);++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a context from another.+ /**+ * This constructor moves an SSL context from one object to another.+ *+ * @param other The other context object from which the move will occur.+ *+ * @note Following the move, the following operations only are valid for the+ * moved-from object:+ * @li Destruction.+ * @li As a target for move-assignment.+ */+ ASIO_DECL context(context&& other);++ /// Move-assign a context from another.+ /**+ * This assignment operator moves an SSL context from one object to another.+ *+ * @param other The other context object from which the move will occur.+ *+ * @note Following the move, the following operations only are valid for the+ * moved-from object:+ * @li Destruction.+ * @li As a target for move-assignment.+ */+ ASIO_DECL context& operator=(context&& other);+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destructor.+ ASIO_DECL ~context();++ /// Get the underlying implementation in the native type.+ /**+ * This function may be used to obtain the underlying implementation of the+ * context. This is intended to allow access to context functionality that is+ * not otherwise provided.+ */+ ASIO_DECL native_handle_type native_handle();++ /// Clear options on the context.+ /**+ * This function may be used to configure the SSL options used by the context.+ *+ * @param o A bitmask of options. The available option values are defined in+ * the context_base class. The specified options, if currently enabled on the+ * context, are cleared.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_clear_options.+ */+ ASIO_DECL void clear_options(options o);++ /// Clear options on the context.+ /**+ * This function may be used to configure the SSL options used by the context.+ *+ * @param o A bitmask of options. The available option values are defined in+ * the context_base class. The specified options, if currently enabled on the+ * context, are cleared.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_clear_options.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID clear_options(options o,+ asio::error_code& ec);++ /// Set options on the context.+ /**+ * This function may be used to configure the SSL options used by the context.+ *+ * @param o A bitmask of options. The available option values are defined in+ * the context_base class. The options are bitwise-ored with any existing+ * value for the options.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_set_options.+ */+ ASIO_DECL void set_options(options o);++ /// Set options on the context.+ /**+ * This function may be used to configure the SSL options used by the context.+ *+ * @param o A bitmask of options. The available option values are defined in+ * the context_base class. The options are bitwise-ored with any existing+ * value for the options.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_set_options.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID set_options(options o,+ asio::error_code& ec);++ /// Set the peer verification mode.+ /**+ * This function may be used to configure the peer verification mode used by+ * the context.+ *+ * @param v A bitmask of peer verification modes. See @ref verify_mode for+ * available values.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_set_verify.+ */+ ASIO_DECL void set_verify_mode(verify_mode v);++ /// Set the peer verification mode.+ /**+ * This function may be used to configure the peer verification mode used by+ * the context.+ *+ * @param v A bitmask of peer verification modes. See @ref verify_mode for+ * available values.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_set_verify.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID set_verify_mode(+ verify_mode v, asio::error_code& ec);++ /// Set the peer verification depth.+ /**+ * This function may be used to configure the maximum verification depth+ * allowed by the context.+ *+ * @param depth Maximum depth for the certificate chain verification that+ * shall be allowed.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_set_verify_depth.+ */+ ASIO_DECL void set_verify_depth(int depth);++ /// Set the peer verification depth.+ /**+ * This function may be used to configure the maximum verification depth+ * allowed by the context.+ *+ * @param depth Maximum depth for the certificate chain verification that+ * shall be allowed.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_set_verify_depth.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID set_verify_depth(+ int depth, asio::error_code& ec);++ /// Set the callback used to verify peer certificates.+ /**+ * This function is used to specify a callback function that will be called+ * by the implementation when it needs to verify a peer certificate.+ *+ * @param callback The function object to be used for verifying a certificate.+ * The function signature of the handler must be:+ * @code bool verify_callback(+ * bool preverified, // True if the certificate passed pre-verification.+ * verify_context& ctx // The peer certificate and other context.+ * ); @endcode+ * The return value of the callback is true if the certificate has passed+ * verification, false otherwise.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_set_verify.+ */+ template <typename VerifyCallback>+ void set_verify_callback(VerifyCallback callback);++ /// Set the callback used to verify peer certificates.+ /**+ * This function is used to specify a callback function that will be called+ * by the implementation when it needs to verify a peer certificate.+ *+ * @param callback The function object to be used for verifying a certificate.+ * The function signature of the handler must be:+ * @code bool verify_callback(+ * bool preverified, // True if the certificate passed pre-verification.+ * verify_context& ctx // The peer certificate and other context.+ * ); @endcode+ * The return value of the callback is true if the certificate has passed+ * verification, false otherwise.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_set_verify.+ */+ template <typename VerifyCallback>+ ASIO_SYNC_OP_VOID set_verify_callback(VerifyCallback callback,+ asio::error_code& ec);++ /// Load a certification authority file for performing verification.+ /**+ * This function is used to load one or more trusted certification authorities+ * from a file.+ *+ * @param filename The name of a file containing certification authority+ * certificates in PEM format.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_load_verify_locations.+ */+ ASIO_DECL void load_verify_file(const std::string& filename);++ /// Load a certification authority file for performing verification.+ /**+ * This function is used to load the certificates for one or more trusted+ * certification authorities from a file.+ *+ * @param filename The name of a file containing certification authority+ * certificates in PEM format.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_load_verify_locations.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID load_verify_file(+ const std::string& filename, asio::error_code& ec);++ /// Add certification authority for performing verification.+ /**+ * This function is used to add one trusted certification authority+ * from a memory buffer.+ *+ * @param ca The buffer containing the certification authority certificate.+ * The certificate must use the PEM format.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_get_cert_store and @c X509_STORE_add_cert.+ */+ ASIO_DECL void add_certificate_authority(const const_buffer& ca);++ /// Add certification authority for performing verification.+ /**+ * This function is used to add one trusted certification authority+ * from a memory buffer.+ *+ * @param ca The buffer containing the certification authority certificate.+ * The certificate must use the PEM format.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_get_cert_store and @c X509_STORE_add_cert.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID add_certificate_authority(+ const const_buffer& ca, asio::error_code& ec);++ /// Configures the context to use the default directories for finding+ /// certification authority certificates.+ /**+ * This function specifies that the context should use the default,+ * system-dependent directories for locating certification authority+ * certificates.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_set_default_verify_paths.+ */+ ASIO_DECL void set_default_verify_paths();++ /// Configures the context to use the default directories for finding+ /// certification authority certificates.+ /**+ * This function specifies that the context should use the default,+ * system-dependent directories for locating certification authority+ * certificates.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_set_default_verify_paths.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID set_default_verify_paths(+ asio::error_code& ec);++ /// Add a directory containing certificate authority files to be used for+ /// performing verification.+ /**+ * This function is used to specify the name of a directory containing+ * certification authority certificates. Each file in the directory must+ * contain a single certificate. The files must be named using the subject+ * name's hash and an extension of ".0".+ *+ * @param path The name of a directory containing the certificates.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_load_verify_locations.+ */+ ASIO_DECL void add_verify_path(const std::string& path);++ /// Add a directory containing certificate authority files to be used for+ /// performing verification.+ /**+ * This function is used to specify the name of a directory containing+ * certification authority certificates. Each file in the directory must+ * contain a single certificate. The files must be named using the subject+ * name's hash and an extension of ".0".+ *+ * @param path The name of a directory containing the certificates.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_load_verify_locations.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID add_verify_path(+ const std::string& path, asio::error_code& ec);++ /// Use a certificate from a memory buffer.+ /**+ * This function is used to load a certificate into the context from a buffer.+ *+ * @param certificate The buffer containing the certificate.+ *+ * @param format The certificate format (ASN.1 or PEM).+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_use_certificate or SSL_CTX_use_certificate_ASN1.+ */+ ASIO_DECL void use_certificate(+ const const_buffer& certificate, file_format format);++ /// Use a certificate from a memory buffer.+ /**+ * This function is used to load a certificate into the context from a buffer.+ *+ * @param certificate The buffer containing the certificate.+ *+ * @param format The certificate format (ASN.1 or PEM).+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_use_certificate or SSL_CTX_use_certificate_ASN1.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID use_certificate(+ const const_buffer& certificate, file_format format,+ asio::error_code& ec);++ /// Use a certificate from a file.+ /**+ * This function is used to load a certificate into the context from a file.+ *+ * @param filename The name of the file containing the certificate.+ *+ * @param format The file format (ASN.1 or PEM).+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_use_certificate_file.+ */+ ASIO_DECL void use_certificate_file(+ const std::string& filename, file_format format);++ /// Use a certificate from a file.+ /**+ * This function is used to load a certificate into the context from a file.+ *+ * @param filename The name of the file containing the certificate.+ *+ * @param format The file format (ASN.1 or PEM).+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_use_certificate_file.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID use_certificate_file(+ const std::string& filename, file_format format,+ asio::error_code& ec);++ /// Use a certificate chain from a memory buffer.+ /**+ * This function is used to load a certificate chain into the context from a+ * buffer.+ *+ * @param chain The buffer containing the certificate chain. The certificate+ * chain must use the PEM format.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_use_certificate and SSL_CTX_add_extra_chain_cert.+ */+ ASIO_DECL void use_certificate_chain(const const_buffer& chain);++ /// Use a certificate chain from a memory buffer.+ /**+ * This function is used to load a certificate chain into the context from a+ * buffer.+ *+ * @param chain The buffer containing the certificate chain. The certificate+ * chain must use the PEM format.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_use_certificate and SSL_CTX_add_extra_chain_cert.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID use_certificate_chain(+ const const_buffer& chain, asio::error_code& ec);++ /// Use a certificate chain from a file.+ /**+ * This function is used to load a certificate chain into the context from a+ * file.+ *+ * @param filename The name of the file containing the certificate. The file+ * must use the PEM format.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_use_certificate_chain_file.+ */+ ASIO_DECL void use_certificate_chain_file(const std::string& filename);++ /// Use a certificate chain from a file.+ /**+ * This function is used to load a certificate chain into the context from a+ * file.+ *+ * @param filename The name of the file containing the certificate. The file+ * must use the PEM format.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_use_certificate_chain_file.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID use_certificate_chain_file(+ const std::string& filename, asio::error_code& ec);++ /// Use a private key from a memory buffer.+ /**+ * This function is used to load a private key into the context from a buffer.+ *+ * @param private_key The buffer containing the private key.+ *+ * @param format The private key format (ASN.1 or PEM).+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_use_PrivateKey or SSL_CTX_use_PrivateKey_ASN1.+ */+ ASIO_DECL void use_private_key(+ const const_buffer& private_key, file_format format);++ /// Use a private key from a memory buffer.+ /**+ * This function is used to load a private key into the context from a buffer.+ *+ * @param private_key The buffer containing the private key.+ *+ * @param format The private key format (ASN.1 or PEM).+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_use_PrivateKey or SSL_CTX_use_PrivateKey_ASN1.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID use_private_key(+ const const_buffer& private_key, file_format format,+ asio::error_code& ec);++ /// Use a private key from a file.+ /**+ * This function is used to load a private key into the context from a file.+ *+ * @param filename The name of the file containing the private key.+ *+ * @param format The file format (ASN.1 or PEM).+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_use_PrivateKey_file.+ */+ ASIO_DECL void use_private_key_file(+ const std::string& filename, file_format format);++ /// Use a private key from a file.+ /**+ * This function is used to load a private key into the context from a file.+ *+ * @param filename The name of the file containing the private key.+ *+ * @param format The file format (ASN.1 or PEM).+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_use_PrivateKey_file.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID use_private_key_file(+ const std::string& filename, file_format format,+ asio::error_code& ec);++ /// Use an RSA private key from a memory buffer.+ /**+ * This function is used to load an RSA private key into the context from a+ * buffer.+ *+ * @param private_key The buffer containing the RSA private key.+ *+ * @param format The private key format (ASN.1 or PEM).+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_use_RSAPrivateKey or SSL_CTX_use_RSAPrivateKey_ASN1.+ */+ ASIO_DECL void use_rsa_private_key(+ const const_buffer& private_key, file_format format);++ /// Use an RSA private key from a memory buffer.+ /**+ * This function is used to load an RSA private key into the context from a+ * buffer.+ *+ * @param private_key The buffer containing the RSA private key.+ *+ * @param format The private key format (ASN.1 or PEM).+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_use_RSAPrivateKey or SSL_CTX_use_RSAPrivateKey_ASN1.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID use_rsa_private_key(+ const const_buffer& private_key, file_format format,+ asio::error_code& ec);++ /// Use an RSA private key from a file.+ /**+ * This function is used to load an RSA private key into the context from a+ * file.+ *+ * @param filename The name of the file containing the RSA private key.+ *+ * @param format The file format (ASN.1 or PEM).+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_use_RSAPrivateKey_file.+ */+ ASIO_DECL void use_rsa_private_key_file(+ const std::string& filename, file_format format);++ /// Use an RSA private key from a file.+ /**+ * This function is used to load an RSA private key into the context from a+ * file.+ *+ * @param filename The name of the file containing the RSA private key.+ *+ * @param format The file format (ASN.1 or PEM).+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_use_RSAPrivateKey_file.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID use_rsa_private_key_file(+ const std::string& filename, file_format format,+ asio::error_code& ec);++ /// Use the specified memory buffer to obtain the temporary Diffie-Hellman+ /// parameters.+ /**+ * This function is used to load Diffie-Hellman parameters into the context+ * from a buffer.+ *+ * @param dh The memory buffer containing the Diffie-Hellman parameters. The+ * buffer must use the PEM format.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_set_tmp_dh.+ */+ ASIO_DECL void use_tmp_dh(const const_buffer& dh);++ /// Use the specified memory buffer to obtain the temporary Diffie-Hellman+ /// parameters.+ /**+ * This function is used to load Diffie-Hellman parameters into the context+ * from a buffer.+ *+ * @param dh The memory buffer containing the Diffie-Hellman parameters. The+ * buffer must use the PEM format.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_set_tmp_dh.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID use_tmp_dh(+ const const_buffer& dh, asio::error_code& ec);++ /// Use the specified file to obtain the temporary Diffie-Hellman parameters.+ /**+ * This function is used to load Diffie-Hellman parameters into the context+ * from a file.+ *+ * @param filename The name of the file containing the Diffie-Hellman+ * parameters. The file must use the PEM format.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_set_tmp_dh.+ */+ ASIO_DECL void use_tmp_dh_file(const std::string& filename);++ /// Use the specified file to obtain the temporary Diffie-Hellman parameters.+ /**+ * This function is used to load Diffie-Hellman parameters into the context+ * from a file.+ *+ * @param filename The name of the file containing the Diffie-Hellman+ * parameters. The file must use the PEM format.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_set_tmp_dh.+ */+ ASIO_DECL ASIO_SYNC_OP_VOID use_tmp_dh_file(+ const std::string& filename, asio::error_code& ec);++ /// Set the password callback.+ /**+ * This function is used to specify a callback function to obtain password+ * information about an encrypted key in PEM format.+ *+ * @param callback The function object to be used for obtaining the password.+ * The function signature of the handler must be:+ * @code std::string password_callback(+ * std::size_t max_length, // The maximum size for a password.+ * password_purpose purpose // Whether password is for reading or writing.+ * ); @endcode+ * The return value of the callback is a string containing the password.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_CTX_set_default_passwd_cb.+ */+ template <typename PasswordCallback>+ void set_password_callback(PasswordCallback callback);++ /// Set the password callback.+ /**+ * This function is used to specify a callback function to obtain password+ * information about an encrypted key in PEM format.+ *+ * @param callback The function object to be used for obtaining the password.+ * The function signature of the handler must be:+ * @code std::string password_callback(+ * std::size_t max_length, // The maximum size for a password.+ * password_purpose purpose // Whether password is for reading or writing.+ * ); @endcode+ * The return value of the callback is a string containing the password.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_CTX_set_default_passwd_cb.+ */+ template <typename PasswordCallback>+ ASIO_SYNC_OP_VOID set_password_callback(PasswordCallback callback,+ asio::error_code& ec);++private:+ struct bio_cleanup;+ struct x509_cleanup;+ struct evp_pkey_cleanup;+ struct rsa_cleanup;+ struct dh_cleanup;++ // Helper function used to set a peer certificate verification callback.+ ASIO_DECL ASIO_SYNC_OP_VOID do_set_verify_callback(+ detail::verify_callback_base* callback, asio::error_code& ec);++ // Callback used when the SSL implementation wants to verify a certificate.+ ASIO_DECL static int verify_callback_function(+ int preverified, X509_STORE_CTX* ctx);++ // Helper function used to set a password callback.+ ASIO_DECL ASIO_SYNC_OP_VOID do_set_password_callback(+ detail::password_callback_base* callback, asio::error_code& ec);++ // Callback used when the SSL implementation wants a password.+ ASIO_DECL static int password_callback_function(+ char* buf, int size, int purpose, void* data);++ // Helper function to set the temporary Diffie-Hellman parameters from a BIO.+ ASIO_DECL ASIO_SYNC_OP_VOID do_use_tmp_dh(+ BIO* bio, asio::error_code& ec);++ // Helper function to make a BIO from a memory buffer.+ ASIO_DECL BIO* make_buffer_bio(const const_buffer& b);++ // The underlying native implementation.+ native_handle_type handle_;++ // Ensure openssl is initialised.+ asio::ssl::detail::openssl_init<> init_;+};++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/ssl/impl/context.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/ssl/impl/context.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_SSL_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/context_base.hpp view
@@ -0,0 +1,209 @@+//+// ssl/context_base.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_CONTEXT_BASE_HPP+#define ASIO_SSL_CONTEXT_BASE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/ssl/detail/openssl_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {++/// The context_base class is used as a base for the basic_context class+/// template so that we have a common place to define various enums.+class context_base+{+public:+ /// Different methods supported by a context.+ enum method+ {+ /// Generic SSL version 2.+ sslv2,++ /// SSL version 2 client.+ sslv2_client,++ /// SSL version 2 server.+ sslv2_server,++ /// Generic SSL version 3.+ sslv3,++ /// SSL version 3 client.+ sslv3_client,++ /// SSL version 3 server.+ sslv3_server,++ /// Generic TLS version 1.+ tlsv1,++ /// TLS version 1 client.+ tlsv1_client,++ /// TLS version 1 server.+ tlsv1_server,++ /// Generic SSL/TLS.+ sslv23,++ /// SSL/TLS client.+ sslv23_client,++ /// SSL/TLS server.+ sslv23_server,++ /// Generic TLS version 1.1.+ tlsv11,++ /// TLS version 1.1 client.+ tlsv11_client,++ /// TLS version 1.1 server.+ tlsv11_server,++ /// Generic TLS version 1.2.+ tlsv12,++ /// TLS version 1.2 client.+ tlsv12_client,++ /// TLS version 1.2 server.+ tlsv12_server,++ /// Generic TLS version 1.3.+ tlsv13,++ /// TLS version 1.3 client.+ tlsv13_client,++ /// TLS version 1.3 server.+ tlsv13_server,++ /// Generic TLS.+ tls,++ /// TLS client.+ tls_client,++ /// TLS server.+ tls_server+ };++ /// Bitmask type for SSL options.+ typedef long options;++#if defined(GENERATING_DOCUMENTATION)+ /// Implement various bug workarounds.+ static const long default_workarounds = implementation_defined;++ /// Always create a new key when using tmp_dh parameters.+ static const long single_dh_use = implementation_defined;++ /// Disable SSL v2.+ static const long no_sslv2 = implementation_defined;++ /// Disable SSL v3.+ static const long no_sslv3 = implementation_defined;++ /// Disable TLS v1.+ static const long no_tlsv1 = implementation_defined;++ /// Disable TLS v1.1.+ static const long no_tlsv1_1 = implementation_defined;++ /// Disable TLS v1.2.+ static const long no_tlsv1_2 = implementation_defined;++ /// Disable TLS v1.3.+ static const long no_tlsv1_3 = implementation_defined;++ /// Disable compression. Compression is disabled by default.+ static const long no_compression = implementation_defined;+#else+ ASIO_STATIC_CONSTANT(long, default_workarounds = SSL_OP_ALL);+ ASIO_STATIC_CONSTANT(long, single_dh_use = SSL_OP_SINGLE_DH_USE);+ ASIO_STATIC_CONSTANT(long, no_sslv2 = SSL_OP_NO_SSLv2);+ ASIO_STATIC_CONSTANT(long, no_sslv3 = SSL_OP_NO_SSLv3);+ ASIO_STATIC_CONSTANT(long, no_tlsv1 = SSL_OP_NO_TLSv1);+# if defined(SSL_OP_NO_TLSv1_1)+ ASIO_STATIC_CONSTANT(long, no_tlsv1_1 = SSL_OP_NO_TLSv1_1);+# else // defined(SSL_OP_NO_TLSv1_1)+ ASIO_STATIC_CONSTANT(long, no_tlsv1_1 = 0x10000000L);+# endif // defined(SSL_OP_NO_TLSv1_1)+# if defined(SSL_OP_NO_TLSv1_2)+ ASIO_STATIC_CONSTANT(long, no_tlsv1_2 = SSL_OP_NO_TLSv1_2);+# else // defined(SSL_OP_NO_TLSv1_2)+ ASIO_STATIC_CONSTANT(long, no_tlsv1_2 = 0x08000000L);+# endif // defined(SSL_OP_NO_TLSv1_2)+# if defined(SSL_OP_NO_TLSv1_3)+ ASIO_STATIC_CONSTANT(long, no_tlsv1_3 = SSL_OP_NO_TLSv1_3);+# else // defined(SSL_OP_NO_TLSv1_3)+ ASIO_STATIC_CONSTANT(long, no_tlsv1_3 = 0x20000000L);+# endif // defined(SSL_OP_NO_TLSv1_3)+# if defined(SSL_OP_NO_COMPRESSION)+ ASIO_STATIC_CONSTANT(long, no_compression = SSL_OP_NO_COMPRESSION);+# else // defined(SSL_OP_NO_COMPRESSION)+ ASIO_STATIC_CONSTANT(long, no_compression = 0x20000L);+# endif // defined(SSL_OP_NO_COMPRESSION)+#endif++ /// File format types.+ enum file_format+ {+ /// ASN.1 file.+ asn1,++ /// PEM file.+ pem+ };++#if !defined(GENERATING_DOCUMENTATION)+ // The following types and constants are preserved for backward compatibility.+ // New programs should use the equivalents of the same names that are defined+ // in the asio::ssl namespace.+ typedef int verify_mode;+ ASIO_STATIC_CONSTANT(int, verify_none = SSL_VERIFY_NONE);+ ASIO_STATIC_CONSTANT(int, verify_peer = SSL_VERIFY_PEER);+ ASIO_STATIC_CONSTANT(int,+ verify_fail_if_no_peer_cert = SSL_VERIFY_FAIL_IF_NO_PEER_CERT);+ ASIO_STATIC_CONSTANT(int, verify_client_once = SSL_VERIFY_CLIENT_ONCE);+#endif++ /// Purpose of PEM password.+ enum password_purpose+ {+ /// The password is needed for reading/decryption.+ for_reading,++ /// The password is needed for writing/encryption.+ for_writing+ };++protected:+ /// Protected destructor to prevent deletion through this type.+ ~context_base()+ {+ }+};++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_CONTEXT_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/buffered_handshake_op.hpp view
@@ -0,0 +1,119 @@+//+// ssl/detail/buffered_handshake_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_BUFFERED_HANDSHAKE_OP_HPP+#define ASIO_SSL_DETAIL_BUFFERED_HANDSHAKE_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/ssl/detail/engine.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++template <typename ConstBufferSequence>+class buffered_handshake_op+{+public:+ static ASIO_CONSTEXPR const char* tracking_name()+ {+ return "ssl::stream<>::async_buffered_handshake";+ }++ buffered_handshake_op(stream_base::handshake_type type,+ const ConstBufferSequence& buffers)+ : type_(type),+ buffers_(buffers),+ total_buffer_size_(asio::buffer_size(buffers_))+ {+ }++ engine::want operator()(engine& eng,+ asio::error_code& ec,+ std::size_t& bytes_transferred) const+ {+ return this->process(eng, ec, bytes_transferred,+ asio::buffer_sequence_begin(buffers_),+ asio::buffer_sequence_end(buffers_));+ }++ template <typename Handler>+ void call_handler(Handler& handler,+ const asio::error_code& ec,+ const std::size_t& bytes_transferred) const+ {+ handler(ec, bytes_transferred);+ }++private:+ template <typename Iterator>+ engine::want process(engine& eng,+ asio::error_code& ec,+ std::size_t& bytes_transferred,+ Iterator begin, Iterator end) const+ {+ Iterator iter = begin;+ std::size_t accumulated_size = 0;++ for (;;)+ {+ engine::want want = eng.handshake(type_, ec);+ if (want != engine::want_input_and_retry+ || bytes_transferred == total_buffer_size_)+ return want;++ // Find the next buffer piece to be fed to the engine.+ while (iter != end)+ {+ const_buffer buffer(*iter);++ // Skip over any buffers which have already been consumed by the engine.+ if (bytes_transferred >= accumulated_size + buffer.size())+ {+ accumulated_size += buffer.size();+ ++iter;+ continue;+ }++ // The current buffer may have been partially consumed by the engine on+ // a previous iteration. If so, adjust the buffer to point to the+ // unused portion.+ if (bytes_transferred > accumulated_size)+ buffer = buffer + (bytes_transferred - accumulated_size);++ // Pass the buffer to the engine, and update the bytes transferred to+ // reflect the total number of bytes consumed so far.+ bytes_transferred += buffer.size();+ buffer = eng.put_input(buffer);+ bytes_transferred -= buffer.size();+ break;+ }+ }+ }++ stream_base::handshake_type type_;+ ConstBufferSequence buffers_;+ std::size_t total_buffer_size_;+};++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_DETAIL_BUFFERED_HANDSHAKE_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/engine.hpp view
@@ -0,0 +1,165 @@+//+// ssl/detail/engine.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_ENGINE_HPP+#define ASIO_SSL_DETAIL_ENGINE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include "asio/buffer.hpp"+#include "asio/detail/static_mutex.hpp"+#include "asio/ssl/detail/openssl_types.hpp"+#include "asio/ssl/detail/verify_callback.hpp"+#include "asio/ssl/stream_base.hpp"+#include "asio/ssl/verify_mode.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++class engine+{+public:+ enum want+ {+ // Returned by functions to indicate that the engine wants input. The input+ // buffer should be updated to point to the data. The engine then needs to+ // be called again to retry the operation.+ want_input_and_retry = -2,++ // Returned by functions to indicate that the engine wants to write output.+ // The output buffer points to the data to be written. The engine then+ // needs to be called again to retry the operation.+ want_output_and_retry = -1,++ // Returned by functions to indicate that the engine doesn't need input or+ // output.+ want_nothing = 0,++ // Returned by functions to indicate that the engine wants to write output.+ // The output buffer points to the data to be written. After that the+ // operation is complete, and the engine does not need to be called again.+ want_output = 1+ };++ // Construct a new engine for the specified context.+ ASIO_DECL explicit engine(SSL_CTX* context);++#if defined(ASIO_HAS_MOVE)+ // Move construct from another engine.+ ASIO_DECL engine(engine&& other) ASIO_NOEXCEPT;+#endif // defined(ASIO_HAS_MOVE)++ // Destructor.+ ASIO_DECL ~engine();++ // Get the underlying implementation in the native type.+ ASIO_DECL SSL* native_handle();++ // Set the peer verification mode.+ ASIO_DECL asio::error_code set_verify_mode(+ verify_mode v, asio::error_code& ec);++ // Set the peer verification depth.+ ASIO_DECL asio::error_code set_verify_depth(+ int depth, asio::error_code& ec);++ // Set a peer certificate verification callback.+ ASIO_DECL asio::error_code set_verify_callback(+ verify_callback_base* callback, asio::error_code& ec);++ // Perform an SSL handshake using either SSL_connect (client-side) or+ // SSL_accept (server-side).+ ASIO_DECL want handshake(+ stream_base::handshake_type type, asio::error_code& ec);++ // Perform a graceful shutdown of the SSL session.+ ASIO_DECL want shutdown(asio::error_code& ec);++ // Write bytes to the SSL session.+ ASIO_DECL want write(const asio::const_buffer& data,+ asio::error_code& ec, std::size_t& bytes_transferred);++ // Read bytes from the SSL session.+ ASIO_DECL want read(const asio::mutable_buffer& data,+ asio::error_code& ec, std::size_t& bytes_transferred);++ // Get output data to be written to the transport.+ ASIO_DECL asio::mutable_buffer get_output(+ const asio::mutable_buffer& data);++ // Put input data that was read from the transport.+ ASIO_DECL asio::const_buffer put_input(+ const asio::const_buffer& data);++ // Map an error::eof code returned by the underlying transport according to+ // the type and state of the SSL session. Returns a const reference to the+ // error code object, suitable for passing to a completion handler.+ ASIO_DECL const asio::error_code& map_error_code(+ asio::error_code& ec) const;++private:+ // Disallow copying and assignment.+ engine(const engine&);+ engine& operator=(const engine&);++ // Callback used when the SSL implementation wants to verify a certificate.+ ASIO_DECL static int verify_callback_function(+ int preverified, X509_STORE_CTX* ctx);++#if (OPENSSL_VERSION_NUMBER < 0x10000000L)+ // The SSL_accept function may not be thread safe. This mutex is used to+ // protect all calls to the SSL_accept function.+ ASIO_DECL static asio::detail::static_mutex& accept_mutex();+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)++ // Perform one operation. Returns >= 0 on success or error, want_read if the+ // operation needs more input, or want_write if it needs to write some output+ // before the operation can complete.+ ASIO_DECL want perform(int (engine::* op)(void*, std::size_t),+ void* data, std::size_t length, asio::error_code& ec,+ std::size_t* bytes_transferred);++ // Adapt the SSL_accept function to the signature needed for perform().+ ASIO_DECL int do_accept(void*, std::size_t);++ // Adapt the SSL_connect function to the signature needed for perform().+ ASIO_DECL int do_connect(void*, std::size_t);++ // Adapt the SSL_shutdown function to the signature needed for perform().+ ASIO_DECL int do_shutdown(void*, std::size_t);++ // Adapt the SSL_read function to the signature needed for perform().+ ASIO_DECL int do_read(void* data, std::size_t length);++ // Adapt the SSL_write function to the signature needed for perform().+ ASIO_DECL int do_write(void* data, std::size_t length);++ SSL* ssl_;+ BIO* ext_bio_;+};++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/ssl/detail/impl/engine.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_SSL_DETAIL_ENGINE_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/handshake_op.hpp view
@@ -0,0 +1,67 @@+//+// ssl/detail/handshake_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_HANDSHAKE_OP_HPP+#define ASIO_SSL_DETAIL_HANDSHAKE_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/ssl/detail/engine.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++class handshake_op+{+public:+ static ASIO_CONSTEXPR const char* tracking_name()+ {+ return "ssl::stream<>::async_handshake";+ }++ handshake_op(stream_base::handshake_type type)+ : type_(type)+ {+ }++ engine::want operator()(engine& eng,+ asio::error_code& ec,+ std::size_t& bytes_transferred) const+ {+ bytes_transferred = 0;+ return eng.handshake(type_, ec);+ }++ template <typename Handler>+ void call_handler(Handler& handler,+ const asio::error_code& ec,+ const std::size_t&) const+ {+ handler(ec);+ }++private:+ stream_base::handshake_type type_;+};++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/impl/engine.ipp view
@@ -0,0 +1,349 @@+//+// ssl/detail/impl/engine.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_IMPL_ENGINE_IPP+#define ASIO_SSL_DETAIL_IMPL_ENGINE_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"+#include "asio/ssl/detail/engine.hpp"+#include "asio/ssl/error.hpp"+#include "asio/ssl/verify_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++engine::engine(SSL_CTX* context)+ : ssl_(::SSL_new(context))+{+ if (!ssl_)+ {+ asio::error_code ec(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ asio::detail::throw_error(ec, "engine");+ }++#if (OPENSSL_VERSION_NUMBER < 0x10000000L)+ accept_mutex().init();+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)++ ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE);+ ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);+#if defined(SSL_MODE_RELEASE_BUFFERS)+ ::SSL_set_mode(ssl_, SSL_MODE_RELEASE_BUFFERS);+#endif // defined(SSL_MODE_RELEASE_BUFFERS)++ ::BIO* int_bio = 0;+ ::BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0);+ ::SSL_set_bio(ssl_, int_bio, int_bio);+}++#if defined(ASIO_HAS_MOVE)+engine::engine(engine&& other) ASIO_NOEXCEPT+ : ssl_(other.ssl_),+ ext_bio_(other.ext_bio_)+{+ other.ssl_ = 0;+ other.ext_bio_ = 0;+}+#endif // defined(ASIO_HAS_MOVE)++engine::~engine()+{+ if (ssl_ && SSL_get_app_data(ssl_))+ {+ delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));+ SSL_set_app_data(ssl_, 0);+ }++ if (ext_bio_)+ ::BIO_free(ext_bio_);++ if (ssl_)+ ::SSL_free(ssl_);+}++SSL* engine::native_handle()+{+ return ssl_;+}++asio::error_code engine::set_verify_mode(+ verify_mode v, asio::error_code& ec)+{+ ::SSL_set_verify(ssl_, v, ::SSL_get_verify_callback(ssl_));++ ec = asio::error_code();+ return ec;+}++asio::error_code engine::set_verify_depth(+ int depth, asio::error_code& ec)+{+ ::SSL_set_verify_depth(ssl_, depth);++ ec = asio::error_code();+ return ec;+}++asio::error_code engine::set_verify_callback(+ verify_callback_base* callback, asio::error_code& ec)+{+ if (SSL_get_app_data(ssl_))+ delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));++ SSL_set_app_data(ssl_, callback);++ ::SSL_set_verify(ssl_, ::SSL_get_verify_mode(ssl_),+ &engine::verify_callback_function);++ ec = asio::error_code();+ return ec;+}++int engine::verify_callback_function(int preverified, X509_STORE_CTX* ctx)+{+ if (ctx)+ {+ if (SSL* ssl = static_cast<SSL*>(+ ::X509_STORE_CTX_get_ex_data(+ ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx())))+ {+ if (SSL_get_app_data(ssl))+ {+ verify_callback_base* callback =+ static_cast<verify_callback_base*>(+ SSL_get_app_data(ssl));++ verify_context verify_ctx(ctx);+ return callback->call(preverified != 0, verify_ctx) ? 1 : 0;+ }+ }+ }++ return 0;+}++engine::want engine::handshake(+ stream_base::handshake_type type, asio::error_code& ec)+{+ return perform((type == asio::ssl::stream_base::client)+ ? &engine::do_connect : &engine::do_accept, 0, 0, ec, 0);+}++engine::want engine::shutdown(asio::error_code& ec)+{+ return perform(&engine::do_shutdown, 0, 0, ec, 0);+}++engine::want engine::write(const asio::const_buffer& data,+ asio::error_code& ec, std::size_t& bytes_transferred)+{+ if (data.size() == 0)+ {+ ec = asio::error_code();+ return engine::want_nothing;+ }++ return perform(&engine::do_write,+ const_cast<void*>(data.data()),+ data.size(), ec, &bytes_transferred);+}++engine::want engine::read(const asio::mutable_buffer& data,+ asio::error_code& ec, std::size_t& bytes_transferred)+{+ if (data.size() == 0)+ {+ ec = asio::error_code();+ return engine::want_nothing;+ }++ return perform(&engine::do_read, data.data(),+ data.size(), ec, &bytes_transferred);+}++asio::mutable_buffer engine::get_output(+ const asio::mutable_buffer& data)+{+ int length = ::BIO_read(ext_bio_,+ data.data(), static_cast<int>(data.size()));++ return asio::buffer(data,+ length > 0 ? static_cast<std::size_t>(length) : 0);+}++asio::const_buffer engine::put_input(+ const asio::const_buffer& data)+{+ int length = ::BIO_write(ext_bio_,+ data.data(), static_cast<int>(data.size()));++ return asio::buffer(data ++ (length > 0 ? static_cast<std::size_t>(length) : 0));+}++const asio::error_code& engine::map_error_code(+ asio::error_code& ec) const+{+ // We only want to map the error::eof code.+ if (ec != asio::error::eof)+ return ec;++ // If there's data yet to be read, it's an error.+ if (BIO_wpending(ext_bio_))+ {+ ec = asio::ssl::error::stream_truncated;+ return ec;+ }++ // SSL v2 doesn't provide a protocol-level shutdown, so an eof on the+ // underlying transport is passed through.+#if (OPENSSL_VERSION_NUMBER < 0x10100000L)+ if (SSL_version(ssl_) == SSL2_VERSION)+ return ec;+#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)++ // Otherwise, the peer should have negotiated a proper shutdown.+ if ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0)+ {+ ec = asio::ssl::error::stream_truncated;+ }++ return ec;+}++#if (OPENSSL_VERSION_NUMBER < 0x10000000L)+asio::detail::static_mutex& engine::accept_mutex()+{+ static asio::detail::static_mutex mutex = ASIO_STATIC_MUTEX_INIT;+ return mutex;+}+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)++engine::want engine::perform(int (engine::* op)(void*, std::size_t),+ void* data, std::size_t length, asio::error_code& ec,+ std::size_t* bytes_transferred)+{+ std::size_t pending_output_before = ::BIO_ctrl_pending(ext_bio_);+ ::ERR_clear_error();+ int result = (this->*op)(data, length);+ int ssl_error = ::SSL_get_error(ssl_, result);+ int sys_error = static_cast<int>(::ERR_get_error());+ std::size_t pending_output_after = ::BIO_ctrl_pending(ext_bio_);++ if (ssl_error == SSL_ERROR_SSL)+ {+ ec = asio::error_code(sys_error,+ asio::error::get_ssl_category());+ return pending_output_after > pending_output_before+ ? want_output : want_nothing;+ }++ if (ssl_error == SSL_ERROR_SYSCALL)+ {+ if (sys_error == 0)+ {+ ec = asio::ssl::error::unspecified_system_error;+ }+ else+ {+ ec = asio::error_code(sys_error,+ asio::error::get_ssl_category());+ }+ return pending_output_after > pending_output_before+ ? want_output : want_nothing;+ }++ if (result > 0 && bytes_transferred)+ *bytes_transferred = static_cast<std::size_t>(result);++ if (ssl_error == SSL_ERROR_WANT_WRITE)+ {+ ec = asio::error_code();+ return want_output_and_retry;+ }+ else if (pending_output_after > pending_output_before)+ {+ ec = asio::error_code();+ return result > 0 ? want_output : want_output_and_retry;+ }+ else if (ssl_error == SSL_ERROR_WANT_READ)+ {+ ec = asio::error_code();+ return want_input_and_retry;+ }+ else if (ssl_error == SSL_ERROR_ZERO_RETURN)+ {+ ec = asio::error::eof;+ return want_nothing;+ }+ else if (ssl_error == SSL_ERROR_NONE)+ {+ ec = asio::error_code();+ return want_nothing;+ }+ else+ {+ ec = asio::ssl::error::unexpected_result;+ return want_nothing;+ }+}++int engine::do_accept(void*, std::size_t)+{+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)+ asio::detail::static_mutex::scoped_lock lock(accept_mutex());+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)+ return ::SSL_accept(ssl_);+}++int engine::do_connect(void*, std::size_t)+{+ return ::SSL_connect(ssl_);+}++int engine::do_shutdown(void*, std::size_t)+{+ int result = ::SSL_shutdown(ssl_);+ if (result == 0)+ result = ::SSL_shutdown(ssl_);+ return result;+}++int engine::do_read(void* data, std::size_t length)+{+ return ::SSL_read(ssl_, data,+ length < INT_MAX ? static_cast<int>(length) : INT_MAX);+}++int engine::do_write(void* data, std::size_t length)+{+ return ::SSL_write(ssl_, data,+ length < INT_MAX ? static_cast<int>(length) : INT_MAX);+}++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_DETAIL_IMPL_ENGINE_IPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/impl/openssl_init.ipp view
@@ -0,0 +1,165 @@+//+// ssl/detail/impl/openssl_init.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com+// Copyright (c) 2005-2020 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_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP+#define ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <vector>+#include "asio/detail/assert.hpp"+#include "asio/detail/mutex.hpp"+#include "asio/detail/tss_ptr.hpp"+#include "asio/ssl/detail/openssl_init.hpp"+#include "asio/ssl/detail/openssl_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++class openssl_init_base::do_init+{+public:+ do_init()+ {+#if (OPENSSL_VERSION_NUMBER < 0x10100000L)+ ::SSL_library_init();+ ::SSL_load_error_strings(); + ::OpenSSL_add_all_algorithms();++ mutexes_.resize(::CRYPTO_num_locks());+ for (size_t i = 0; i < mutexes_.size(); ++i)+ mutexes_[i].reset(new asio::detail::mutex);+ ::CRYPTO_set_locking_callback(&do_init::openssl_locking_func);+#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)+ ::CRYPTO_set_id_callback(&do_init::openssl_id_func);+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)++#if !defined(SSL_OP_NO_COMPRESSION) \+ && (OPENSSL_VERSION_NUMBER >= 0x00908000L)+ null_compression_methods_ = sk_SSL_COMP_new_null();+#endif // !defined(SSL_OP_NO_COMPRESSION)+ // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)+ }++ ~do_init()+ {+#if !defined(SSL_OP_NO_COMPRESSION) \+ && (OPENSSL_VERSION_NUMBER >= 0x00908000L)+ sk_SSL_COMP_free(null_compression_methods_);+#endif // !defined(SSL_OP_NO_COMPRESSION)+ // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)++#if (OPENSSL_VERSION_NUMBER < 0x10000000L)+ ::CRYPTO_set_id_callback(0);+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)+#if (OPENSSL_VERSION_NUMBER < 0x10100000L)+ ::CRYPTO_set_locking_callback(0);+ ::ERR_free_strings();+ ::EVP_cleanup();+ ::CRYPTO_cleanup_all_ex_data();+#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)+ ::ERR_remove_state(0);+#elif (OPENSSL_VERSION_NUMBER < 0x10100000L)+ ::ERR_remove_thread_state(NULL);+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) \+ && (OPENSSL_VERSION_NUMBER < 0x10100000L) \+ && !defined(SSL_OP_NO_COMPRESSION)+ ::SSL_COMP_free_compression_methods();+#endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L)+ // && (OPENSSL_VERSION_NUMBER < 0x10100000L)+ // && !defined(SSL_OP_NO_COMPRESSION)+#if !defined(OPENSSL_IS_BORINGSSL) && !defined(ASIO_USE_WOLFSSL)+ ::CONF_modules_unload(1);+#endif // !defined(OPENSSL_IS_BORINGSSL) && !defined(ASIO_USE_WOLFSSL)+#if !defined(OPENSSL_NO_ENGINE) \+ && (OPENSSL_VERSION_NUMBER < 0x10100000L)+ ::ENGINE_cleanup();+#endif // !defined(OPENSSL_NO_ENGINE)+ // && (OPENSSL_VERSION_NUMBER < 0x10100000L)+ }++#if !defined(SSL_OP_NO_COMPRESSION) \+ && (OPENSSL_VERSION_NUMBER >= 0x00908000L)+ STACK_OF(SSL_COMP)* get_null_compression_methods() const+ {+ return null_compression_methods_;+ }+#endif // !defined(SSL_OP_NO_COMPRESSION)+ // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)++private:+#if (OPENSSL_VERSION_NUMBER < 0x10000000L)+ static unsigned long openssl_id_func()+ {+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ return ::GetCurrentThreadId();+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ void* id = &errno;+ ASIO_ASSERT(sizeof(unsigned long) >= sizeof(void*));+ return reinterpret_cast<unsigned long>(id);+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)+ }+#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L)++#if (OPENSSL_VERSION_NUMBER < 0x10100000L)+ static void openssl_locking_func(int mode, int n, + const char* /*file*/, int /*line*/)+ {+ if (mode & CRYPTO_LOCK)+ instance()->mutexes_[n]->lock();+ else+ instance()->mutexes_[n]->unlock();+ }++ // Mutexes to be used in locking callbacks.+ std::vector<asio::detail::shared_ptr<+ asio::detail::mutex> > mutexes_;+#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)++#if !defined(SSL_OP_NO_COMPRESSION) \+ && (OPENSSL_VERSION_NUMBER >= 0x00908000L)+ STACK_OF(SSL_COMP)* null_compression_methods_;+#endif // !defined(SSL_OP_NO_COMPRESSION)+ // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)+};++asio::detail::shared_ptr<openssl_init_base::do_init>+openssl_init_base::instance()+{+ static asio::detail::shared_ptr<do_init> init(new do_init);+ return init;+}++#if !defined(SSL_OP_NO_COMPRESSION) \+ && (OPENSSL_VERSION_NUMBER >= 0x00908000L)+STACK_OF(SSL_COMP)* openssl_init_base::get_null_compression_methods()+{+ return instance()->get_null_compression_methods();+}+#endif // !defined(SSL_OP_NO_COMPRESSION)+ // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/io.hpp view
@@ -0,0 +1,415 @@+//+// ssl/detail/io.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_IO_HPP+#define ASIO_SSL_DETAIL_IO_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_tracking.hpp"+#include "asio/ssl/detail/engine.hpp"+#include "asio/ssl/detail/stream_core.hpp"+#include "asio/write.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++template <typename Stream, typename Operation>+std::size_t io(Stream& next_layer, stream_core& core,+ const Operation& op, asio::error_code& ec)+{+ asio::error_code io_ec;+ std::size_t bytes_transferred = 0;+ do switch (op(core.engine_, ec, bytes_transferred))+ {+ case engine::want_input_and_retry:++ // If the input buffer is empty then we need to read some more data from+ // the underlying transport.+ if (core.input_.size() == 0)+ {+ core.input_ = asio::buffer(core.input_buffer_,+ next_layer.read_some(core.input_buffer_, io_ec));+ if (!ec)+ ec = io_ec;+ }++ // Pass the new input data to the engine.+ core.input_ = core.engine_.put_input(core.input_);++ // Try the operation again.+ continue;++ case engine::want_output_and_retry:++ // Get output data from the engine and write it to the underlying+ // transport.+ asio::write(next_layer,+ core.engine_.get_output(core.output_buffer_), io_ec);+ if (!ec)+ ec = io_ec;++ // Try the operation again.+ continue;++ case engine::want_output:++ // Get output data from the engine and write it to the underlying+ // transport.+ asio::write(next_layer,+ core.engine_.get_output(core.output_buffer_), io_ec);+ if (!ec)+ ec = io_ec;++ // Operation is complete. Return result to caller.+ core.engine_.map_error_code(ec);+ return bytes_transferred;++ default:++ // Operation is complete. Return result to caller.+ core.engine_.map_error_code(ec);+ return bytes_transferred;++ } while (!ec);++ // Operation failed. Return result to caller.+ core.engine_.map_error_code(ec);+ return 0;+}++template <typename Stream, typename Operation, typename Handler>+class io_op+{+public:+ io_op(Stream& next_layer, stream_core& core,+ const Operation& op, Handler& handler)+ : next_layer_(next_layer),+ core_(core),+ op_(op),+ start_(0),+ want_(engine::want_nothing),+ bytes_transferred_(0),+ handler_(ASIO_MOVE_CAST(Handler)(handler))+ {+ }++#if defined(ASIO_HAS_MOVE)+ io_op(const io_op& other)+ : next_layer_(other.next_layer_),+ core_(other.core_),+ op_(other.op_),+ start_(other.start_),+ want_(other.want_),+ ec_(other.ec_),+ bytes_transferred_(other.bytes_transferred_),+ handler_(other.handler_)+ {+ }++ io_op(io_op&& other)+ : next_layer_(other.next_layer_),+ core_(other.core_),+ op_(ASIO_MOVE_CAST(Operation)(other.op_)),+ start_(other.start_),+ want_(other.want_),+ ec_(other.ec_),+ bytes_transferred_(other.bytes_transferred_),+ handler_(ASIO_MOVE_CAST(Handler)(other.handler_))+ {+ }+#endif // defined(ASIO_HAS_MOVE)++ void operator()(asio::error_code ec,+ std::size_t bytes_transferred = ~std::size_t(0), int start = 0)+ {+ switch (start_ = start)+ {+ case 1: // Called after at least one async operation.+ do+ {+ switch (want_ = op_(core_.engine_, ec_, bytes_transferred_))+ {+ case engine::want_input_and_retry:++ // If the input buffer already has data in it we can pass it to the+ // engine and then retry the operation immediately.+ if (core_.input_.size() != 0)+ {+ core_.input_ = core_.engine_.put_input(core_.input_);+ continue;+ }++ // The engine wants more data to be read from input. However, we+ // cannot allow more than one read operation at a time on the+ // underlying transport. The pending_read_ timer's expiry is set to+ // pos_infin if a read is in progress, and neg_infin otherwise.+ if (core_.expiry(core_.pending_read_) == core_.neg_infin())+ {+ // Prevent other read operations from being started.+ core_.pending_read_.expires_at(core_.pos_infin());++ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, Operation::tracking_name()));++ // Start reading some data from the underlying transport.+ next_layer_.async_read_some(+ asio::buffer(core_.input_buffer_),+ ASIO_MOVE_CAST(io_op)(*this));+ }+ else+ {+ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, Operation::tracking_name()));++ // Wait until the current read operation completes.+ core_.pending_read_.async_wait(ASIO_MOVE_CAST(io_op)(*this));+ }++ // Yield control until asynchronous operation completes. Control+ // resumes at the "default:" label below.+ return;++ case engine::want_output_and_retry:+ case engine::want_output:++ // The engine wants some data to be written to the output. However, we+ // cannot allow more than one write operation at a time on the+ // underlying transport. The pending_write_ timer's expiry is set to+ // pos_infin if a write is in progress, and neg_infin otherwise.+ if (core_.expiry(core_.pending_write_) == core_.neg_infin())+ {+ // Prevent other write operations from being started.+ core_.pending_write_.expires_at(core_.pos_infin());++ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, Operation::tracking_name()));++ // Start writing all the data to the underlying transport.+ asio::async_write(next_layer_,+ core_.engine_.get_output(core_.output_buffer_),+ ASIO_MOVE_CAST(io_op)(*this));+ }+ else+ {+ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, Operation::tracking_name()));++ // Wait until the current write operation completes.+ core_.pending_write_.async_wait(ASIO_MOVE_CAST(io_op)(*this));+ }++ // Yield control until asynchronous operation completes. Control+ // resumes at the "default:" label below.+ return;++ default:++ // The SSL operation is done and we can invoke the handler, but we+ // have to keep in mind that this function might be being called from+ // the async operation's initiating function. In this case we're not+ // allowed to call the handler directly. Instead, issue a zero-sized+ // read so the handler runs "as-if" posted using io_context::post().+ if (start)+ {+ ASIO_HANDLER_LOCATION((+ __FILE__, __LINE__, Operation::tracking_name()));++ next_layer_.async_read_some(+ asio::buffer(core_.input_buffer_, 0),+ ASIO_MOVE_CAST(io_op)(*this));++ // Yield control until asynchronous operation completes. Control+ // resumes at the "default:" label below.+ return;+ }+ else+ {+ // Continue on to run handler directly.+ break;+ }+ }++ default:+ if (bytes_transferred == ~std::size_t(0))+ bytes_transferred = 0; // Timer cancellation, no data transferred.+ else if (!ec_)+ ec_ = ec;++ switch (want_)+ {+ case engine::want_input_and_retry:++ // Add received data to the engine's input.+ core_.input_ = asio::buffer(+ core_.input_buffer_, bytes_transferred);+ core_.input_ = core_.engine_.put_input(core_.input_);++ // Release any waiting read operations.+ core_.pending_read_.expires_at(core_.neg_infin());++ // Try the operation again.+ continue;++ case engine::want_output_and_retry:++ // Release any waiting write operations.+ core_.pending_write_.expires_at(core_.neg_infin());++ // Try the operation again.+ continue;++ case engine::want_output:++ // Release any waiting write operations.+ core_.pending_write_.expires_at(core_.neg_infin());++ // Fall through to call handler.++ default:++ // Pass the result to the handler.+ op_.call_handler(handler_,+ core_.engine_.map_error_code(ec_),+ ec_ ? 0 : bytes_transferred_);++ // Our work here is done.+ return;+ }+ } while (!ec_);++ // Operation failed. Pass the result to the handler.+ op_.call_handler(handler_, core_.engine_.map_error_code(ec_), 0);+ }+ }++//private:+ Stream& next_layer_;+ stream_core& core_;+ Operation op_;+ int start_;+ engine::want want_;+ asio::error_code ec_;+ std::size_t bytes_transferred_;+ Handler handler_;+};++template <typename Stream, typename Operation, typename Handler>+inline asio_handler_allocate_is_deprecated+asio_handler_allocate(std::size_t size,+ io_op<Stream, Operation, Handler>* this_handler)+{+#if defined(ASIO_NO_DEPRECATED)+ asio_handler_alloc_helpers::allocate(size, this_handler->handler_);+ return asio_handler_allocate_is_no_longer_used();+#else // defined(ASIO_NO_DEPRECATED)+ return asio_handler_alloc_helpers::allocate(+ size, this_handler->handler_);+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Stream, typename Operation, typename Handler>+inline asio_handler_deallocate_is_deprecated+asio_handler_deallocate(void* pointer, std::size_t size,+ io_op<Stream, Operation, Handler>* this_handler)+{+ asio_handler_alloc_helpers::deallocate(+ pointer, size, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_deallocate_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Stream, typename Operation, typename Handler>+inline bool asio_handler_is_continuation(+ io_op<Stream, Operation, Handler>* this_handler)+{+ return this_handler->start_ == 0 ? true+ : asio_handler_cont_helpers::is_continuation(this_handler->handler_);+}++template <typename Function, typename Stream,+ typename Operation, typename Handler>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(Function& function,+ io_op<Stream, Operation, Handler>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Function, typename Stream,+ typename Operation, typename Handler>+inline asio_handler_invoke_is_deprecated+asio_handler_invoke(const Function& function,+ io_op<Stream, Operation, Handler>* this_handler)+{+ asio_handler_invoke_helpers::invoke(+ function, this_handler->handler_);+#if defined(ASIO_NO_DEPRECATED)+ return asio_handler_invoke_is_no_longer_used();+#endif // defined(ASIO_NO_DEPRECATED)+}++template <typename Stream, typename Operation, typename Handler>+inline void async_io(Stream& next_layer, stream_core& core,+ const Operation& op, Handler& handler)+{+ io_op<Stream, Operation, Handler>(+ next_layer, core, op, handler)(+ asio::error_code(), 0, 1);+}++} // namespace detail+} // namespace ssl++template <typename Stream, typename Operation,+ typename Handler, typename Allocator>+struct associated_allocator<+ ssl::detail::io_op<Stream, Operation, Handler>, Allocator>+{+ typedef typename associated_allocator<Handler, Allocator>::type type;++ static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h,+ const Allocator& a = Allocator()) ASIO_NOEXCEPT+ {+ return associated_allocator<Handler, Allocator>::get(h.handler_, a);+ }+};++template <typename Stream, typename Operation,+ typename Handler, typename Executor>+struct associated_executor<+ ssl::detail::io_op<Stream, Operation, Handler>, Executor>+{+ typedef typename associated_executor<Handler, Executor>::type type;++ static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h,+ const Executor& ex = Executor()) ASIO_NOEXCEPT+ {+ return associated_executor<Handler, Executor>::get(h.handler_, ex);+ }+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_DETAIL_IO_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/openssl_init.hpp view
@@ -0,0 +1,101 @@+//+// ssl/detail/openssl_init.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_OPENSSL_INIT_HPP+#define ASIO_SSL_DETAIL_OPENSSL_INIT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstring>+#include "asio/detail/memory.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/ssl/detail/openssl_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++class openssl_init_base+ : private noncopyable+{+protected:+ // Class that performs the actual initialisation.+ class do_init;++ // Helper function to manage a do_init singleton. The static instance of the+ // openssl_init object ensures that this function is always called before+ // main, and therefore before any other threads can get started. The do_init+ // instance must be static in this function to ensure that it gets+ // initialised before any other global objects try to use it.+ ASIO_DECL static asio::detail::shared_ptr<do_init> instance();++#if !defined(SSL_OP_NO_COMPRESSION) \+ && (OPENSSL_VERSION_NUMBER >= 0x00908000L)+ // Get an empty stack of compression methods, to be used when disabling+ // compression.+ ASIO_DECL static STACK_OF(SSL_COMP)* get_null_compression_methods();+#endif // !defined(SSL_OP_NO_COMPRESSION)+ // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)+};++template <bool Do_Init = true>+class openssl_init : private openssl_init_base+{+public:+ // Constructor.+ openssl_init()+ : ref_(instance())+ {+ using namespace std; // For memmove.++ // Ensure openssl_init::instance_ is linked in.+ openssl_init* tmp = &instance_;+ memmove(&tmp, &tmp, sizeof(openssl_init*));+ }++ // Destructor.+ ~openssl_init()+ {+ }++#if !defined(SSL_OP_NO_COMPRESSION) \+ && (OPENSSL_VERSION_NUMBER >= 0x00908000L)+ using openssl_init_base::get_null_compression_methods;+#endif // !defined(SSL_OP_NO_COMPRESSION)+ // && (OPENSSL_VERSION_NUMBER >= 0x00908000L)++private:+ // Instance to force initialisation of openssl at global scope.+ static openssl_init instance_;++ // Reference to singleton do_init object to ensure that openssl does not get+ // cleaned up until the last user has finished with it.+ asio::detail::shared_ptr<do_init> ref_;+};++template <bool Do_Init>+openssl_init<Do_Init> openssl_init<Do_Init>::instance_;++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/ssl/detail/impl/openssl_init.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_SSL_DETAIL_OPENSSL_INIT_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/openssl_types.hpp view
@@ -0,0 +1,34 @@+//+// ssl/detail/openssl_types.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_OPENSSL_TYPES_HPP+#define ASIO_SSL_DETAIL_OPENSSL_TYPES_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/socket_types.hpp"+#if defined(ASIO_USE_WOLFSSL)+# include <wolfssl/options.h>+#endif // defined(ASIO_USE_WOLFSSL)+#include <openssl/conf.h>+#include <openssl/ssl.h>+#if !defined(OPENSSL_NO_ENGINE)+# include <openssl/engine.h>+#endif // !defined(OPENSSL_NO_ENGINE)+#include <openssl/dh.h>+#include <openssl/err.h>+#include <openssl/rsa.h>+#include <openssl/x509.h>+#include <openssl/x509v3.h>++#endif // ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/password_callback.hpp view
@@ -0,0 +1,66 @@+//+// ssl/detail/password_callback.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_PASSWORD_CALLBACK_HPP+#define ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <cstddef>+#include <string>+#include "asio/ssl/context_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++class password_callback_base+{+public:+ virtual ~password_callback_base()+ {+ }++ virtual std::string call(std::size_t size,+ context_base::password_purpose purpose) = 0;+};++template <typename PasswordCallback>+class password_callback : public password_callback_base+{+public:+ explicit password_callback(PasswordCallback callback)+ : callback_(callback)+ {+ }++ virtual std::string call(std::size_t size,+ context_base::password_purpose purpose)+ {+ return callback_(size, purpose);+ }++private:+ PasswordCallback callback_;+};++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/read_op.hpp view
@@ -0,0 +1,72 @@+//+// ssl/detail/read_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_READ_OP_HPP+#define ASIO_SSL_DETAIL_READ_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/buffer_sequence_adapter.hpp"+#include "asio/ssl/detail/engine.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++template <typename MutableBufferSequence>+class read_op+{+public:+ static ASIO_CONSTEXPR const char* tracking_name()+ {+ return "ssl::stream<>::async_read_some";+ }++ read_op(const MutableBufferSequence& buffers)+ : buffers_(buffers)+ {+ }++ engine::want operator()(engine& eng,+ asio::error_code& ec,+ std::size_t& bytes_transferred) const+ {+ asio::mutable_buffer buffer =+ asio::detail::buffer_sequence_adapter<asio::mutable_buffer,+ MutableBufferSequence>::first(buffers_);++ return eng.read(buffer, ec, bytes_transferred);+ }++ template <typename Handler>+ void call_handler(Handler& handler,+ const asio::error_code& ec,+ const std::size_t& bytes_transferred) const+ {+ handler(ec, bytes_transferred);+ }++private:+ MutableBufferSequence buffers_;+};++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_DETAIL_READ_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/shutdown_op.hpp view
@@ -0,0 +1,69 @@+//+// ssl/detail/shutdown_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_SHUTDOWN_OP_HPP+#define ASIO_SSL_DETAIL_SHUTDOWN_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/ssl/detail/engine.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++class shutdown_op+{+public:+ static ASIO_CONSTEXPR const char* tracking_name()+ {+ return "ssl::stream<>::async_shutdown";+ }++ engine::want operator()(engine& eng,+ asio::error_code& ec,+ std::size_t& bytes_transferred) const+ {+ bytes_transferred = 0;+ return eng.shutdown(ec);+ }++ template <typename Handler>+ void call_handler(Handler& handler,+ const asio::error_code& ec,+ const std::size_t&) const+ {+ if (ec == asio::error::eof)+ {+ // The engine only generates an eof when the shutdown notification has+ // been received from the peer. This indicates that the shutdown has+ // completed successfully, and thus need not be passed on to the handler.+ handler(asio::error_code());+ }+ else+ {+ handler(ec);+ }+ }+};++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/stream_core.hpp view
@@ -0,0 +1,169 @@+//+// ssl/detail/stream_core.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_STREAM_CORE_HPP+#define ASIO_SSL_DETAIL_STREAM_CORE_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_BOOST_DATE_TIME)+# include "asio/deadline_timer.hpp"+#else // defined(ASIO_HAS_BOOST_DATE_TIME)+# include "asio/steady_timer.hpp"+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)+#include "asio/ssl/detail/engine.hpp"+#include "asio/buffer.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++struct stream_core+{+ // According to the OpenSSL documentation, this is the buffer size that is+ // sufficient to hold the largest possible TLS record.+ enum { max_tls_record_size = 17 * 1024 };++ template <typename Executor>+ stream_core(SSL_CTX* context, const Executor& ex)+ : engine_(context),+ pending_read_(ex),+ pending_write_(ex),+ output_buffer_space_(max_tls_record_size),+ output_buffer_(asio::buffer(output_buffer_space_)),+ input_buffer_space_(max_tls_record_size),+ input_buffer_(asio::buffer(input_buffer_space_))+ {+ pending_read_.expires_at(neg_infin());+ pending_write_.expires_at(neg_infin());+ }++#if defined(ASIO_HAS_MOVE)+ stream_core(stream_core&& other)+ : engine_(ASIO_MOVE_CAST(engine)(other.engine_)),+#if defined(ASIO_HAS_BOOST_DATE_TIME)+ pending_read_(+ ASIO_MOVE_CAST(asio::deadline_timer)(+ other.pending_read_)),+ pending_write_(+ ASIO_MOVE_CAST(asio::deadline_timer)(+ other.pending_write_)),+#else // defined(ASIO_HAS_BOOST_DATE_TIME)+ pending_read_(+ ASIO_MOVE_CAST(asio::steady_timer)(+ other.pending_read_)),+ pending_write_(+ ASIO_MOVE_CAST(asio::steady_timer)(+ other.pending_write_)),+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)+ output_buffer_space_(+ ASIO_MOVE_CAST(std::vector<unsigned char>)(+ other.output_buffer_space_)),+ output_buffer_(other.output_buffer_),+ input_buffer_space_(+ ASIO_MOVE_CAST(std::vector<unsigned char>)(+ other.input_buffer_space_)),+ input_buffer_(other.input_buffer_),+ input_(other.input_)+ {+ other.output_buffer_ = asio::mutable_buffer(0, 0);+ other.input_buffer_ = asio::mutable_buffer(0, 0);+ other.input_ = asio::const_buffer(0, 0);+ }+#endif // defined(ASIO_HAS_MOVE)++ ~stream_core()+ {+ }++ // The SSL engine.+ engine engine_;++#if defined(ASIO_HAS_BOOST_DATE_TIME)+ // Timer used for storing queued read operations.+ asio::deadline_timer pending_read_;++ // Timer used for storing queued write operations.+ asio::deadline_timer pending_write_;++ // Helper function for obtaining a time value that always fires.+ static asio::deadline_timer::time_type neg_infin()+ {+ return boost::posix_time::neg_infin;+ }++ // Helper function for obtaining a time value that never fires.+ static asio::deadline_timer::time_type pos_infin()+ {+ return boost::posix_time::pos_infin;+ }++ // Helper function to get a timer's expiry time.+ static asio::deadline_timer::time_type expiry(+ const asio::deadline_timer& timer)+ {+ return timer.expires_at();+ }+#else // defined(ASIO_HAS_BOOST_DATE_TIME)+ // Timer used for storing queued read operations.+ asio::steady_timer pending_read_;++ // Timer used for storing queued write operations.+ asio::steady_timer pending_write_;++ // Helper function for obtaining a time value that always fires.+ static asio::steady_timer::time_point neg_infin()+ {+ return (asio::steady_timer::time_point::min)();+ }++ // Helper function for obtaining a time value that never fires.+ static asio::steady_timer::time_point pos_infin()+ {+ return (asio::steady_timer::time_point::max)();+ }++ // Helper function to get a timer's expiry time.+ static asio::steady_timer::time_point expiry(+ const asio::steady_timer& timer)+ {+ return timer.expiry();+ }+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)++ // Buffer space used to prepare output intended for the transport.+ std::vector<unsigned char> output_buffer_space_;++ // A buffer that may be used to prepare output intended for the transport.+ asio::mutable_buffer output_buffer_;++ // Buffer space used to read input intended for the engine.+ std::vector<unsigned char> input_buffer_space_;++ // A buffer that may be used to read input intended for the engine.+ asio::mutable_buffer input_buffer_;++ // The buffer pointing to the engine's unconsumed input.+ asio::const_buffer input_;+};++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_DETAIL_STREAM_CORE_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/verify_callback.hpp view
@@ -0,0 +1,62 @@+//+// ssl/detail/verify_callback.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_VERIFY_CALLBACK_HPP+#define ASIO_SSL_DETAIL_VERIFY_CALLBACK_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include "asio/ssl/verify_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++class verify_callback_base+{+public:+ virtual ~verify_callback_base()+ {+ }++ virtual bool call(bool preverified, verify_context& ctx) = 0;+};++template <typename VerifyCallback>+class verify_callback : public verify_callback_base+{+public:+ explicit verify_callback(VerifyCallback callback)+ : callback_(callback)+ {+ }++ virtual bool call(bool preverified, verify_context& ctx)+ {+ return callback_(preverified, ctx);+ }++private:+ VerifyCallback callback_;+};++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_DETAIL_VERIFY_CALLBACK_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/detail/write_op.hpp view
@@ -0,0 +1,76 @@+//+// ssl/detail/write_op.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_DETAIL_WRITE_OP_HPP+#define ASIO_SSL_DETAIL_WRITE_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/buffer_sequence_adapter.hpp"+#include "asio/ssl/detail/engine.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {+namespace detail {++template <typename ConstBufferSequence>+class write_op+{+public:+ static ASIO_CONSTEXPR const char* tracking_name()+ {+ return "ssl::stream<>::async_write_some";+ }++ write_op(const ConstBufferSequence& buffers)+ : buffers_(buffers)+ {+ }++ engine::want operator()(engine& eng,+ asio::error_code& ec,+ std::size_t& bytes_transferred) const+ {+ unsigned char storage[+ asio::detail::buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::linearisation_storage_size];++ asio::const_buffer buffer =+ asio::detail::buffer_sequence_adapter<asio::const_buffer,+ ConstBufferSequence>::linearise(buffers_, asio::buffer(storage));++ return eng.write(buffer, ec, bytes_transferred);+ }++ template <typename Handler>+ void call_handler(Handler& handler,+ const asio::error_code& ec,+ const std::size_t& bytes_transferred) const+ {+ handler(ec, bytes_transferred);+ }++private:+ ConstBufferSequence buffers_;+};++} // namespace detail+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_DETAIL_WRITE_OP_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/error.hpp view
@@ -0,0 +1,125 @@+//+// ssl/error.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_ERROR_HPP+#define ASIO_SSL_ERROR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/error_code.hpp"+#include "asio/ssl/detail/openssl_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace error {++enum ssl_errors+{+ // Error numbers are those produced by openssl.+};++extern ASIO_DECL+const asio::error_category& get_ssl_category();++static const asio::error_category&+ ssl_category ASIO_UNUSED_VARIABLE+ = asio::error::get_ssl_category();++} // namespace error+namespace ssl {+namespace error {++enum stream_errors+{+#if defined(GENERATING_DOCUMENTATION)+ /// The underlying stream closed before the ssl stream gracefully shut down.+ stream_truncated,++ /// The underlying SSL library returned a system error without providing+ /// further information.+ unspecified_system_error,++ /// The underlying SSL library generated an unexpected result from a function+ /// call.+ unexpected_result+#else // defined(GENERATING_DOCUMENTATION)+# if (OPENSSL_VERSION_NUMBER < 0x10100000L) \+ && !defined(OPENSSL_IS_BORINGSSL) \+ && !defined(ASIO_USE_WOLFSSL)+ stream_truncated = ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ),+# else+ stream_truncated = 1,+# endif+ unspecified_system_error = 2,+ unexpected_result = 3+#endif // defined(GENERATING_DOCUMENTATION)+};++extern ASIO_DECL+const asio::error_category& get_stream_category();++static const asio::error_category&+ stream_category ASIO_UNUSED_VARIABLE+ = asio::ssl::error::get_stream_category();++} // namespace error+} // namespace ssl+} // namespace asio++#if defined(ASIO_HAS_STD_SYSTEM_ERROR)+namespace std {++template<> struct is_error_code_enum<asio::error::ssl_errors>+{+ static const bool value = true;+};++template<> struct is_error_code_enum<asio::ssl::error::stream_errors>+{+ static const bool value = true;+};++} // namespace std+#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)++namespace asio {+namespace error {++inline asio::error_code make_error_code(ssl_errors e)+{+ return asio::error_code(+ static_cast<int>(e), get_ssl_category());+}++} // namespace error+namespace ssl {+namespace error {++inline asio::error_code make_error_code(stream_errors e)+{+ return asio::error_code(+ static_cast<int>(e), get_stream_category());+}++} // namespace error+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/ssl/impl/error.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_SSL_ERROR_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/host_name_verification.hpp view
@@ -0,0 +1,90 @@+//+// ssl/host_name_verification.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_HOST_NAME_VERIFICATION_HPP+#define ASIO_SSL_HOST_NAME_VERIFICATION_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <string>+#include "asio/ssl/detail/openssl_types.hpp"+#include "asio/ssl/verify_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {++/// Verifies a certificate against a host_name according to the rules described+/// in RFC 6125.+/**+ * @par Example+ * The following example shows how to synchronously open a secure connection to+ * a given host name:+ * @code+ * using asio::ip::tcp;+ * namespace ssl = asio::ssl;+ * typedef ssl::stream<tcp::socket> ssl_socket;+ *+ * // Create a context that uses the default paths for finding CA certificates.+ * ssl::context ctx(ssl::context::sslv23);+ * ctx.set_default_verify_paths();+ *+ * // Open a socket and connect it to the remote host.+ * asio::io_context io_context;+ * ssl_socket sock(io_context, ctx);+ * tcp::resolver resolver(io_context);+ * tcp::resolver::query query("host.name", "https");+ * asio::connect(sock.lowest_layer(), resolver.resolve(query));+ * sock.lowest_layer().set_option(tcp::no_delay(true));+ *+ * // Perform SSL handshake and verify the remote host's certificate.+ * sock.set_verify_mode(ssl::verify_peer);+ * sock.set_verify_callback(ssl::host_name_verification("host.name"));+ * sock.handshake(ssl_socket::client);+ *+ * // ... read and write as normal ...+ * @endcode+ */+class host_name_verification+{+public:+ /// The type of the function object's result.+ typedef bool result_type;++ /// Constructor.+ explicit host_name_verification(const std::string& host)+ : host_(host)+ {+ }++ /// Perform certificate verification.+ ASIO_DECL bool operator()(bool preverified, verify_context& ctx) const;++private:+ // Helper function to check a host name against an IPv4 address+ // The host name to be checked.+ std::string host_;+};++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/ssl/impl/host_name_verification.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_SSL_HOST_NAME_VERIFICATION_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/impl/context.hpp view
@@ -0,0 +1,67 @@+//+// ssl/impl/context.hpp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com+// Copyright (c) 2005-2020 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_SSL_IMPL_CONTEXT_HPP+#define ASIO_SSL_IMPL_CONTEXT_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/throw_error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {++template <typename VerifyCallback>+void context::set_verify_callback(VerifyCallback callback)+{+ asio::error_code ec;+ this->set_verify_callback(callback, ec);+ asio::detail::throw_error(ec, "set_verify_callback");+}++template <typename VerifyCallback>+ASIO_SYNC_OP_VOID context::set_verify_callback(+ VerifyCallback callback, asio::error_code& ec)+{+ do_set_verify_callback(+ new detail::verify_callback<VerifyCallback>(callback), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++template <typename PasswordCallback>+void context::set_password_callback(PasswordCallback callback)+{+ asio::error_code ec;+ this->set_password_callback(callback, ec);+ asio::detail::throw_error(ec, "set_password_callback");+}++template <typename PasswordCallback>+ASIO_SYNC_OP_VOID context::set_password_callback(+ PasswordCallback callback, asio::error_code& ec)+{+ do_set_password_callback(+ new detail::password_callback<PasswordCallback>(callback), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_IMPL_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/impl/context.ipp view
@@ -0,0 +1,1238 @@+//+// ssl/impl/context.ipp+// ~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com+// Copyright (c) 2005-2020 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_SSL_IMPL_CONTEXT_IPP+#define ASIO_SSL_IMPL_CONTEXT_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <cstring>+#include "asio/detail/throw_error.hpp"+#include "asio/error.hpp"+#include "asio/ssl/context.hpp"+#include "asio/ssl/error.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {++struct context::bio_cleanup+{+ BIO* p;+ ~bio_cleanup() { if (p) ::BIO_free(p); }+};++struct context::x509_cleanup+{+ X509* p;+ ~x509_cleanup() { if (p) ::X509_free(p); }+};++struct context::evp_pkey_cleanup+{+ EVP_PKEY* p;+ ~evp_pkey_cleanup() { if (p) ::EVP_PKEY_free(p); }+};++struct context::rsa_cleanup+{+ RSA* p;+ ~rsa_cleanup() { if (p) ::RSA_free(p); }+};++struct context::dh_cleanup+{+ DH* p;+ ~dh_cleanup() { if (p) ::DH_free(p); }+};++context::context(context::method m)+ : handle_(0)+{+ ::ERR_clear_error();++ switch (m)+ {+ // SSL v2.+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2)+ case context::sslv2:+ case context::sslv2_client:+ case context::sslv2_server:+ asio::detail::throw_error(+ asio::error::invalid_argument, "context");+ break;+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2)+ case context::sslv2:+ handle_ = ::SSL_CTX_new(::SSLv2_method());+ break;+ case context::sslv2_client:+ handle_ = ::SSL_CTX_new(::SSLv2_client_method());+ break;+ case context::sslv2_server:+ handle_ = ::SSL_CTX_new(::SSLv2_server_method());+ break;+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2)++ // SSL v3.+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)+ case context::sslv3:+ handle_ = ::SSL_CTX_new(::TLS_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION);+ SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION);+ }+ break;+ case context::sslv3_client:+ handle_ = ::SSL_CTX_new(::TLS_client_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION);+ SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION);+ }+ break;+ case context::sslv3_server:+ handle_ = ::SSL_CTX_new(::TLS_server_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION);+ SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION);+ }+ break;+#elif defined(OPENSSL_NO_SSL3)+ case context::sslv3:+ case context::sslv3_client:+ case context::sslv3_server:+ asio::detail::throw_error(+ asio::error::invalid_argument, "context");+ break;+#else // defined(OPENSSL_NO_SSL3)+ case context::sslv3:+ handle_ = ::SSL_CTX_new(::SSLv3_method());+ break;+ case context::sslv3_client:+ handle_ = ::SSL_CTX_new(::SSLv3_client_method());+ break;+ case context::sslv3_server:+ handle_ = ::SSL_CTX_new(::SSLv3_server_method());+ break;+#endif // defined(OPENSSL_NO_SSL3)++ // TLS v1.0.+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)+ case context::tlsv1:+ handle_ = ::SSL_CTX_new(::TLS_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION);+ }+ break;+ case context::tlsv1_client:+ handle_ = ::SSL_CTX_new(::TLS_client_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION);+ }+ break;+ case context::tlsv1_server:+ handle_ = ::SSL_CTX_new(::TLS_server_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION);+ }+ break;+#elif defined(SSL_TXT_TLSV1)+ case context::tlsv1:+ handle_ = ::SSL_CTX_new(::TLSv1_method());+ break;+ case context::tlsv1_client:+ handle_ = ::SSL_CTX_new(::TLSv1_client_method());+ break;+ case context::tlsv1_server:+ handle_ = ::SSL_CTX_new(::TLSv1_server_method());+ break;+#else // defined(SSL_TXT_TLSV1)+ case context::tlsv1:+ case context::tlsv1_client:+ case context::tlsv1_server:+ asio::detail::throw_error(+ asio::error::invalid_argument, "context");+ break;+#endif // defined(SSL_TXT_TLSV1)++ // TLS v1.1.+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)+ case context::tlsv11:+ handle_ = ::SSL_CTX_new(::TLS_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION);+ }+ break;+ case context::tlsv11_client:+ handle_ = ::SSL_CTX_new(::TLS_client_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION);+ }+ break;+ case context::tlsv11_server:+ handle_ = ::SSL_CTX_new(::TLS_server_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION);+ }+ break;+#elif defined(SSL_TXT_TLSV1_1)+ case context::tlsv11:+ handle_ = ::SSL_CTX_new(::TLSv1_1_method());+ break;+ case context::tlsv11_client:+ handle_ = ::SSL_CTX_new(::TLSv1_1_client_method());+ break;+ case context::tlsv11_server:+ handle_ = ::SSL_CTX_new(::TLSv1_1_server_method());+ break;+#else // defined(SSL_TXT_TLSV1_1)+ case context::tlsv11:+ case context::tlsv11_client:+ case context::tlsv11_server:+ asio::detail::throw_error(+ asio::error::invalid_argument, "context");+ break;+#endif // defined(SSL_TXT_TLSV1_1)++ // TLS v1.2.+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)+ case context::tlsv12:+ handle_ = ::SSL_CTX_new(::TLS_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION);+ }+ break;+ case context::tlsv12_client:+ handle_ = ::SSL_CTX_new(::TLS_client_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION);+ }+ break;+ case context::tlsv12_server:+ handle_ = ::SSL_CTX_new(::TLS_server_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION);+ }+ break;+#elif defined(SSL_TXT_TLSV1_2)+ case context::tlsv12:+ handle_ = ::SSL_CTX_new(::TLSv1_2_method());+ break;+ case context::tlsv12_client:+ handle_ = ::SSL_CTX_new(::TLSv1_2_client_method());+ break;+ case context::tlsv12_server:+ handle_ = ::SSL_CTX_new(::TLSv1_2_server_method());+ break;+#else // defined(SSL_TXT_TLSV1_2)+ case context::tlsv12:+ case context::tlsv12_client:+ case context::tlsv12_server:+ asio::detail::throw_error(+ asio::error::invalid_argument, "context");+ break;+#endif // defined(SSL_TXT_TLSV1_2)++ // TLS v1.3.+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L) \+ && !defined(LIBRESSL_VERSION_NUMBER)+ case context::tlsv13:+ handle_ = ::SSL_CTX_new(::TLS_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);+ }+ break;+ case context::tlsv13_client:+ handle_ = ::SSL_CTX_new(::TLS_client_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);+ }+ break;+ case context::tlsv13_server:+ handle_ = ::SSL_CTX_new(::TLS_server_method());+ if (handle_)+ {+ SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION);+ SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION);+ }+ break;+#else // (OPENSSL_VERSION_NUMBER >= 0x10101000L)+ // && !defined(LIBRESSL_VERSION_NUMBER)+ case context::tlsv13:+ case context::tlsv13_client:+ case context::tlsv13_server:+ asio::detail::throw_error(+ asio::error::invalid_argument, "context");+ break;+#endif // (OPENSSL_VERSION_NUMBER >= 0x10101000L)+ // && !defined(LIBRESSL_VERSION_NUMBER)++ // Any supported SSL/TLS version.+ case context::sslv23:+ handle_ = ::SSL_CTX_new(::SSLv23_method());+ break;+ case context::sslv23_client:+ handle_ = ::SSL_CTX_new(::SSLv23_client_method());+ break;+ case context::sslv23_server:+ handle_ = ::SSL_CTX_new(::SSLv23_server_method());+ break;++ // Any supported TLS version.+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)+ case context::tls:+ handle_ = ::SSL_CTX_new(::TLS_method());+ if (handle_)+ SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);+ break;+ case context::tls_client:+ handle_ = ::SSL_CTX_new(::TLS_client_method());+ if (handle_)+ SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);+ break;+ case context::tls_server:+ handle_ = ::SSL_CTX_new(::TLS_server_method());+ if (handle_)+ SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION);+ break;+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)+ case context::tls:+ handle_ = ::SSL_CTX_new(::SSLv23_method());+ if (handle_)+ SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);+ break;+ case context::tls_client:+ handle_ = ::SSL_CTX_new(::SSLv23_client_method());+ if (handle_)+ SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);+ break;+ case context::tls_server:+ handle_ = ::SSL_CTX_new(::SSLv23_server_method());+ if (handle_)+ SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);+ break;+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)++ default:+ handle_ = ::SSL_CTX_new(0);+ break;+ }++ if (handle_ == 0)+ {+ asio::error_code ec(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ asio::detail::throw_error(ec, "context");+ }++ set_options(no_compression);+}++context::context(context::native_handle_type native_handle)+ : handle_(native_handle)+{+ if (!handle_)+ {+ asio::detail::throw_error(+ asio::error::invalid_argument, "context");+ }+}++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+context::context(context&& other)+{+ handle_ = other.handle_;+ other.handle_ = 0;+}++context& context::operator=(context&& other)+{+ context tmp(ASIO_MOVE_CAST(context)(*this));+ handle_ = other.handle_;+ other.handle_ = 0;+ return *this;+}+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++context::~context()+{+ if (handle_)+ {+#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \+ && !defined(LIBRESSL_VERSION_NUMBER)) \+ || defined(ASIO_USE_WOLFSSL)+ void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)+ void* cb_userdata = handle_->default_passwd_callback_userdata;+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)+ if (cb_userdata)+ {+ detail::password_callback_base* callback =+ static_cast<detail::password_callback_base*>(+ cb_userdata);+ delete callback;+#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \+ && !defined(LIBRESSL_VERSION_NUMBER)) \+ || defined(ASIO_USE_WOLFSSL)+ ::SSL_CTX_set_default_passwd_cb_userdata(handle_, 0);+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)+ handle_->default_passwd_callback_userdata = 0;+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)+ }++ if (SSL_CTX_get_app_data(handle_))+ {+ detail::verify_callback_base* callback =+ static_cast<detail::verify_callback_base*>(+ SSL_CTX_get_app_data(handle_));+ delete callback;+ SSL_CTX_set_app_data(handle_, 0);+ }++ ::SSL_CTX_free(handle_);+ }+}++context::native_handle_type context::native_handle()+{+ return handle_;+}++void context::clear_options(context::options o)+{+ asio::error_code ec;+ clear_options(o, ec);+ asio::detail::throw_error(ec, "clear_options");+}++ASIO_SYNC_OP_VOID context::clear_options(+ context::options o, asio::error_code& ec)+{+#if (OPENSSL_VERSION_NUMBER >= 0x009080DFL) \+ && (OPENSSL_VERSION_NUMBER != 0x00909000L)+# if !defined(SSL_OP_NO_COMPRESSION)+ if ((o & context::no_compression) != 0)+ {+# if (OPENSSL_VERSION_NUMBER >= 0x00908000L)+ handle_->comp_methods = SSL_COMP_get_compression_methods();+# endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L)+ o ^= context::no_compression;+ }+# endif // !defined(SSL_OP_NO_COMPRESSION)++ ::SSL_CTX_clear_options(handle_, o);++ ec = asio::error_code();+#else // (OPENSSL_VERSION_NUMBER >= 0x009080DFL)+ // && (OPENSSL_VERSION_NUMBER != 0x00909000L)+ (void)o;+ ec = asio::error::operation_not_supported;+#endif // (OPENSSL_VERSION_NUMBER >= 0x009080DFL)+ // && (OPENSSL_VERSION_NUMBER != 0x00909000L)+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::set_options(context::options o)+{+ asio::error_code ec;+ set_options(o, ec);+ asio::detail::throw_error(ec, "set_options");+}++ASIO_SYNC_OP_VOID context::set_options(+ context::options o, asio::error_code& ec)+{+#if !defined(SSL_OP_NO_COMPRESSION)+ if ((o & context::no_compression) != 0)+ {+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)+ handle_->comp_methods =+ asio::ssl::detail::openssl_init<>::get_null_compression_methods();+#endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L)+ o ^= context::no_compression;+ }+#endif // !defined(SSL_OP_NO_COMPRESSION)++ ::SSL_CTX_set_options(handle_, o);++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::set_verify_mode(verify_mode v)+{+ asio::error_code ec;+ set_verify_mode(v, ec);+ asio::detail::throw_error(ec, "set_verify_mode");+}++ASIO_SYNC_OP_VOID context::set_verify_mode(+ verify_mode v, asio::error_code& ec)+{+ ::SSL_CTX_set_verify(handle_, v, ::SSL_CTX_get_verify_callback(handle_));++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::set_verify_depth(int depth)+{+ asio::error_code ec;+ set_verify_depth(depth, ec);+ asio::detail::throw_error(ec, "set_verify_depth");+}++ASIO_SYNC_OP_VOID context::set_verify_depth(+ int depth, asio::error_code& ec)+{+ ::SSL_CTX_set_verify_depth(handle_, depth);++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::load_verify_file(const std::string& filename)+{+ asio::error_code ec;+ load_verify_file(filename, ec);+ asio::detail::throw_error(ec, "load_verify_file");+}++ASIO_SYNC_OP_VOID context::load_verify_file(+ const std::string& filename, asio::error_code& ec)+{+ ::ERR_clear_error();++ if (::SSL_CTX_load_verify_locations(handle_, filename.c_str(), 0) != 1)+ {+ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::add_certificate_authority(const const_buffer& ca)+{+ asio::error_code ec;+ add_certificate_authority(ca, ec);+ asio::detail::throw_error(ec, "add_certificate_authority");+}++ASIO_SYNC_OP_VOID context::add_certificate_authority(+ const const_buffer& ca, asio::error_code& ec)+{+ ::ERR_clear_error();++ bio_cleanup bio = { make_buffer_bio(ca) };+ if (bio.p)+ {+ if (X509_STORE* store = ::SSL_CTX_get_cert_store(handle_))+ {+ for (bool added = false;; added = true)+ {+ x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) };+ if (!cert.p)+ {+ unsigned long err = ::ERR_get_error();+ if (added && ERR_GET_LIB(err) == ERR_LIB_PEM+ && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)+ break;++ ec = asio::error_code(+ static_cast<int>(err),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ if (::X509_STORE_add_cert(store, cert.p) != 1)+ {+ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }+ }+ }++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::set_default_verify_paths()+{+ asio::error_code ec;+ set_default_verify_paths(ec);+ asio::detail::throw_error(ec, "set_default_verify_paths");+}++ASIO_SYNC_OP_VOID context::set_default_verify_paths(+ asio::error_code& ec)+{+ ::ERR_clear_error();++ if (::SSL_CTX_set_default_verify_paths(handle_) != 1)+ {+ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::add_verify_path(const std::string& path)+{+ asio::error_code ec;+ add_verify_path(path, ec);+ asio::detail::throw_error(ec, "add_verify_path");+}++ASIO_SYNC_OP_VOID context::add_verify_path(+ const std::string& path, asio::error_code& ec)+{+ ::ERR_clear_error();++ if (::SSL_CTX_load_verify_locations(handle_, 0, path.c_str()) != 1)+ {+ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::use_certificate(+ const const_buffer& certificate, file_format format)+{+ asio::error_code ec;+ use_certificate(certificate, format, ec);+ asio::detail::throw_error(ec, "use_certificate");+}++ASIO_SYNC_OP_VOID context::use_certificate(+ const const_buffer& certificate, file_format format,+ asio::error_code& ec)+{+ ::ERR_clear_error();++ if (format == context_base::asn1)+ {+ if (::SSL_CTX_use_certificate_ASN1(handle_,+ static_cast<int>(certificate.size()),+ static_cast<const unsigned char*>(certificate.data())) == 1)+ {+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }+ else if (format == context_base::pem)+ {+ bio_cleanup bio = { make_buffer_bio(certificate) };+ if (bio.p)+ {+ x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) };+ if (cert.p)+ {+ if (::SSL_CTX_use_certificate(handle_, cert.p) == 1)+ {+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }+ }+ }+ else+ {+ ec = asio::error::invalid_argument;+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::use_certificate_file(+ const std::string& filename, file_format format)+{+ asio::error_code ec;+ use_certificate_file(filename, format, ec);+ asio::detail::throw_error(ec, "use_certificate_file");+}++ASIO_SYNC_OP_VOID context::use_certificate_file(+ const std::string& filename, file_format format,+ asio::error_code& ec)+{+ int file_type;+ switch (format)+ {+ case context_base::asn1:+ file_type = SSL_FILETYPE_ASN1;+ break;+ case context_base::pem:+ file_type = SSL_FILETYPE_PEM;+ break;+ default:+ {+ ec = asio::error::invalid_argument;+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }++ ::ERR_clear_error();++ if (::SSL_CTX_use_certificate_file(handle_, filename.c_str(), file_type) != 1)+ {+ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::use_certificate_chain(const const_buffer& chain)+{+ asio::error_code ec;+ use_certificate_chain(chain, ec);+ asio::detail::throw_error(ec, "use_certificate_chain");+}++ASIO_SYNC_OP_VOID context::use_certificate_chain(+ const const_buffer& chain, asio::error_code& ec)+{+ ::ERR_clear_error();++ bio_cleanup bio = { make_buffer_bio(chain) };+ if (bio.p)+ {+#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \+ && !defined(LIBRESSL_VERSION_NUMBER)) \+ || defined(ASIO_USE_WOLFSSL)+ pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);+ void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)+ pem_password_cb* callback = handle_->default_passwd_callback;+ void* cb_userdata = handle_->default_passwd_callback_userdata;+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)+ x509_cleanup cert = {+ ::PEM_read_bio_X509_AUX(bio.p, 0,+ callback,+ cb_userdata) };+ if (!cert.p)+ {+ ec = asio::error_code(ERR_R_PEM_LIB,+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ int result = ::SSL_CTX_use_certificate(handle_, cert.p);+ if (result == 0 || ::ERR_peek_error() != 0)+ {+ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++#if ((OPENSSL_VERSION_NUMBER >= 0x10002000L) \+ && !defined(LIBRESSL_VERSION_NUMBER)) \+ || defined(ASIO_USE_WOLFSSL)+ ::SSL_CTX_clear_chain_certs(handle_);+#else+ if (handle_->extra_certs)+ {+ ::sk_X509_pop_free(handle_->extra_certs, X509_free);+ handle_->extra_certs = 0;+ }+#endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L)++ while (X509* cacert = ::PEM_read_bio_X509(bio.p, 0,+ callback,+ cb_userdata))+ {+ if (!::SSL_CTX_add_extra_chain_cert(handle_, cacert))+ {+ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }+ + result = ::ERR_peek_last_error();+ if ((ERR_GET_LIB(result) == ERR_LIB_PEM)+ && (ERR_GET_REASON(result) == PEM_R_NO_START_LINE))+ {+ ::ERR_clear_error();+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }++ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::use_certificate_chain_file(const std::string& filename)+{+ asio::error_code ec;+ use_certificate_chain_file(filename, ec);+ asio::detail::throw_error(ec, "use_certificate_chain_file");+}++ASIO_SYNC_OP_VOID context::use_certificate_chain_file(+ const std::string& filename, asio::error_code& ec)+{+ ::ERR_clear_error();++ if (::SSL_CTX_use_certificate_chain_file(handle_, filename.c_str()) != 1)+ {+ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::use_private_key(+ const const_buffer& private_key, context::file_format format)+{+ asio::error_code ec;+ use_private_key(private_key, format, ec);+ asio::detail::throw_error(ec, "use_private_key");+}++ASIO_SYNC_OP_VOID context::use_private_key(+ const const_buffer& private_key, context::file_format format,+ asio::error_code& ec)+{+ ::ERR_clear_error();++#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \+ && !defined(LIBRESSL_VERSION_NUMBER)) \+ || defined(ASIO_USE_WOLFSSL)+ pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);+ void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)+ pem_password_cb* callback = handle_->default_passwd_callback;+ void* cb_userdata = handle_->default_passwd_callback_userdata;+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)++ bio_cleanup bio = { make_buffer_bio(private_key) };+ if (bio.p)+ {+ evp_pkey_cleanup evp_private_key = { 0 };+ switch (format)+ {+ case context_base::asn1:+ evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0);+ break;+ case context_base::pem:+ evp_private_key.p = ::PEM_read_bio_PrivateKey(+ bio.p, 0, callback,+ cb_userdata);+ break;+ default:+ {+ ec = asio::error::invalid_argument;+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }++ if (evp_private_key.p)+ {+ if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1)+ {+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }+ }++ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::use_private_key_file(+ const std::string& filename, context::file_format format)+{+ asio::error_code ec;+ use_private_key_file(filename, format, ec);+ asio::detail::throw_error(ec, "use_private_key_file");+}++void context::use_rsa_private_key(+ const const_buffer& private_key, context::file_format format)+{+ asio::error_code ec;+ use_rsa_private_key(private_key, format, ec);+ asio::detail::throw_error(ec, "use_rsa_private_key");+}++ASIO_SYNC_OP_VOID context::use_rsa_private_key(+ const const_buffer& private_key, context::file_format format,+ asio::error_code& ec)+{+ ::ERR_clear_error();++#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \+ && !defined(LIBRESSL_VERSION_NUMBER)) \+ || defined(ASIO_USE_WOLFSSL)+ pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_);+ void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)+ pem_password_cb* callback = handle_->default_passwd_callback;+ void* cb_userdata = handle_->default_passwd_callback_userdata;+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)++ bio_cleanup bio = { make_buffer_bio(private_key) };+ if (bio.p)+ {+ rsa_cleanup rsa_private_key = { 0 };+ switch (format)+ {+ case context_base::asn1:+ rsa_private_key.p = ::d2i_RSAPrivateKey_bio(bio.p, 0);+ break;+ case context_base::pem:+ rsa_private_key.p = ::PEM_read_bio_RSAPrivateKey(+ bio.p, 0, callback,+ cb_userdata);+ break;+ default:+ {+ ec = asio::error::invalid_argument;+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }++ if (rsa_private_key.p)+ {+ if (::SSL_CTX_use_RSAPrivateKey(handle_, rsa_private_key.p) == 1)+ {+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }+ }++ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++ASIO_SYNC_OP_VOID context::use_private_key_file(+ const std::string& filename, context::file_format format,+ asio::error_code& ec)+{+ int file_type;+ switch (format)+ {+ case context_base::asn1:+ file_type = SSL_FILETYPE_ASN1;+ break;+ case context_base::pem:+ file_type = SSL_FILETYPE_PEM;+ break;+ default:+ {+ ec = asio::error::invalid_argument;+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }++ ::ERR_clear_error();++ if (::SSL_CTX_use_PrivateKey_file(handle_, filename.c_str(), file_type) != 1)+ {+ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::use_rsa_private_key_file(+ const std::string& filename, context::file_format format)+{+ asio::error_code ec;+ use_rsa_private_key_file(filename, format, ec);+ asio::detail::throw_error(ec, "use_rsa_private_key_file");+}++ASIO_SYNC_OP_VOID context::use_rsa_private_key_file(+ const std::string& filename, context::file_format format,+ asio::error_code& ec)+{+ int file_type;+ switch (format)+ {+ case context_base::asn1:+ file_type = SSL_FILETYPE_ASN1;+ break;+ case context_base::pem:+ file_type = SSL_FILETYPE_PEM;+ break;+ default:+ {+ ec = asio::error::invalid_argument;+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }++ ::ERR_clear_error();++ if (::SSL_CTX_use_RSAPrivateKey_file(+ handle_, filename.c_str(), file_type) != 1)+ {+ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::use_tmp_dh(const const_buffer& dh)+{+ asio::error_code ec;+ use_tmp_dh(dh, ec);+ asio::detail::throw_error(ec, "use_tmp_dh");+}++ASIO_SYNC_OP_VOID context::use_tmp_dh(+ const const_buffer& dh, asio::error_code& ec)+{+ ::ERR_clear_error();++ bio_cleanup bio = { make_buffer_bio(dh) };+ if (bio.p)+ {+ return do_use_tmp_dh(bio.p, ec);+ }++ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++void context::use_tmp_dh_file(const std::string& filename)+{+ asio::error_code ec;+ use_tmp_dh_file(filename, ec);+ asio::detail::throw_error(ec, "use_tmp_dh_file");+}++ASIO_SYNC_OP_VOID context::use_tmp_dh_file(+ const std::string& filename, asio::error_code& ec)+{+ ::ERR_clear_error();++ bio_cleanup bio = { ::BIO_new_file(filename.c_str(), "r") };+ if (bio.p)+ {+ return do_use_tmp_dh(bio.p, ec);+ }++ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++ASIO_SYNC_OP_VOID context::do_use_tmp_dh(+ BIO* bio, asio::error_code& ec)+{+ ::ERR_clear_error();++ dh_cleanup dh = { ::PEM_read_bio_DHparams(bio, 0, 0, 0) };+ if (dh.p)+ {+ if (::SSL_CTX_set_tmp_dh(handle_, dh.p) == 1)+ {+ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }+ }++ ec = asio::error_code(+ static_cast<int>(::ERR_get_error()),+ asio::error::get_ssl_category());+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++ASIO_SYNC_OP_VOID context::do_set_verify_callback(+ detail::verify_callback_base* callback, asio::error_code& ec)+{+ if (SSL_CTX_get_app_data(handle_))+ {+ delete static_cast<detail::verify_callback_base*>(+ SSL_CTX_get_app_data(handle_));+ }++ SSL_CTX_set_app_data(handle_, callback);++ ::SSL_CTX_set_verify(handle_,+ ::SSL_CTX_get_verify_mode(handle_),+ &context::verify_callback_function);++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++int context::verify_callback_function(int preverified, X509_STORE_CTX* ctx)+{+ if (ctx)+ {+ if (SSL* ssl = static_cast<SSL*>(+ ::X509_STORE_CTX_get_ex_data(+ ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx())))+ {+ if (SSL_CTX* handle = ::SSL_get_SSL_CTX(ssl))+ {+ if (SSL_CTX_get_app_data(handle))+ {+ detail::verify_callback_base* callback =+ static_cast<detail::verify_callback_base*>(+ SSL_CTX_get_app_data(handle));++ verify_context verify_ctx(ctx);+ return callback->call(preverified != 0, verify_ctx) ? 1 : 0;+ }+ }+ }+ }++ return 0;+}++ASIO_SYNC_OP_VOID context::do_set_password_callback(+ detail::password_callback_base* callback, asio::error_code& ec)+{+#if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \+ && !defined(LIBRESSL_VERSION_NUMBER)) \+ || defined(ASIO_USE_WOLFSSL)+ void* old_callback = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);+ ::SSL_CTX_set_default_passwd_cb_userdata(handle_, callback);+#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)+ void* old_callback = handle_->default_passwd_callback_userdata;+ handle_->default_passwd_callback_userdata = callback;+#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)++ if (old_callback)+ delete static_cast<detail::password_callback_base*>(+ old_callback);++ SSL_CTX_set_default_passwd_cb(handle_, &context::password_callback_function);++ ec = asio::error_code();+ ASIO_SYNC_OP_VOID_RETURN(ec);+}++int context::password_callback_function(+ char* buf, int size, int purpose, void* data)+{+ using namespace std; // For strncat and strlen.++ if (data)+ {+ detail::password_callback_base* callback =+ static_cast<detail::password_callback_base*>(data);++ std::string passwd = callback->call(static_cast<std::size_t>(size),+ purpose ? context_base::for_writing : context_base::for_reading);++#if defined(ASIO_HAS_SECURE_RTL)+ strcpy_s(buf, size, passwd.c_str());+#else // defined(ASIO_HAS_SECURE_RTL)+ *buf = '\0';+ if (size > 0)+ strncat(buf, passwd.c_str(), size - 1);+#endif // defined(ASIO_HAS_SECURE_RTL)++ return static_cast<int>(strlen(buf));+ }++ return 0;+}++BIO* context::make_buffer_bio(const const_buffer& b)+{+ return ::BIO_new_mem_buf(+ const_cast<void*>(b.data()),+ static_cast<int>(b.size()));+}++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_IMPL_CONTEXT_IPP
+ link/modules/asio-standalone/asio/include/asio/ssl/impl/error.ipp view
@@ -0,0 +1,102 @@+//+// ssl/impl/error.ipp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_IMPL_ERROR_IPP+#define ASIO_SSL_IMPL_ERROR_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/ssl/error.hpp"+#include "asio/ssl/detail/openssl_init.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace error {+namespace detail {++class ssl_category : public asio::error_category+{+public:+ const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT+ {+ return "asio.ssl";+ }++ std::string message(int value) const+ {+ const char* s = ::ERR_reason_error_string(value);+ return s ? s : "asio.ssl error";+ }+};++} // namespace detail++const asio::error_category& get_ssl_category()+{+ static detail::ssl_category instance;+ return instance;+}++} // namespace error+namespace ssl {+namespace error {++#if (OPENSSL_VERSION_NUMBER < 0x10100000L) && !defined(OPENSSL_IS_BORINGSSL)++const asio::error_category& get_stream_category()+{+ return asio::error::get_ssl_category();+}++#else++namespace detail {++class stream_category : public asio::error_category+{+public:+ const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT+ {+ return "asio.ssl.stream";+ }++ std::string message(int value) const+ {+ switch (value)+ {+ case stream_truncated: return "stream truncated";+ case unspecified_system_error: return "unspecified system error";+ case unexpected_result: return "unexpected result";+ default: return "asio.ssl.stream error";+ }+ }+};++} // namespace detail++const asio::error_category& get_stream_category()+{+ static detail::stream_category instance;+ return instance;+}++#endif++} // namespace error+} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_IMPL_ERROR_IPP
+ link/modules/asio-standalone/asio/include/asio/ssl/impl/host_name_verification.ipp view
@@ -0,0 +1,73 @@+//+// ssl/impl/host_name_verification.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_IMPL_HOST_NAME_VERIFICATION_IPP+#define ASIO_SSL_IMPL_HOST_NAME_VERIFICATION_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include <cctype>+#include <cstring>+#include "asio/ip/address.hpp"+#include "asio/ssl/host_name_verification.hpp"+#include "asio/ssl/detail/openssl_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {++bool host_name_verification::operator()(+ bool preverified, verify_context& ctx) const+{+ using namespace std; // For memcmp.++ // Don't bother looking at certificates that have failed pre-verification.+ if (!preverified)+ return false;++ // We're only interested in checking the certificate at the end of the chain.+ int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());+ if (depth > 0)+ return true;++ // Try converting the host name to an address. If it is an address then we+ // need to look for an IP address in the certificate rather than a host name.+ asio::error_code ec;+ ip::address address = ip::make_address(host_, ec);+ const bool is_address = !ec;+ (void)address;++ X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());++ if (is_address)+ {+ return X509_check_ip_asc(cert, host_.c_str(), 0) == 1;+ }+ else+ {+ char* peername = 0;+ const int result = X509_check_host(cert,+ host_.c_str(), host_.size(), 0, &peername);+ OPENSSL_free(peername);+ return result == 1;+ }+}++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_IMPL_HOST_NAME_VERIFICATION_IPP
+ link/modules/asio-standalone/asio/include/asio/ssl/impl/rfc2818_verification.ipp view
@@ -0,0 +1,164 @@+//+// ssl/impl/rfc2818_verification.ipp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_IMPL_RFC2818_VERIFICATION_IPP+#define ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#if !defined(ASIO_NO_DEPRECATED)++#include <cctype>+#include <cstring>+#include "asio/ip/address.hpp"+#include "asio/ssl/rfc2818_verification.hpp"+#include "asio/ssl/detail/openssl_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {++bool rfc2818_verification::operator()(+ bool preverified, verify_context& ctx) const+{+ using namespace std; // For memcmp.++ // Don't bother looking at certificates that have failed pre-verification.+ if (!preverified)+ return false;++ // We're only interested in checking the certificate at the end of the chain.+ int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());+ if (depth > 0)+ return true;++ // Try converting the host name to an address. If it is an address then we+ // need to look for an IP address in the certificate rather than a host name.+ asio::error_code ec;+ ip::address address = ip::make_address(host_, ec);+ bool is_address = !ec;++ X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());++ // Go through the alternate names in the certificate looking for matching DNS+ // or IP address entries.+ GENERAL_NAMES* gens = static_cast<GENERAL_NAMES*>(+ X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0));+ for (int i = 0; i < sk_GENERAL_NAME_num(gens); ++i)+ {+ GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i);+ if (gen->type == GEN_DNS && !is_address)+ {+ ASN1_IA5STRING* domain = gen->d.dNSName;+ if (domain->type == V_ASN1_IA5STRING && domain->data && domain->length)+ {+ const char* pattern = reinterpret_cast<const char*>(domain->data);+ std::size_t pattern_length = domain->length;+ if (match_pattern(pattern, pattern_length, host_.c_str()))+ {+ GENERAL_NAMES_free(gens);+ return true;+ }+ }+ }+ else if (gen->type == GEN_IPADD && is_address)+ {+ ASN1_OCTET_STRING* ip_address = gen->d.iPAddress;+ if (ip_address->type == V_ASN1_OCTET_STRING && ip_address->data)+ {+ if (address.is_v4() && ip_address->length == 4)+ {+ ip::address_v4::bytes_type bytes = address.to_v4().to_bytes();+ if (memcmp(bytes.data(), ip_address->data, 4) == 0)+ {+ GENERAL_NAMES_free(gens);+ return true;+ }+ }+ else if (address.is_v6() && ip_address->length == 16)+ {+ ip::address_v6::bytes_type bytes = address.to_v6().to_bytes();+ if (memcmp(bytes.data(), ip_address->data, 16) == 0)+ {+ GENERAL_NAMES_free(gens);+ return true;+ }+ }+ }+ }+ }+ GENERAL_NAMES_free(gens);++ // No match in the alternate names, so try the common names. We should only+ // use the "most specific" common name, which is the last one in the list.+ X509_NAME* name = X509_get_subject_name(cert);+ int i = -1;+ ASN1_STRING* common_name = 0;+ while ((i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0)+ {+ X509_NAME_ENTRY* name_entry = X509_NAME_get_entry(name, i);+ common_name = X509_NAME_ENTRY_get_data(name_entry);+ }+ if (common_name && common_name->data && common_name->length)+ {+ const char* pattern = reinterpret_cast<const char*>(common_name->data);+ std::size_t pattern_length = common_name->length;+ if (match_pattern(pattern, pattern_length, host_.c_str()))+ return true;+ }++ return false;+}++bool rfc2818_verification::match_pattern(const char* pattern,+ std::size_t pattern_length, const char* host)+{+ using namespace std; // For tolower.++ const char* p = pattern;+ const char* p_end = p + pattern_length;+ const char* h = host;++ while (p != p_end && *h)+ {+ if (*p == '*')+ {+ ++p;+ while (*h && *h != '.')+ if (match_pattern(p, p_end - p, h++))+ return true;+ }+ else if (tolower(*p) == tolower(*h))+ {+ ++p;+ ++h;+ }+ else+ {+ return false;+ }+ }++ return p == p_end && !*h;+}++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(ASIO_NO_DEPRECATED)++#endif // ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP
+ link/modules/asio-standalone/asio/include/asio/ssl/impl/src.hpp view
@@ -0,0 +1,29 @@+//+// impl/ssl/src.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_IMPL_SRC_HPP+#define ASIO_SSL_IMPL_SRC_HPP++#define ASIO_SOURCE++#include "asio/detail/config.hpp"++#if defined(ASIO_HEADER_ONLY)+# error Do not compile Asio library source with ASIO_HEADER_ONLY defined+#endif++#include "asio/ssl/impl/context.ipp"+#include "asio/ssl/impl/error.ipp"+#include "asio/ssl/detail/impl/engine.ipp"+#include "asio/ssl/detail/impl/openssl_init.ipp"+#include "asio/ssl/impl/host_name_verification.ipp"+#include "asio/ssl/impl/rfc2818_verification.ipp"++#endif // ASIO_SSL_IMPL_SRC_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/rfc2818_verification.hpp view
@@ -0,0 +1,98 @@+//+// ssl/rfc2818_verification.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_RFC2818_VERIFICATION_HPP+#define ASIO_SSL_RFC2818_VERIFICATION_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_NO_DEPRECATED)++#include <string>+#include "asio/ssl/detail/openssl_types.hpp"+#include "asio/ssl/verify_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {++/// (Deprecated. Use ssl::host_name_verification.) Verifies a certificate+/// against a hostname according to the rules described in RFC 2818.+/**+ * @par Example+ * The following example shows how to synchronously open a secure connection to+ * a given host name:+ * @code+ * using asio::ip::tcp;+ * namespace ssl = asio::ssl;+ * typedef ssl::stream<tcp::socket> ssl_socket;+ *+ * // Create a context that uses the default paths for finding CA certificates.+ * ssl::context ctx(ssl::context::sslv23);+ * ctx.set_default_verify_paths();+ *+ * // Open a socket and connect it to the remote host.+ * asio::io_context io_context;+ * ssl_socket sock(io_context, ctx);+ * tcp::resolver resolver(io_context);+ * tcp::resolver::query query("host.name", "https");+ * asio::connect(sock.lowest_layer(), resolver.resolve(query));+ * sock.lowest_layer().set_option(tcp::no_delay(true));+ *+ * // Perform SSL handshake and verify the remote host's certificate.+ * sock.set_verify_mode(ssl::verify_peer);+ * sock.set_verify_callback(ssl::rfc2818_verification("host.name"));+ * sock.handshake(ssl_socket::client);+ *+ * // ... read and write as normal ...+ * @endcode+ */+class rfc2818_verification+{+public:+ /// The type of the function object's result.+ typedef bool result_type;++ /// Constructor.+ explicit rfc2818_verification(const std::string& host)+ : host_(host)+ {+ }++ /// Perform certificate verification.+ ASIO_DECL bool operator()(bool preverified, verify_context& ctx) const;++private:+ // Helper function to check a host name against a pattern.+ ASIO_DECL static bool match_pattern(const char* pattern,+ std::size_t pattern_length, const char* host);++ // Helper function to check a host name against an IPv4 address+ // The host name to be checked.+ std::string host_;+};++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#if defined(ASIO_HEADER_ONLY)+# include "asio/ssl/impl/rfc2818_verification.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // !defined(ASIO_NO_DEPRECATED)++#endif // ASIO_SSL_RFC2818_VERIFICATION_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/stream.hpp view
@@ -0,0 +1,900 @@+//+// ssl/stream.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_STREAM_HPP+#define ASIO_SSL_STREAM_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"++#include "asio/async_result.hpp"+#include "asio/detail/buffer_sequence_adapter.hpp"+#include "asio/detail/handler_type_requirements.hpp"+#include "asio/detail/non_const_lvalue.hpp"+#include "asio/detail/noncopyable.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/ssl/context.hpp"+#include "asio/ssl/detail/buffered_handshake_op.hpp"+#include "asio/ssl/detail/handshake_op.hpp"+#include "asio/ssl/detail/io.hpp"+#include "asio/ssl/detail/read_op.hpp"+#include "asio/ssl/detail/shutdown_op.hpp"+#include "asio/ssl/detail/stream_core.hpp"+#include "asio/ssl/detail/write_op.hpp"+#include "asio/ssl/stream_base.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {++/// Provides stream-oriented functionality using SSL.+/**+ * The stream class template provides asynchronous and blocking stream-oriented+ * functionality using SSL.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe. The application must also ensure that all+ * asynchronous operations are performed within the same implicit or explicit+ * strand.+ *+ * @par Example+ * To use the SSL stream template with an ip::tcp::socket, you would write:+ * @code+ * asio::io_context my_context;+ * asio::ssl::context ctx(asio::ssl::context::sslv23);+ * asio::ssl::stream<asio:ip::tcp::socket> sock(my_context, ctx);+ * @endcode+ *+ * @par Concepts:+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.+ */+template <typename Stream>+class stream :+ public stream_base,+ private noncopyable+{+public:+ /// The native handle type of the SSL stream.+ typedef SSL* native_handle_type;++ /// Structure for use with deprecated impl_type.+ struct impl_struct+ {+ SSL* ssl;+ };++ /// The type of the next layer.+ typedef typename remove_reference<Stream>::type next_layer_type;++ /// The type of the lowest layer.+ typedef typename next_layer_type::lowest_layer_type lowest_layer_type;++ /// The type of the executor associated with the object.+ typedef typename lowest_layer_type::executor_type executor_type;++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Construct a stream.+ /**+ * This constructor creates a stream and initialises the underlying stream+ * object.+ *+ * @param arg The argument to be passed to initialise the underlying stream.+ *+ * @param ctx The SSL context to be used for the stream.+ */+ template <typename Arg>+ stream(Arg&& arg, context& ctx)+ : next_layer_(ASIO_MOVE_CAST(Arg)(arg)),+ core_(ctx.native_handle(), next_layer_.lowest_layer().get_executor())+ {+ }+#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ template <typename Arg>+ stream(Arg& arg, context& ctx)+ : next_layer_(arg),+ core_(ctx.native_handle(), next_layer_.lowest_layer().get_executor())+ {+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a stream from another.+ /**+ * @param other The other stream object from which the move will occur. Must+ * have no outstanding asynchronous operations associated with it. Following+ * the move, @c other has a valid but unspecified state where the only safe+ * operation is destruction.+ */+ stream(stream&& other)+ : next_layer_(ASIO_MOVE_CAST(Stream)(other.next_layer_)),+ core_(ASIO_MOVE_CAST(detail::stream_core)(other.core_))+ {+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destructor.+ /**+ * @note A @c stream object must not be destroyed while there are pending+ * asynchronous operations associated with it.+ */+ ~stream()+ {+ }++ /// Get the executor associated with the object.+ /**+ * This function may be used to obtain the executor object that the stream+ * uses to dispatch handlers for asynchronous operations.+ *+ * @return A copy of the executor that stream will use to dispatch handlers.+ */+ executor_type get_executor() ASIO_NOEXCEPT+ {+ return next_layer_.lowest_layer().get_executor();+ }++ /// Get the underlying implementation in the native type.+ /**+ * This function may be used to obtain the underlying implementation of the+ * context. This is intended to allow access to context functionality that is+ * not otherwise provided.+ *+ * @par Example+ * The native_handle() function returns a pointer of type @c SSL* that is+ * suitable for passing to functions such as @c SSL_get_verify_result and+ * @c SSL_get_peer_certificate:+ * @code+ * asio::ssl::stream<asio:ip::tcp::socket> sock(my_context, ctx);+ *+ * // ... establish connection and perform handshake ...+ *+ * if (X509* cert = SSL_get_peer_certificate(sock.native_handle()))+ * {+ * if (SSL_get_verify_result(sock.native_handle()) == X509_V_OK)+ * {+ * // ...+ * }+ * }+ * @endcode+ */+ native_handle_type native_handle()+ {+ return core_.engine_.native_handle();+ }++ /// Get a reference to the next layer.+ /**+ * This function returns a reference to the next layer in a stack of stream+ * layers.+ *+ * @return A reference to the next layer in the stack of stream layers.+ * Ownership is not transferred to the caller.+ */+ const next_layer_type& next_layer() const+ {+ return next_layer_;+ }++ /// Get a reference to the next layer.+ /**+ * This function returns a reference to the next layer in a stack of stream+ * layers.+ *+ * @return A reference to the next layer in the stack of stream layers.+ * Ownership is not transferred to the caller.+ */+ next_layer_type& next_layer()+ {+ return next_layer_;+ }++ /// Get a reference to the lowest layer.+ /**+ * This function returns a reference to the lowest layer in a stack of+ * stream layers.+ *+ * @return A reference to the lowest layer in the stack of stream layers.+ * Ownership is not transferred to the caller.+ */+ lowest_layer_type& lowest_layer()+ {+ return next_layer_.lowest_layer();+ }++ /// Get a reference to the lowest layer.+ /**+ * This function returns a reference to the lowest layer in a stack of+ * stream layers.+ *+ * @return A reference to the lowest layer in the stack of stream layers.+ * Ownership is not transferred to the caller.+ */+ const lowest_layer_type& lowest_layer() const+ {+ return next_layer_.lowest_layer();+ }++ /// Set the peer verification mode.+ /**+ * This function may be used to configure the peer verification mode used by+ * the stream. The new mode will override the mode inherited from the context.+ *+ * @param v A bitmask of peer verification modes. See @ref verify_mode for+ * available values.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_set_verify.+ */+ void set_verify_mode(verify_mode v)+ {+ asio::error_code ec;+ set_verify_mode(v, ec);+ asio::detail::throw_error(ec, "set_verify_mode");+ }++ /// Set the peer verification mode.+ /**+ * This function may be used to configure the peer verification mode used by+ * the stream. The new mode will override the mode inherited from the context.+ *+ * @param v A bitmask of peer verification modes. See @ref verify_mode for+ * available values.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_set_verify.+ */+ ASIO_SYNC_OP_VOID set_verify_mode(+ verify_mode v, asio::error_code& ec)+ {+ core_.engine_.set_verify_mode(v, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Set the peer verification depth.+ /**+ * This function may be used to configure the maximum verification depth+ * allowed by the stream.+ *+ * @param depth Maximum depth for the certificate chain verification that+ * shall be allowed.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_set_verify_depth.+ */+ void set_verify_depth(int depth)+ {+ asio::error_code ec;+ set_verify_depth(depth, ec);+ asio::detail::throw_error(ec, "set_verify_depth");+ }++ /// Set the peer verification depth.+ /**+ * This function may be used to configure the maximum verification depth+ * allowed by the stream.+ *+ * @param depth Maximum depth for the certificate chain verification that+ * shall be allowed.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_set_verify_depth.+ */+ ASIO_SYNC_OP_VOID set_verify_depth(+ int depth, asio::error_code& ec)+ {+ core_.engine_.set_verify_depth(depth, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Set the callback used to verify peer certificates.+ /**+ * This function is used to specify a callback function that will be called+ * by the implementation when it needs to verify a peer certificate.+ *+ * @param callback The function object to be used for verifying a certificate.+ * The function signature of the handler must be:+ * @code bool verify_callback(+ * bool preverified, // True if the certificate passed pre-verification.+ * verify_context& ctx // The peer certificate and other context.+ * ); @endcode+ * The return value of the callback is true if the certificate has passed+ * verification, false otherwise.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note Calls @c SSL_set_verify.+ */+ template <typename VerifyCallback>+ void set_verify_callback(VerifyCallback callback)+ {+ asio::error_code ec;+ this->set_verify_callback(callback, ec);+ asio::detail::throw_error(ec, "set_verify_callback");+ }++ /// Set the callback used to verify peer certificates.+ /**+ * This function is used to specify a callback function that will be called+ * by the implementation when it needs to verify a peer certificate.+ *+ * @param callback The function object to be used for verifying a certificate.+ * The function signature of the handler must be:+ * @code bool verify_callback(+ * bool preverified, // True if the certificate passed pre-verification.+ * verify_context& ctx // The peer certificate and other context.+ * ); @endcode+ * The return value of the callback is true if the certificate has passed+ * verification, false otherwise.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @note Calls @c SSL_set_verify.+ */+ template <typename VerifyCallback>+ ASIO_SYNC_OP_VOID set_verify_callback(VerifyCallback callback,+ asio::error_code& ec)+ {+ core_.engine_.set_verify_callback(+ new detail::verify_callback<VerifyCallback>(callback), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Perform SSL handshaking.+ /**+ * This function is used to perform SSL handshaking on the stream. The+ * function call will block until handshaking is complete or an error occurs.+ *+ * @param type The type of handshaking to be performed, i.e. as a client or as+ * a server.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void handshake(handshake_type type)+ {+ asio::error_code ec;+ handshake(type, ec);+ asio::detail::throw_error(ec, "handshake");+ }++ /// Perform SSL handshaking.+ /**+ * This function is used to perform SSL handshaking on the stream. The+ * function call will block until handshaking is complete or an error occurs.+ *+ * @param type The type of handshaking to be performed, i.e. as a client or as+ * a server.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ ASIO_SYNC_OP_VOID handshake(handshake_type type,+ asio::error_code& ec)+ {+ detail::io(next_layer_, core_, detail::handshake_op(type), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Perform SSL handshaking.+ /**+ * This function is used to perform SSL handshaking on the stream. The+ * function call will block until handshaking is complete or an error occurs.+ *+ * @param type The type of handshaking to be performed, i.e. as a client or as+ * a server.+ *+ * @param buffers The buffered data to be reused for the handshake.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ConstBufferSequence>+ void handshake(handshake_type type, const ConstBufferSequence& buffers)+ {+ asio::error_code ec;+ handshake(type, buffers, ec);+ asio::detail::throw_error(ec, "handshake");+ }++ /// Perform SSL handshaking.+ /**+ * This function is used to perform SSL handshaking on the stream. The+ * function call will block until handshaking is complete or an error occurs.+ *+ * @param type The type of handshaking to be performed, i.e. as a client or as+ * a server.+ *+ * @param buffers The buffered data to be reused for the handshake.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ template <typename ConstBufferSequence>+ ASIO_SYNC_OP_VOID handshake(handshake_type type,+ const ConstBufferSequence& buffers, asio::error_code& ec)+ {+ detail::io(next_layer_, core_,+ detail::buffered_handshake_op<ConstBufferSequence>(type, buffers), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Start an asynchronous SSL handshake.+ /**+ * This function is used to asynchronously perform an SSL handshake on the+ * stream. This function call always returns immediately.+ *+ * @param type The type of handshaking to be performed, i.e. as a client or as+ * a server.+ *+ * @param handler The handler to be called when the handshake operation+ * completes. Copies will be made of the handler as required. The equivalent+ * function signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error // Result of operation.+ * ); @endcode+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))+ HandshakeHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(HandshakeHandler,+ void (asio::error_code))+ async_handshake(handshake_type type,+ ASIO_MOVE_ARG(HandshakeHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<HandshakeHandler,+ void (asio::error_code)>(+ initiate_async_handshake(this), handler, type);+ }++ /// Start an asynchronous SSL handshake.+ /**+ * This function is used to asynchronously perform an SSL handshake on the+ * stream. This function call always returns immediately.+ *+ * @param type The type of handshaking to be performed, i.e. as a client or as+ * a server.+ *+ * @param buffers The buffered data to be reused for the handshake. Although+ * the buffers object may be copied as necessary, ownership of the underlying+ * buffers is retained by the caller, which must guarantee that they remain+ * valid until the handler is called.+ *+ * @param handler The handler to be called when the handshake operation+ * completes. Copies will be made of the handler as required. The equivalent+ * function signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Amount of buffers used in handshake.+ * ); @endcode+ */+ template <typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) BufferedHandshakeHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(BufferedHandshakeHandler,+ void (asio::error_code, std::size_t))+ async_handshake(handshake_type type, const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(BufferedHandshakeHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<BufferedHandshakeHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_buffered_handshake(this), handler, type, buffers);+ }++ /// Shut down SSL on the stream.+ /**+ * This function is used to shut down SSL on the stream. The function call+ * will block until SSL has been shut down or an error occurs.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void shutdown()+ {+ asio::error_code ec;+ shutdown(ec);+ asio::detail::throw_error(ec, "shutdown");+ }++ /// Shut down SSL on the stream.+ /**+ * This function is used to shut down SSL on the stream. The function call+ * will block until SSL has been shut down or an error occurs.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ ASIO_SYNC_OP_VOID shutdown(asio::error_code& ec)+ {+ detail::io(next_layer_, core_, detail::shutdown_op(), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Asynchronously shut down SSL on the stream.+ /**+ * This function is used to asynchronously shut down SSL on the stream. This+ * function call always returns immediately.+ *+ * @param handler The handler to be called when the handshake operation+ * completes. Copies will be made of the handler as required. The equivalent+ * function signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error // Result of operation.+ * ); @endcode+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))+ ShutdownHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ShutdownHandler,+ void (asio::error_code))+ async_shutdown(+ ASIO_MOVE_ARG(ShutdownHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ShutdownHandler,+ void (asio::error_code)>(+ initiate_async_shutdown(this), handler);+ }++ /// Write some data to the stream.+ /**+ * This function is used to write data on the stream. The function call will+ * block until one or more bytes of data has been written successfully, or+ * until an error occurs.+ *+ * @param buffers The data to be written.+ *+ * @returns The number of bytes written.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @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;+ std::size_t n = write_some(buffers, ec);+ asio::detail::throw_error(ec, "write_some");+ return n;+ }++ /// Write some data to the stream.+ /**+ * This function is used to write data on the stream. The function call will+ * block until one or more bytes of data has been written successfully, or+ * until an error occurs.+ *+ * @param buffers The data to be written to the stream.+ *+ * @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 detail::io(next_layer_, core_,+ detail::write_op<ConstBufferSequence>(buffers), ec);+ }++ /// Start an asynchronous write.+ /**+ * This function is used to asynchronously write one or more bytes of data to+ * the stream. The function call always returns immediately.+ *+ * @param buffers The data to be written to the stream. Although the buffers+ * object may be copied as necessary, ownership of the underlying buffers is+ * retained by the caller, which must guarantee that they remain valid until+ * the handler is called.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The equivalent function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes written.+ * ); @endcode+ *+ * @note The async_write_some 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.+ */+ template <typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_write_some(const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_write_some(this), handler, buffers);+ }++ /// Read some data from the stream.+ /**+ * This function is used to read data from the stream. The function call will+ * block until one or more bytes of data has been read successfully, or until+ * an error occurs.+ *+ * @param buffers The buffers into which the data will be read.+ *+ * @returns The number of bytes read.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @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;+ std::size_t n = read_some(buffers, ec);+ asio::detail::throw_error(ec, "read_some");+ return n;+ }++ /// Read some data from the stream.+ /**+ * This function is used to read data from the stream. The function call will+ * block until one or more bytes of data has been read successfully, or until+ * an error occurs.+ *+ * @param buffers The 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 detail::io(next_layer_, core_,+ detail::read_op<MutableBufferSequence>(buffers), ec);+ }++ /// Start an asynchronous read.+ /**+ * This function is used to asynchronously read one or more bytes of data from+ * the stream. The function call always returns immediately.+ *+ * @param buffers The buffers into which the data will be read. Although the+ * buffers object may be copied as necessary, ownership of the underlying+ * buffers is retained by the caller, which must guarantee that they remain+ * valid until the handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The equivalent function+ * signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ * std::size_t bytes_transferred // Number of bytes read.+ * ); @endcode+ *+ * @note The async_read_some 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.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_read_some(const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_read_some(this), handler, buffers);+ }++private:+ class initiate_async_handshake+ {+ public:+ typedef typename stream::executor_type executor_type;++ explicit initiate_async_handshake(stream* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename HandshakeHandler>+ void operator()(ASIO_MOVE_ARG(HandshakeHandler) handler,+ handshake_type type) const+ {+ // If you get an error on the following line it means that your handler+ // does not meet the documented type requirements for a HandshakeHandler.+ ASIO_HANDSHAKE_HANDLER_CHECK(HandshakeHandler, handler) type_check;++ asio::detail::non_const_lvalue<HandshakeHandler> handler2(handler);+ detail::async_io(self_->next_layer_, self_->core_,+ detail::handshake_op(type), handler2.value);+ }++ private:+ stream* self_;+ };++ class initiate_async_buffered_handshake+ {+ public:+ typedef typename stream::executor_type executor_type;++ explicit initiate_async_buffered_handshake(stream* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename BufferedHandshakeHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(BufferedHandshakeHandler) handler,+ handshake_type type, 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+ // BufferedHandshakeHandler.+ ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK(+ BufferedHandshakeHandler, handler) type_check;++ asio::detail::non_const_lvalue<+ BufferedHandshakeHandler> handler2(handler);+ detail::async_io(self_->next_layer_, self_->core_,+ detail::buffered_handshake_op<ConstBufferSequence>(type, buffers),+ handler2.value);+ }++ private:+ stream* self_;+ };++ class initiate_async_shutdown+ {+ public:+ typedef typename stream::executor_type executor_type;++ explicit initiate_async_shutdown(stream* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ShutdownHandler>+ void operator()(ASIO_MOVE_ARG(ShutdownHandler) 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 ShutdownHandler.+ ASIO_HANDSHAKE_HANDLER_CHECK(ShutdownHandler, handler) type_check;++ asio::detail::non_const_lvalue<ShutdownHandler> handler2(handler);+ detail::async_io(self_->next_layer_, self_->core_,+ detail::shutdown_op(), handler2.value);+ }++ private:+ stream* self_;+ };++ class initiate_async_write_some+ {+ public:+ typedef typename stream::executor_type executor_type;++ explicit initiate_async_write_some(stream* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(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;++ asio::detail::non_const_lvalue<WriteHandler> handler2(handler);+ detail::async_io(self_->next_layer_, self_->core_,+ detail::write_op<ConstBufferSequence>(buffers), handler2.value);+ }++ private:+ stream* self_;+ };++ class initiate_async_read_some+ {+ public:+ typedef typename stream::executor_type executor_type;++ explicit initiate_async_read_some(stream* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(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::detail::non_const_lvalue<ReadHandler> handler2(handler);+ detail::async_io(self_->next_layer_, self_->core_,+ detail::read_op<MutableBufferSequence>(buffers), handler2.value);+ }++ private:+ stream* self_;+ };++ Stream next_layer_;+ detail::stream_core core_;+};++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_STREAM_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/stream_base.hpp view
@@ -0,0 +1,52 @@+//+// ssl/stream_base.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_STREAM_BASE_HPP+#define ASIO_SSL_STREAM_BASE_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 {+namespace ssl {++/// The stream_base class is used as a base for the asio::ssl::stream+/// class template so that we have a common place to define various enums.+class stream_base+{+public:+ /// Different handshake types.+ enum handshake_type+ {+ /// Perform handshaking as a client.+ client,++ /// Perform handshaking as a server.+ server+ };++protected:+ /// Protected destructor to prevent deletion through this type.+ ~stream_base()+ {+ }+};++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_STREAM_BASE_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/verify_context.hpp view
@@ -0,0 +1,67 @@+//+// ssl/verify_context.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_VERIFY_CONTEXT_HPP+#define ASIO_SSL_VERIFY_CONTEXT_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/noncopyable.hpp"+#include "asio/ssl/detail/openssl_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {++/// A simple wrapper around the X509_STORE_CTX type, used during verification of+/// a peer certificate.+/**+ * @note The verify_context does not own the underlying X509_STORE_CTX object.+ */+class verify_context+ : private noncopyable+{+public:+ /// The native handle type of the verification context.+ typedef X509_STORE_CTX* native_handle_type;++ /// Constructor.+ explicit verify_context(native_handle_type handle)+ : handle_(handle)+ {+ }++ /// Get the underlying implementation in the native type.+ /**+ * This function may be used to obtain the underlying implementation of the+ * context. This is intended to allow access to context functionality that is+ * not otherwise provided.+ */+ native_handle_type native_handle()+ {+ return handle_;+ }++private:+ // The underlying native implementation.+ native_handle_type handle_;+};++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_VERIFY_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/ssl/verify_mode.hpp view
@@ -0,0 +1,63 @@+//+// ssl/verify_mode.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SSL_VERIFY_MODE_HPP+#define ASIO_SSL_VERIFY_MODE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/ssl/detail/openssl_types.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace ssl {++/// Bitmask type for peer verification.+/**+ * Possible values are:+ *+ * @li @ref verify_none+ * @li @ref verify_peer+ * @li @ref verify_fail_if_no_peer_cert+ * @li @ref verify_client_once+ */+typedef int verify_mode;++#if defined(GENERATING_DOCUMENTATION)+/// No verification.+const int verify_none = implementation_defined;++/// Verify the peer.+const int verify_peer = implementation_defined;++/// Fail verification if the peer has no certificate. Ignored unless+/// @ref verify_peer is set.+const int verify_fail_if_no_peer_cert = implementation_defined;++/// Do not request client certificate on renegotiation. Ignored unless+/// @ref verify_peer is set.+const int verify_client_once = implementation_defined;+#else+const int verify_none = SSL_VERIFY_NONE;+const int verify_peer = SSL_VERIFY_PEER;+const int verify_fail_if_no_peer_cert = SSL_VERIFY_FAIL_IF_NO_PEER_CERT;+const int verify_client_once = SSL_VERIFY_CLIENT_ONCE;+#endif++} // namespace ssl+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SSL_VERIFY_MODE_HPP
+ link/modules/asio-standalone/asio/include/asio/static_thread_pool.hpp view
@@ -0,0 +1,31 @@+//+// static_thread_pool.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STATIC_THREAD_POOL_HPP+#define ASIO_STATIC_THREAD_POOL_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/thread_pool.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++typedef thread_pool static_thread_pool;++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_STATIC_THREAD_POOL_HPP
+ link/modules/asio-standalone/asio/include/asio/steady_timer.hpp view
@@ -0,0 +1,42 @@+//+// steady_timer.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STEADY_TIMER_HPP+#define ASIO_STEADY_TIMER_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_CHRONO) || defined(GENERATING_DOCUMENTATION)++#include "asio/basic_waitable_timer.hpp"+#include "asio/detail/chrono.hpp"++namespace asio {++/// Typedef for a timer based on the steady clock.+/**+ * This typedef uses the C++11 @c <chrono> standard library facility, if+ * available. Otherwise, it may use the Boost.Chrono library. To explicitly+ * utilise Boost.Chrono, use the basic_waitable_timer template directly:+ * @code+ * typedef basic_waitable_timer<boost::chrono::steady_clock> timer;+ * @endcode+ */+typedef basic_waitable_timer<chrono::steady_clock> steady_timer;++} // namespace asio++#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_STEADY_TIMER_HPP
+ link/modules/asio-standalone/asio/include/asio/strand.hpp view
@@ -0,0 +1,537 @@+//+// strand.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STRAND_HPP+#define ASIO_STRAND_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/strand_executor_service.hpp"+#include "asio/detail/type_traits.hpp"+#include "asio/execution/executor.hpp"+#include "asio/is_executor.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// Provides serialised function invocation for any executor type.+template <typename Executor>+class strand+{+public:+ /// The type of the underlying executor.+ typedef Executor inner_executor_type;++ /// Default constructor.+ /**+ * This constructor is only valid if the underlying executor type is default+ * constructible.+ */+ strand()+ : executor_(),+ impl_(strand::create_implementation(executor_))+ {+ }++ /// Construct a strand for the specified executor.+ template <typename Executor1>+ explicit strand(const Executor1& e,+ typename enable_if<+ conditional<+ !is_same<Executor1, strand>::value,+ is_convertible<Executor1, Executor>,+ false_type+ >::type::value+ >::type* = 0)+ : executor_(e),+ impl_(strand::create_implementation(executor_))+ {+ }++ /// Copy constructor.+ strand(const strand& other) ASIO_NOEXCEPT+ : executor_(other.executor_),+ impl_(other.impl_)+ {+ }++ /// Converting constructor.+ /**+ * This constructor is only valid if the @c OtherExecutor type is convertible+ * to @c Executor.+ */+ template <class OtherExecutor>+ strand(+ const strand<OtherExecutor>& other) ASIO_NOEXCEPT+ : executor_(other.executor_),+ impl_(other.impl_)+ {+ }++ /// Assignment operator.+ strand& operator=(const strand& other) ASIO_NOEXCEPT+ {+ executor_ = other.executor_;+ impl_ = other.impl_;+ return *this;+ }++ /// Converting assignment operator.+ /**+ * This assignment operator is only valid if the @c OtherExecutor type is+ * convertible to @c Executor.+ */+ template <class OtherExecutor>+ strand& operator=(+ const strand<OtherExecutor>& other) ASIO_NOEXCEPT+ {+ executor_ = other.executor_;+ impl_ = other.impl_;+ return *this;+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move constructor.+ strand(strand&& other) ASIO_NOEXCEPT+ : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)),+ impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_))+ {+ }++ /// Converting move constructor.+ /**+ * This constructor is only valid if the @c OtherExecutor type is convertible+ * to @c Executor.+ */+ template <class OtherExecutor>+ strand(strand<OtherExecutor>&& other) ASIO_NOEXCEPT+ : executor_(ASIO_MOVE_CAST(OtherExecutor)(other.executor_)),+ impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_))+ {+ }++ /// Move assignment operator.+ strand& operator=(strand&& other) ASIO_NOEXCEPT+ {+ executor_ = ASIO_MOVE_CAST(Executor)(other.executor_);+ impl_ = ASIO_MOVE_CAST(implementation_type)(other.impl_);+ return *this;+ }++ /// Converting move assignment operator.+ /**+ * This assignment operator is only valid if the @c OtherExecutor type is+ * convertible to @c Executor.+ */+ template <class OtherExecutor>+ strand& operator=(strand<OtherExecutor>&& other) ASIO_NOEXCEPT+ {+ executor_ = ASIO_MOVE_CAST(OtherExecutor)(other.executor_);+ impl_ = ASIO_MOVE_CAST(implementation_type)(other.impl_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destructor.+ ~strand() ASIO_NOEXCEPT+ {+ }++ /// Obtain the underlying executor.+ inner_executor_type get_inner_executor() const ASIO_NOEXCEPT+ {+ return executor_;+ }++ /// Forward a query to the underlying executor.+ /**+ * Do not call this function directly. It is intended for use with the+ * execution::execute customisation point.+ *+ * For example:+ * @code asio::strand<my_executor_type> ex = ...;+ * if (asio::query(ex, asio::execution::blocking)+ * == asio::execution::blocking.never)+ * ... @endcode+ */+ template <typename Property>+ typename enable_if<+ can_query<const Executor&, Property>::value,+ typename query_result<const Executor&, Property>::type+ >::type query(const Property& p) const+ ASIO_NOEXCEPT_IF((+ is_nothrow_query<const Executor&, Property>::value))+ {+ return asio::query(executor_, p);+ }++ /// Forward a requirement to the underlying executor.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code asio::strand<my_executor_type> ex1 = ...;+ * auto ex2 = asio::require(ex1,+ * asio::execution::blocking.never); @endcode+ */+ template <typename Property>+ typename enable_if<+ can_require<const Executor&, Property>::value,+ strand<typename decay<+ typename require_result<const Executor&, Property>::type+ >::type>+ >::type require(const Property& p) const+ ASIO_NOEXCEPT_IF((+ is_nothrow_require<const Executor&, Property>::value))+ {+ return strand<typename decay<+ typename require_result<const Executor&, Property>::type+ >::type>(asio::require(executor_, p), impl_);+ }++ /// Forward a preference to the underlying executor.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::prefer customisation point.+ *+ * For example:+ * @code asio::strand<my_executor_type> ex1 = ...;+ * auto ex2 = asio::prefer(ex1,+ * asio::execution::blocking.never); @endcode+ */+ template <typename Property>+ typename enable_if<+ can_prefer<const Executor&, Property>::value,+ strand<typename decay<+ typename prefer_result<const Executor&, Property>::type+ >::type>+ >::type prefer(const Property& p) const+ ASIO_NOEXCEPT_IF((+ is_nothrow_prefer<const Executor&, Property>::value))+ {+ return strand<typename decay<+ typename prefer_result<const Executor&, Property>::type+ >::type>(asio::prefer(executor_, p), impl_);+ }++#if !defined(ASIO_NO_TS_EXECUTORS)+ /// Obtain the underlying execution context.+ execution_context& context() const ASIO_NOEXCEPT+ {+ return executor_.context();+ }++ /// Inform the strand that it has some outstanding work to do.+ /**+ * The strand delegates this call to its underlying executor.+ */+ void on_work_started() const ASIO_NOEXCEPT+ {+ executor_.on_work_started();+ }++ /// Inform the strand that some work is no longer outstanding.+ /**+ * The strand delegates this call to its underlying executor.+ */+ void on_work_finished() const ASIO_NOEXCEPT+ {+ executor_.on_work_finished();+ }+#endif // !defined(ASIO_NO_TS_EXECUTORS)++ /// Request the strand to invoke the given function object.+ /**+ * Do not call this function directly. It is intended for use with the+ * execution::execute customisation point.+ *+ * For example:+ * @code asio::strand<my_executor_type> ex = ...;+ * execution::execute(ex, my_function_object); @endcode+ *+ * This function is used to ask the strand to execute the given function+ * object on its underlying executor. The function object will be executed+ * according to the properties of the underlying executor.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ */+ template <typename Function>+ typename enable_if<+ execution::can_execute<const Executor&, Function>::value+ >::type execute(ASIO_MOVE_ARG(Function) f) const+ {+ detail::strand_executor_service::execute(impl_,+ executor_, ASIO_MOVE_CAST(Function)(f));+ }++#if !defined(ASIO_NO_TS_EXECUTORS)+ /// Request the strand to invoke the given function object.+ /**+ * This function is used to ask the strand to execute the given function+ * object on its underlying executor. The function object will be executed+ * inside this function if the strand is not otherwise busy and if the+ * underlying executor's @c dispatch() function is also able to execute the+ * function before returning.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename Allocator>+ void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const+ {+ detail::strand_executor_service::dispatch(impl_,+ executor_, ASIO_MOVE_CAST(Function)(f), a);+ }++ /// Request the strand to invoke the given function object.+ /**+ * This function is used to ask the executor to execute the given function+ * object. The function object will never be executed inside this function.+ * Instead, it will be scheduled by the underlying executor's defer function.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename Allocator>+ void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const+ {+ detail::strand_executor_service::post(impl_,+ executor_, ASIO_MOVE_CAST(Function)(f), a);+ }++ /// Request the strand to invoke the given function object.+ /**+ * This function is used to ask the executor to execute the given function+ * object. The function object will never be executed inside this function.+ * Instead, it will be scheduled by the underlying executor's defer function.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename Allocator>+ void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const+ {+ detail::strand_executor_service::defer(impl_,+ executor_, ASIO_MOVE_CAST(Function)(f), a);+ }+#endif // !defined(ASIO_NO_TS_EXECUTORS)++ /// Determine whether the strand is running in the current thread.+ /**+ * @return @c true if the current thread is executing a function that was+ * submitted to the strand using post(), dispatch() or defer(). Otherwise+ * returns @c false.+ */+ bool running_in_this_thread() const ASIO_NOEXCEPT+ {+ return detail::strand_executor_service::running_in_this_thread(impl_);+ }++ /// Compare two strands for equality.+ /**+ * Two strands are equal if they refer to the same ordered, non-concurrent+ * state.+ */+ friend bool operator==(const strand& a, const strand& b) ASIO_NOEXCEPT+ {+ return a.impl_ == b.impl_;+ }++ /// Compare two strands for inequality.+ /**+ * Two strands are equal if they refer to the same ordered, non-concurrent+ * state.+ */+ friend bool operator!=(const strand& a, const strand& b) ASIO_NOEXCEPT+ {+ return a.impl_ != b.impl_;+ }++#if defined(GENERATING_DOCUMENTATION)+private:+#endif // defined(GENERATING_DOCUMENTATION)+ typedef detail::strand_executor_service::implementation_type+ implementation_type;++ template <typename InnerExecutor>+ static implementation_type create_implementation(const InnerExecutor& ex,+ typename enable_if<+ can_query<InnerExecutor, execution::context_t>::value+ >::type* = 0)+ {+ return use_service<detail::strand_executor_service>(+ asio::query(ex, execution::context)).create_implementation();+ }++ template <typename InnerExecutor>+ static implementation_type create_implementation(const InnerExecutor& ex,+ typename enable_if<+ !can_query<InnerExecutor, execution::context_t>::value+ >::type* = 0)+ {+ return use_service<detail::strand_executor_service>(+ ex.context()).create_implementation();+ }++ strand(const Executor& ex, const implementation_type& impl)+ : executor_(ex),+ impl_(impl)+ {+ }++ Executor executor_;+ implementation_type impl_;+};++/** @defgroup make_strand asio::make_strand+ *+ * @brief The asio::make_strand function creates a @ref strand object for+ * an executor or execution context.+ */+/*@{*/++/// Create a @ref strand object for an executor.+template <typename Executor>+inline strand<Executor> make_strand(const Executor& ex,+ typename enable_if<+ is_executor<Executor>::value || execution::is_executor<Executor>::value+ >::type* = 0)+{+ return strand<Executor>(ex);+}++/// Create a @ref strand object for an execution context.+template <typename ExecutionContext>+inline strand<typename ExecutionContext::executor_type>+make_strand(ExecutionContext& ctx,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+{+ return strand<typename ExecutionContext::executor_type>(ctx.get_executor());+}++/*@}*/++#if !defined(GENERATING_DOCUMENTATION)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++template <typename Executor>+struct equality_comparable<strand<Executor> >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+};++#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++template <typename Executor, typename Function>+struct execute_member<strand<Executor>, Function>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(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 Executor, typename Property>+struct query_member<strand<Executor>, Property,+ typename enable_if<+ can_query<const Executor&, Property>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_query<Executor, Property>::value));+ typedef typename query_result<Executor, Property>::type result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++template <typename Executor, typename Property>+struct require_member<strand<Executor>, Property,+ typename enable_if<+ can_require<const Executor&, Property>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_require<Executor, Property>::value));+ typedef strand<typename decay<+ typename require_result<Executor, Property>::type+ >::type> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)++template <typename Executor, typename Property>+struct prefer_member<strand<Executor>, Property,+ typename enable_if<+ can_prefer<const Executor&, Property>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ (is_nothrow_prefer<Executor, Property>::value));+ typedef strand<typename decay<+ typename prefer_result<Executor, Property>::type+ >::type> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)++} // namespace traits++#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++// If both io_context.hpp and strand.hpp have been included, automatically+// include the header file needed for the io_context::strand class.+#if !defined(ASIO_NO_EXTENSIONS)+# if defined(ASIO_IO_CONTEXT_HPP)+# include "asio/io_context_strand.hpp"+# endif // defined(ASIO_IO_CONTEXT_HPP)+#endif // !defined(ASIO_NO_EXTENSIONS)++#endif // ASIO_STRAND_HPP
+ link/modules/asio-standalone/asio/include/asio/streambuf.hpp view
@@ -0,0 +1,33 @@+//+// streambuf.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_STREAMBUF_HPP+#define ASIO_STREAMBUF_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_NO_IOSTREAM)++#include "asio/basic_streambuf.hpp"++namespace asio {++/// Typedef for the typical usage of basic_streambuf.+typedef basic_streambuf<> streambuf;++} // namespace asio++#endif // !defined(ASIO_NO_IOSTREAM)++#endif // ASIO_STREAMBUF_HPP
+ link/modules/asio-standalone/asio/include/asio/system_context.hpp view
@@ -0,0 +1,90 @@+//+// system_context.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SYSTEM_CONTEXT_HPP+#define ASIO_SYSTEM_CONTEXT_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/scheduler.hpp"+#include "asio/detail/thread_group.hpp"+#include "asio/execution.hpp"+#include "asio/execution_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++template <typename Blocking, typename Relationship, typename Allocator>+class basic_system_executor;++/// The executor context for the system executor.+class system_context : public execution_context+{+public:+ /// The executor type associated with the context.+ typedef basic_system_executor<+ execution::blocking_t::possibly_t,+ execution::relationship_t::fork_t,+ std::allocator<void>+ > executor_type;++ /// Destructor shuts down all threads in the system thread pool.+ ASIO_DECL ~system_context();++ /// Obtain an executor for the context.+ executor_type get_executor() ASIO_NOEXCEPT;++ /// Signal all threads in the system thread pool to stop.+ ASIO_DECL void stop();++ /// Determine whether the system thread pool has been stopped.+ ASIO_DECL bool stopped() const ASIO_NOEXCEPT;++ /// Join all threads in the system thread pool.+ ASIO_DECL void join();++#if defined(GENERATING_DOCUMENTATION)+private:+#endif // defined(GENERATING_DOCUMENTATION)+ // Constructor creates all threads in the system thread pool.+ ASIO_DECL system_context();++private:+ template <typename, typename, typename> friend class basic_system_executor;++ struct thread_function;++ // Helper function to create the underlying scheduler.+ ASIO_DECL detail::scheduler& add_scheduler(detail::scheduler* s);++ // The underlying scheduler.+ detail::scheduler& scheduler_;++ // The threads in the system thread pool.+ detail::thread_group threads_;++ // The number of threads in the pool.+ std::size_t num_threads_;+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/system_context.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/impl/system_context.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_SYSTEM_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/system_error.hpp view
@@ -0,0 +1,131 @@+//+// system_error.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SYSTEM_ERROR_HPP+#define ASIO_SYSTEM_ERROR_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_STD_SYSTEM_ERROR)+# include <system_error>+#else // defined(ASIO_HAS_STD_SYSTEM_ERROR)+# include <cerrno>+# include <exception>+# include <string>+# include "asio/error_code.hpp"+# include "asio/detail/scoped_ptr.hpp"+#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)++#include "asio/detail/push_options.hpp"++namespace asio {++#if defined(ASIO_HAS_STD_SYSTEM_ERROR)++typedef std::system_error system_error;++#else // defined(ASIO_HAS_STD_SYSTEM_ERROR)++/// The system_error class is used to represent system conditions that+/// prevent the library from operating correctly.+class system_error+ : public std::exception+{+public:+ /// Construct with an error code.+ system_error(const error_code& ec)+ : code_(ec),+ context_()+ {+ }++ /// Construct with an error code and context.+ system_error(const error_code& ec, const std::string& context)+ : code_(ec),+ context_(context)+ {+ }++ /// Copy constructor.+ system_error(const system_error& other)+ : std::exception(other),+ code_(other.code_),+ context_(other.context_),+ what_()+ {+ }++ /// Destructor.+ virtual ~system_error() throw ()+ {+ }++ /// Assignment operator.+ system_error& operator=(const system_error& e)+ {+ context_ = e.context_;+ code_ = e.code_;+ what_.reset();+ return *this;+ }++ /// Get a string representation of the exception.+ virtual const char* what() const throw ()+ {+#if !defined(ASIO_NO_EXCEPTIONS)+ try+#endif // !defined(ASIO_NO_EXCEPTIONS)+ {+ if (!what_.get())+ {+ std::string tmp(context_);+ if (tmp.length())+ tmp += ": ";+ tmp += code_.message();+ what_.reset(new std::string(tmp));+ }+ return what_->c_str();+ }+#if !defined(ASIO_NO_EXCEPTIONS)+ catch (std::exception&)+ {+ return "system_error";+ }+#endif // !defined(ASIO_NO_EXCEPTIONS)+ }++ /// Get the error code associated with the exception.+ error_code code() const+ {+ return code_;+ }++private:+ // The code associated with the error.+ error_code code_;++ // The context associated with the error.+ std::string context_;++ // The string representation of the error.+ mutable asio::detail::scoped_ptr<std::string> what_;+};++#endif // defined(ASIO_HAS_STD_SYSTEM_ERROR)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_SYSTEM_ERROR_HPP
+ link/modules/asio-standalone/asio/include/asio/system_executor.hpp view
@@ -0,0 +1,662 @@+//+// system_executor.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SYSTEM_EXECUTOR_HPP+#define ASIO_SYSTEM_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/memory.hpp"+#include "asio/execution.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++class system_context;++/// An executor that uses arbitrary threads.+/**+ * The system executor represents an execution context where functions are+ * permitted to run on arbitrary threads. When the blocking.never property is+ * established, the system executor will schedule the function to run on an+ * unspecified system thread pool. When either blocking.possibly or+ * blocking.always is established, the executor invokes the function+ * immediately.+ */+template <typename Blocking, typename Relationship, typename Allocator>+class basic_system_executor+{+public:+ /// Default constructor.+ basic_system_executor() ASIO_NOEXCEPT+ : allocator_(Allocator())+ {+ }++ /// Obtain an executor with the @c blocking.possibly property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code asio::system_executor ex1;+ * auto ex2 = asio::require(ex1,+ * asio::execution::blocking.possibly); @endcode+ */+ basic_system_executor<execution::blocking_t::possibly_t,+ Relationship, Allocator>+ require(execution::blocking_t::possibly_t) const+ {+ return basic_system_executor<execution::blocking_t::possibly_t,+ Relationship, Allocator>(allocator_);+ }++ /// Obtain an executor with the @c blocking.always property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code asio::system_executor ex1;+ * auto ex2 = asio::require(ex1,+ * asio::execution::blocking.always); @endcode+ */+ basic_system_executor<execution::blocking_t::always_t,+ Relationship, Allocator>+ require(execution::blocking_t::always_t) const+ {+ return basic_system_executor<execution::blocking_t::always_t,+ Relationship, Allocator>(allocator_);+ }++ /// Obtain an executor with the @c blocking.never property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code asio::system_executor ex1;+ * auto ex2 = asio::require(ex1,+ * asio::execution::blocking.never); @endcode+ */+ basic_system_executor<execution::blocking_t::never_t,+ Relationship, Allocator>+ require(execution::blocking_t::never_t) const+ {+ return basic_system_executor<execution::blocking_t::never_t,+ Relationship, Allocator>(allocator_);+ }++ /// Obtain an executor with the @c relationship.continuation property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code asio::system_executor ex1;+ * auto ex2 = asio::require(ex1,+ * asio::execution::relationship.continuation); @endcode+ */+ basic_system_executor<Blocking,+ execution::relationship_t::continuation_t, Allocator>+ require(execution::relationship_t::continuation_t) const+ {+ return basic_system_executor<Blocking,+ execution::relationship_t::continuation_t, Allocator>(allocator_);+ }++ /// Obtain an executor with the @c relationship.fork property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code asio::system_executor ex1;+ * auto ex2 = asio::require(ex1,+ * asio::execution::relationship.fork); @endcode+ */+ basic_system_executor<Blocking,+ execution::relationship_t::fork_t, Allocator>+ require(execution::relationship_t::fork_t) const+ {+ return basic_system_executor<Blocking,+ execution::relationship_t::fork_t, Allocator>(allocator_);+ }++ /// Obtain an executor with the specified @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code asio::system_executor ex1;+ * auto ex2 = asio::require(ex1,+ * asio::execution::allocator(my_allocator)); @endcode+ */+ template <typename OtherAllocator>+ basic_system_executor<Blocking, Relationship, OtherAllocator>+ require(execution::allocator_t<OtherAllocator> a) const+ {+ return basic_system_executor<Blocking,+ Relationship, OtherAllocator>(a.value());+ }++ /// Obtain an executor with the default @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code asio::system_executor ex1;+ * auto ex2 = asio::require(ex1,+ * asio::execution::allocator); @endcode+ */+ basic_system_executor<Blocking, Relationship, std::allocator<void> >+ require(execution::allocator_t<void>) const+ {+ return basic_system_executor<Blocking,+ Relationship, std::allocator<void> >();+ }++ /// Query the current value of the @c mapping property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code asio::system_executor ex;+ * if (asio::query(ex, asio::execution::mapping)+ * == asio::execution::mapping.thread)+ * ... @endcode+ */+ static ASIO_CONSTEXPR execution::mapping_t query(+ execution::mapping_t) ASIO_NOEXCEPT+ {+ return execution::mapping.thread;+ }++ /// Query the current value of the @c context property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code asio::system_executor ex;+ * asio::system_context& pool = asio::query(+ * ex, asio::execution::context); @endcode+ */+ static system_context& query(execution::context_t) ASIO_NOEXCEPT;++ /// Query the current value of the @c blocking property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code asio::system_executor ex;+ * if (asio::query(ex, asio::execution::blocking)+ * == asio::execution::blocking.always)+ * ... @endcode+ */+ static ASIO_CONSTEXPR execution::blocking_t query(+ execution::blocking_t) ASIO_NOEXCEPT+ {+ return Blocking();+ }++ /// Query the current value of the @c relationship property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code asio::system_executor ex;+ * if (asio::query(ex, asio::execution::relationship)+ * == asio::execution::relationship.continuation)+ * ... @endcode+ */+ static ASIO_CONSTEXPR execution::relationship_t query(+ execution::relationship_t) ASIO_NOEXCEPT+ {+ return Relationship();+ }++ /// Query the current value of the @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code asio::system_executor ex;+ * auto alloc = asio::query(ex,+ * asio::execution::allocator); @endcode+ */+ template <typename OtherAllocator>+ ASIO_CONSTEXPR Allocator query(+ execution::allocator_t<OtherAllocator>) const ASIO_NOEXCEPT+ {+ return allocator_;+ }++ /// Query the current value of the @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code asio::system_executor ex;+ * auto alloc = asio::query(ex,+ * asio::execution::allocator); @endcode+ */+ ASIO_CONSTEXPR Allocator query(+ execution::allocator_t<void>) const ASIO_NOEXCEPT+ {+ return allocator_;+ }++ /// Query the occupancy (recommended number of work items) for the system+ /// context.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code asio::system_executor ex;+ * std::size_t occupancy = asio::query(+ * ex, asio::execution::occupancy); @endcode+ */+ std::size_t query(execution::occupancy_t) const ASIO_NOEXCEPT;++ /// Compare two executors for equality.+ /**+ * Two executors are equal if they refer to the same underlying io_context.+ */+ friend bool operator==(const basic_system_executor&,+ const basic_system_executor&) ASIO_NOEXCEPT+ {+ return true;+ }++ /// Compare two executors for inequality.+ /**+ * Two executors are equal if they refer to the same underlying io_context.+ */+ friend bool operator!=(const basic_system_executor&,+ const basic_system_executor&) ASIO_NOEXCEPT+ {+ return false;+ }++ /// Execution function.+ /**+ * Do not call this function directly. It is intended for use with the+ * execution::execute customisation point.+ *+ * For example:+ * @code asio::system_executor ex;+ * execution::execute(ex, my_function_object); @endcode+ */+ template <typename Function>+ void execute(ASIO_MOVE_ARG(Function) f) const+ {+ this->do_execute(ASIO_MOVE_CAST(Function)(f), Blocking());+ }++#if !defined(ASIO_NO_TS_EXECUTORS)+ /// Obtain the underlying execution context.+ system_context& context() const ASIO_NOEXCEPT;++ /// Inform the executor that it has some outstanding work to do.+ /**+ * For the system executor, this is a no-op.+ */+ void on_work_started() const ASIO_NOEXCEPT+ {+ }++ /// Inform the executor that some work is no longer outstanding.+ /**+ * For the system executor, this is a no-op.+ */+ void on_work_finished() const ASIO_NOEXCEPT+ {+ }++ /// Request the system executor to invoke the given function object.+ /**+ * This function is used to ask the executor to execute the given function+ * object. The function object will always be executed inside this function.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename OtherAllocator>+ void dispatch(ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const;++ /// Request the system executor to invoke the given function object.+ /**+ * This function is used to ask the executor to execute the given function+ * object. The function object will never be executed inside this function.+ * Instead, it will be scheduled to run on an unspecified system thread pool.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename OtherAllocator>+ void post(ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const;++ /// Request the system executor to invoke the given function object.+ /**+ * This function is used to ask the executor to execute the given function+ * object. The function object will never be executed inside this function.+ * Instead, it will be scheduled to run on an unspecified system thread pool.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename OtherAllocator>+ void defer(ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const;+#endif // !defined(ASIO_NO_TS_EXECUTORS)++private:+ template <typename, typename, typename> friend class basic_system_executor;++ // Constructor used by require().+ basic_system_executor(const Allocator& a)+ : allocator_(a)+ {+ }++ /// Execution helper implementation for the possibly blocking property.+ template <typename Function>+ void do_execute(ASIO_MOVE_ARG(Function) f,+ execution::blocking_t::possibly_t) const;++ /// Execution helper implementation for the always blocking property.+ template <typename Function>+ void do_execute(ASIO_MOVE_ARG(Function) f,+ execution::blocking_t::always_t) const;++ /// Execution helper implementation for the never blocking property.+ template <typename Function>+ void do_execute(ASIO_MOVE_ARG(Function) f,+ execution::blocking_t::never_t) const;++ // The allocator used for execution functions.+ Allocator allocator_;+};++/// An executor that uses arbitrary threads.+/**+ * The system executor represents an execution context where functions are+ * permitted to run on arbitrary threads. When the blocking.never property is+ * established, the system executor will schedule the function to run on an+ * unspecified system thread pool. When either blocking.possibly or+ * blocking.always is established, the executor invokes the function+ * immediately.+ */+typedef basic_system_executor<execution::blocking_t::possibly_t,+ execution::relationship_t::fork_t, std::allocator<void> >+ system_executor;++#if !defined(GENERATING_DOCUMENTATION)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++template <typename Blocking, typename Relationship, typename Allocator>+struct equality_comparable<+ asio::basic_system_executor<Blocking, Relationship, Allocator>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+};++#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++template <typename Blocking, typename Relationship,+ typename Allocator, typename Function>+struct execute_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ Function+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++template <typename Blocking, typename Relationship, typename Allocator>+struct require_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ asio::execution::blocking_t::possibly_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::basic_system_executor<+ asio::execution::blocking_t::possibly_t,+ Relationship, Allocator> result_type;+};++template <typename Blocking, typename Relationship, typename Allocator>+struct require_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ asio::execution::blocking_t::always_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::basic_system_executor<+ asio::execution::blocking_t::always_t,+ Relationship, Allocator> result_type;+};++template <typename Blocking, typename Relationship, typename Allocator>+struct require_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ asio::execution::blocking_t::never_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::basic_system_executor<+ asio::execution::blocking_t::never_t,+ Relationship, Allocator> result_type;+};++template <typename Blocking, typename Relationship, typename Allocator>+struct require_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ asio::execution::relationship_t::fork_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::basic_system_executor<Blocking,+ asio::execution::relationship_t::fork_t,+ Allocator> result_type;+};++template <typename Blocking, typename Relationship, typename Allocator>+struct require_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ asio::execution::relationship_t::continuation_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::basic_system_executor<Blocking,+ asio::execution::relationship_t::continuation_t,+ Allocator> result_type;+};++template <typename Blocking, typename Relationship, typename Allocator>+struct require_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ asio::execution::allocator_t<void>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::basic_system_executor<Blocking,+ Relationship, std::allocator<void> > result_type;+};++template <typename Blocking, typename Relationship,+ typename Allocator, typename OtherAllocator>+struct require_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ asio::execution::allocator_t<OtherAllocator>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::basic_system_executor<Blocking,+ Relationship, OtherAllocator> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++template <typename Blocking, typename Relationship,+ typename Allocator, typename Property>+struct query_static_constexpr_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::mapping_t+ >::value+ >::type+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::mapping_t::thread_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return result_type();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++template <typename Blocking, typename Relationship,+ typename Allocator, typename Property>+struct query_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::blocking_t+ >::value+ >::type+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::blocking_t result_type;+};++template <typename Blocking, typename Relationship,+ typename Allocator, typename Property>+struct query_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::relationship_t+ >::value+ >::type+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::relationship_t result_type;+};++template <typename Blocking, typename Relationship, typename Allocator>+struct query_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ asio::execution::context_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::system_context& result_type;+};++template <typename Blocking, typename Relationship, typename Allocator>+struct query_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ asio::execution::allocator_t<void>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef Allocator result_type;+};++template <typename Blocking, typename Relationship, typename Allocator>+struct query_member<+ asio::basic_system_executor<Blocking, Relationship, Allocator>,+ asio::execution::allocator_t<Allocator>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef Allocator result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++} // namespace traits++#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/system_executor.hpp"++#endif // ASIO_SYSTEM_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/system_timer.hpp view
@@ -0,0 +1,42 @@+//+// system_timer.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_SYSTEM_TIMER_HPP+#define ASIO_SYSTEM_TIMER_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_CHRONO) || defined(GENERATING_DOCUMENTATION)++#include "asio/basic_waitable_timer.hpp"+#include "asio/detail/chrono.hpp"++namespace asio {++/// Typedef for a timer based on the system clock.+/**+ * This typedef uses the C++11 @c <chrono> standard library facility, if+ * available. Otherwise, it may use the Boost.Chrono library. To explicitly+ * utilise Boost.Chrono, use the basic_waitable_timer template directly:+ * @code+ * typedef basic_waitable_timer<boost::chrono::system_clock> timer;+ * @endcode+ */+typedef basic_waitable_timer<chrono::system_clock> system_timer;++} // namespace asio++#endif // defined(ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_SYSTEM_TIMER_HPP
+ link/modules/asio-standalone/asio/include/asio/this_coro.hpp view
@@ -0,0 +1,45 @@+//+// this_coro.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_THIS_CORO_HPP+#define ASIO_THIS_CORO_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 {+namespace this_coro {++/// Awaitable type that returns the executor of the current coroutine.+struct executor_t+{+ ASIO_CONSTEXPR executor_t()+ {+ }+};++/// Awaitable object that returns the executor of the current coroutine.+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr executor_t executor;+#elif defined(ASIO_MSVC)+__declspec(selectany) executor_t executor;+#endif++} // namespace this_coro+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_THIS_CORO_HPP
+ link/modules/asio-standalone/asio/include/asio/thread.hpp view
@@ -0,0 +1,92 @@+//+// thread.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_THREAD_HPP+#define ASIO_THREAD_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/noncopyable.hpp"+#include "asio/detail/thread.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {++/// A simple abstraction for starting threads.+/**+ * The asio::thread class implements the smallest possible subset of the+ * functionality of boost::thread. It is intended to be used only for starting+ * a thread and waiting for it to exit. If more extensive threading+ * capabilities are required, you are strongly advised to use something else.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ *+ * @par Example+ * A typical use of asio::thread would be to launch a thread to run an+ * io_context's event processing loop:+ *+ * @par+ * @code asio::io_context io_context;+ * // ...+ * asio::thread t(boost::bind(&asio::io_context::run, &io_context));+ * // ...+ * t.join(); @endcode+ */+class thread+ : private noncopyable+{+public:+ /// Start a new thread that executes the supplied function.+ /**+ * This constructor creates a new thread that will execute the given function+ * or function object.+ *+ * @param f The function or function object to be run in the thread. The+ * function signature must be: @code void f(); @endcode+ */+ template <typename Function>+ explicit thread(Function f)+ : impl_(f)+ {+ }++ /// Destructor.+ ~thread()+ {+ }++ /// Wait for the thread to exit.+ /**+ * This function will block until the thread has exited.+ *+ * If this function is not called before the thread object is destroyed, the+ * thread itself will continue to run until completion. You will, however,+ * no longer have the ability to wait for it to exit.+ */+ void join()+ {+ impl_.join();+ }++private:+ detail::thread impl_;+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_THREAD_HPP
+ link/modules/asio-standalone/asio/include/asio/thread_pool.hpp view
@@ -0,0 +1,1111 @@+//+// thread_pool.hpp+// ~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_THREAD_POOL_HPP+#define ASIO_THREAD_POOL_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/atomic_count.hpp"+#include "asio/detail/scheduler.hpp"+#include "asio/detail/thread_group.hpp"+#include "asio/execution.hpp"+#include "asio/execution_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {+ struct thread_pool_bits+ {+ ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1);+ ASIO_STATIC_CONSTEXPR(unsigned int, blocking_always = 2);+ ASIO_STATIC_CONSTEXPR(unsigned int, blocking_mask = 3);+ ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 4);+ ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 8);+ };+} // namespace detail++/// A simple fixed-size thread pool.+/**+ * The thread pool class is an execution context where functions are permitted+ * to run on one of a fixed number of threads.+ *+ * @par Submitting tasks to the pool+ *+ * To submit functions to the thread pool, use the @ref asio::dispatch,+ * @ref asio::post or @ref asio::defer free functions.+ *+ * For example:+ *+ * @code void my_task()+ * {+ * ...+ * }+ *+ * ...+ *+ * // Launch the pool with four threads.+ * asio::thread_pool pool(4);+ *+ * // Submit a function to the pool.+ * asio::post(pool, my_task);+ *+ * // Submit a lambda object to the pool.+ * asio::post(pool,+ * []()+ * {+ * ...+ * });+ *+ * // Wait for all tasks in the pool to complete.+ * pool.join(); @endcode+ */+class thread_pool+ : public execution_context+{+public:+ template <typename Allocator, unsigned int Bits>+ class basic_executor_type;++ template <typename Allocator, unsigned int Bits>+ friend class basic_executor_type;++ /// Executor used to submit functions to a thread pool.+ typedef basic_executor_type<std::allocator<void>, 0> executor_type;++ /// Scheduler used to schedule receivers on a thread pool.+ typedef basic_executor_type<std::allocator<void>, 0> scheduler_type;++#if !defined(ASIO_NO_TS_EXECUTORS)+ /// Constructs a pool with an automatically determined number of threads.+ ASIO_DECL thread_pool();+#endif // !defined(ASIO_NO_TS_EXECUTORS)++ /// Constructs a pool with a specified number of threads.+ ASIO_DECL thread_pool(std::size_t num_threads);++ /// Destructor.+ /**+ * Automatically stops and joins the pool, if not explicitly done beforehand.+ */+ ASIO_DECL ~thread_pool();++ /// Obtains the executor associated with the pool.+ executor_type get_executor() ASIO_NOEXCEPT;++ /// Obtains the executor associated with the pool.+ executor_type executor() ASIO_NOEXCEPT;++ /// Obtains the scheduler associated with the pool.+ scheduler_type scheduler() ASIO_NOEXCEPT;++ /// Stops the threads.+ /**+ * This function stops the threads as soon as possible. As a result of calling+ * @c stop(), pending function objects may be never be invoked.+ */+ ASIO_DECL void stop();++ /// Attaches the current thread to the pool.+ /**+ * This function attaches the current thread to the pool so that it may be+ * used for executing submitted function objects. Blocks the calling thread+ * until the pool is stopped or joined and has no outstanding work.+ */+ ASIO_DECL void attach();++ /// Joins the threads.+ /**+ * This function blocks until the threads in the pool have completed. If @c+ * stop() is not called prior to @c join(), the @c join() call will wait+ * until the pool has no more outstanding work.+ */+ ASIO_DECL void join();++ /// Waits for threads to complete.+ /**+ * This function blocks until the threads in the pool have completed. If @c+ * stop() is not called prior to @c wait(), the @c wait() call will wait+ * until the pool has no more outstanding work.+ */+ ASIO_DECL void wait();++private:+ thread_pool(const thread_pool&) ASIO_DELETED;+ thread_pool& operator=(const thread_pool&) ASIO_DELETED;++ struct thread_function;++ // Helper function to create the underlying scheduler.+ ASIO_DECL detail::scheduler& add_scheduler(detail::scheduler* s);++ // The underlying scheduler.+ detail::scheduler& scheduler_;++ // The threads in the pool.+ detail::thread_group threads_;++ // The current number of threads in the pool.+ detail::atomic_count num_threads_;+};++/// Executor implementation type used to submit functions to a thread pool.+template <typename Allocator, unsigned int Bits>+class thread_pool::basic_executor_type : detail::thread_pool_bits+{+public:+ /// The sender type, when this type is used as a scheduler.+ typedef basic_executor_type sender_type;++ /// The bulk execution shape type.+ typedef std::size_t shape_type;++ /// The bulk execution index type.+ typedef std::size_t index_type;++#if defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) \+ && defined(ASIO_HAS_STD_EXCEPTION_PTR)+ template <+ template <typename...> class Tuple,+ template <typename...> class Variant>+ using value_types = Variant<Tuple<>>;++ template <template <typename...> class Variant>+ using error_types = Variant<std::exception_ptr>;++ ASIO_STATIC_CONSTEXPR(bool, sends_done = true);+#endif // defined(ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT)+ // && defined(ASIO_HAS_STD_EXCEPTION_PTR)++ /// Copy constructor.+ basic_executor_type(+ const basic_executor_type& other) ASIO_NOEXCEPT+ : pool_(other.pool_),+ allocator_(other.allocator_),+ bits_(other.bits_)+ {+ if (Bits & outstanding_work_tracked)+ if (pool_)+ pool_->scheduler_.work_started();+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move constructor.+ basic_executor_type(basic_executor_type&& other) ASIO_NOEXCEPT+ : pool_(other.pool_),+ allocator_(ASIO_MOVE_CAST(Allocator)(other.allocator_)),+ bits_(other.bits_)+ {+ if (Bits & outstanding_work_tracked)+ other.pool_ = 0;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Destructor.+ ~basic_executor_type() ASIO_NOEXCEPT+ {+ if (Bits & outstanding_work_tracked)+ if (pool_)+ pool_->scheduler_.work_finished();+ }++ /// Assignment operator.+ basic_executor_type& operator=(+ const basic_executor_type& other) ASIO_NOEXCEPT;++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move assignment operator.+ basic_executor_type& operator=(+ basic_executor_type&& other) ASIO_NOEXCEPT;+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Obtain an executor with the @c blocking.possibly property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_thread_pool.executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::blocking.possibly); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type<Allocator,+ ASIO_UNSPECIFIED(Bits & ~blocking_mask)>+ require(execution::blocking_t::possibly_t) const+ {+ return basic_executor_type<Allocator, Bits & ~blocking_mask>(+ pool_, allocator_, bits_ & ~blocking_mask);+ }++ /// Obtain an executor with the @c blocking.always property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_thread_pool.executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::blocking.always); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type<Allocator,+ ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>+ require(execution::blocking_t::always_t) const+ {+ return basic_executor_type<Allocator,+ ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>(+ pool_, allocator_, bits_ & ~blocking_mask);+ }++ /// Obtain an executor with the @c blocking.never property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_thread_pool.executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::blocking.never); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type<Allocator,+ ASIO_UNSPECIFIED(Bits & ~blocking_mask)>+ require(execution::blocking_t::never_t) const+ {+ return basic_executor_type<Allocator, Bits & ~blocking_mask>(+ pool_, allocator_, (bits_ & ~blocking_mask) | blocking_never);+ }++ /// Obtain an executor with the @c relationship.fork property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_thread_pool.executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::relationship.fork); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type require(+ execution::relationship_t::fork_t) const+ {+ return basic_executor_type(pool_,+ allocator_, bits_ & ~relationship_continuation);+ }++ /// Obtain an executor with the @c relationship.continuation property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_thread_pool.executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::relationship.continuation); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type require(+ execution::relationship_t::continuation_t) const+ {+ return basic_executor_type(pool_,+ allocator_, bits_ | relationship_continuation);+ }++ /// Obtain an executor with the @c outstanding_work.tracked property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_thread_pool.executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::outstanding_work.tracked); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type<Allocator,+ ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)>+ require(execution::outstanding_work_t::tracked_t) const+ {+ return basic_executor_type<Allocator, Bits | outstanding_work_tracked>(+ pool_, allocator_, bits_);+ }++ /// Obtain an executor with the @c outstanding_work.untracked property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_thread_pool.executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::outstanding_work.untracked); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type<Allocator,+ ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)>+ require(execution::outstanding_work_t::untracked_t) const+ {+ return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>(+ pool_, allocator_, bits_);+ }++ /// Obtain an executor with the specified @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_thread_pool.executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::allocator(my_allocator)); @endcode+ */+ template <typename OtherAllocator>+ ASIO_CONSTEXPR basic_executor_type<OtherAllocator, Bits>+ require(execution::allocator_t<OtherAllocator> a) const+ {+ return basic_executor_type<OtherAllocator, Bits>(+ pool_, a.value(), bits_);+ }++ /// Obtain an executor with the default @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::require customisation point.+ *+ * For example:+ * @code auto ex1 = my_thread_pool.executor();+ * auto ex2 = asio::require(ex1,+ * asio::execution::allocator); @endcode+ */+ ASIO_CONSTEXPR basic_executor_type<std::allocator<void>, Bits>+ require(execution::allocator_t<void>) const+ {+ return basic_executor_type<std::allocator<void>, Bits>(+ pool_, std::allocator<void>(), bits_);+ }++ /// Query the current value of the @c bulk_guarantee property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_thread_pool.executor();+ * if (asio::query(ex, asio::execution::bulk_guarantee)+ * == asio::execution::bulk_guarantee.parallel)+ * ... @endcode+ */+ static ASIO_CONSTEXPR execution::bulk_guarantee_t query(+ execution::bulk_guarantee_t) ASIO_NOEXCEPT+ {+ return execution::bulk_guarantee.parallel;+ }++ /// Query the current value of the @c mapping property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_thread_pool.executor();+ * if (asio::query(ex, asio::execution::mapping)+ * == asio::execution::mapping.thread)+ * ... @endcode+ */+ static ASIO_CONSTEXPR execution::mapping_t query(+ execution::mapping_t) ASIO_NOEXCEPT+ {+ return execution::mapping.thread;+ }++ /// Query the current value of the @c context property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_thread_pool.executor();+ * asio::thread_pool& pool = asio::query(+ * ex, asio::execution::context); @endcode+ */+ thread_pool& query(execution::context_t) const ASIO_NOEXCEPT+ {+ return *pool_;+ }++ /// Query the current value of the @c blocking property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_thread_pool.executor();+ * if (asio::query(ex, asio::execution::blocking)+ * == asio::execution::blocking.always)+ * ... @endcode+ */+ ASIO_CONSTEXPR execution::blocking_t query(+ execution::blocking_t) const ASIO_NOEXCEPT+ {+ return (bits_ & blocking_never)+ ? execution::blocking_t(execution::blocking.never)+ : ((Bits & blocking_always)+ ? execution::blocking_t(execution::blocking.always)+ : execution::blocking_t(execution::blocking.possibly));+ }++ /// Query the current value of the @c relationship property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_thread_pool.executor();+ * if (asio::query(ex, asio::execution::relationship)+ * == asio::execution::relationship.continuation)+ * ... @endcode+ */+ ASIO_CONSTEXPR execution::relationship_t query(+ execution::relationship_t) const ASIO_NOEXCEPT+ {+ return (bits_ & relationship_continuation)+ ? execution::relationship_t(execution::relationship.continuation)+ : execution::relationship_t(execution::relationship.fork);+ }++ /// Query the current value of the @c outstanding_work property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_thread_pool.executor();+ * if (asio::query(ex, asio::execution::outstanding_work)+ * == asio::execution::outstanding_work.tracked)+ * ... @endcode+ */+ static ASIO_CONSTEXPR execution::outstanding_work_t query(+ execution::outstanding_work_t) ASIO_NOEXCEPT+ {+ return (Bits & outstanding_work_tracked)+ ? execution::outstanding_work_t(execution::outstanding_work.tracked)+ : execution::outstanding_work_t(execution::outstanding_work.untracked);+ }++ /// Query the current value of the @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_thread_pool.executor();+ * auto alloc = asio::query(ex,+ * asio::execution::allocator); @endcode+ */+ template <typename OtherAllocator>+ ASIO_CONSTEXPR Allocator query(+ execution::allocator_t<OtherAllocator>) const ASIO_NOEXCEPT+ {+ return allocator_;+ }++ /// Query the current value of the @c allocator property.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_thread_pool.executor();+ * auto alloc = asio::query(ex,+ * asio::execution::allocator); @endcode+ */+ ASIO_CONSTEXPR Allocator query(+ execution::allocator_t<void>) const ASIO_NOEXCEPT+ {+ return allocator_;+ }++ /// Query the occupancy (recommended number of work items) for the pool.+ /**+ * Do not call this function directly. It is intended for use with the+ * asio::query customisation point.+ *+ * For example:+ * @code auto ex = my_thread_pool.executor();+ * std::size_t occupancy = asio::query(+ * ex, asio::execution::occupancy); @endcode+ */+ std::size_t query(execution::occupancy_t) const ASIO_NOEXCEPT+ {+ return static_cast<std::size_t>(pool_->num_threads_);+ }++ /// Determine whether the thread pool is running in the current thread.+ /**+ * @return @c true if the current thread is running the thread pool. Otherwise+ * returns @c false.+ */+ bool running_in_this_thread() const ASIO_NOEXCEPT;++ /// Compare two executors for equality.+ /**+ * Two executors are equal if they refer to the same underlying thread pool.+ */+ friend bool operator==(const basic_executor_type& a,+ const basic_executor_type& b) ASIO_NOEXCEPT+ {+ return a.pool_ == b.pool_+ && a.allocator_ == b.allocator_+ && a.bits_ == b.bits_;+ }++ /// Compare two executors for inequality.+ /**+ * Two executors are equal if they refer to the same underlying thread pool.+ */+ friend bool operator!=(const basic_executor_type& a,+ const basic_executor_type& b) ASIO_NOEXCEPT+ {+ return a.pool_ != b.pool_+ || a.allocator_ != b.allocator_+ || a.bits_ != b.bits_;+ }++ /// Execution function.+ /**+ * Do not call this function directly. It is intended for use with the+ * execution::execute customisation point.+ *+ * For example:+ * @code auto ex = my_thread_pool.executor();+ * execution::execute(ex, my_function_object); @endcode+ */+ template <typename Function>+ void execute(ASIO_MOVE_ARG(Function) f) const+ {+ this->do_execute(ASIO_MOVE_CAST(Function)(f),+ integral_constant<bool, (Bits & blocking_always) != 0>());+ }++ /// Bulk execution function.+ template <typename Function>+ void bulk_execute(ASIO_MOVE_ARG(Function) f, std::size_t n) const+ {+ this->do_bulk_execute(ASIO_MOVE_CAST(Function)(f), n,+ integral_constant<bool, (Bits & blocking_always) != 0>());+ }++ /// Schedule function.+ /**+ * Do not call this function directly. It is intended for use with the+ * execution::schedule customisation point.+ *+ * @return An object that satisfies the sender concept.+ */+ sender_type schedule() const ASIO_NOEXCEPT+ {+ return *this;+ }++ /// Connect function.+ /**+ * Do not call this function directly. It is intended for use with the+ * execution::connect customisation point.+ *+ * @return An object of an unspecified type that satisfies the @c+ * operation_state concept.+ */+ template <ASIO_EXECUTION_RECEIVER_OF_0 Receiver>+#if defined(GENERATING_DOCUMENTATION)+ unspecified+#else // defined(GENERATING_DOCUMENTATION)+ execution::detail::as_operation<basic_executor_type, Receiver>+#endif // defined(GENERATING_DOCUMENTATION)+ connect(ASIO_MOVE_ARG(Receiver) r) const+ {+ return execution::detail::as_operation<basic_executor_type, Receiver>(+ *this, ASIO_MOVE_CAST(Receiver)(r));+ }++#if !defined(ASIO_NO_TS_EXECUTORS)+ /// Obtain the underlying execution context.+ thread_pool& context() const ASIO_NOEXCEPT;++ /// Inform the thread pool that it has some outstanding work to do.+ /**+ * This function is used to inform the thread pool that some work has begun.+ * This ensures that the thread pool's join() function will not return while+ * the work is underway.+ */+ void on_work_started() const ASIO_NOEXCEPT;++ /// Inform the thread pool that some work is no longer outstanding.+ /**+ * This function is used to inform the thread pool that some work has+ * finished. Once the count of unfinished work reaches zero, the thread+ * pool's join() function is permitted to exit.+ */+ void on_work_finished() const ASIO_NOEXCEPT;++ /// Request the thread pool to invoke the given function object.+ /**+ * This function is used to ask the thread pool to execute the given function+ * object. If the current thread belongs to the pool, @c dispatch() executes+ * the function before returning. Otherwise, the function will be scheduled+ * to run on the thread pool.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename OtherAllocator>+ void dispatch(ASIO_MOVE_ARG(Function) f,+ const OtherAllocator& a) const;++ /// Request the thread pool to invoke the given function object.+ /**+ * This function is used to ask the thread pool to execute the given function+ * object. The function object will never be executed inside @c post().+ * Instead, it will be scheduled to run on the thread pool.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename OtherAllocator>+ void post(ASIO_MOVE_ARG(Function) f,+ const OtherAllocator& a) const;++ /// Request the thread pool to invoke the given function object.+ /**+ * This function is used to ask the thread pool to execute the given function+ * object. The function object will never be executed inside @c defer().+ * Instead, it will be scheduled to run on the thread pool.+ *+ * If the current thread belongs to the thread pool, @c defer() will delay+ * scheduling the function object until the current thread returns control to+ * the pool.+ *+ * @param f The function object to be called. The executor will make+ * a copy of the handler object as required. The function signature of the+ * function object must be: @code void function(); @endcode+ *+ * @param a An allocator that may be used by the executor to allocate the+ * internal storage needed for function invocation.+ */+ template <typename Function, typename OtherAllocator>+ void defer(ASIO_MOVE_ARG(Function) f,+ const OtherAllocator& a) const;+#endif // !defined(ASIO_NO_TS_EXECUTORS)++private:+ friend class thread_pool;+ template <typename, unsigned int> friend class basic_executor_type;++ // Constructor used by thread_pool::get_executor().+ explicit basic_executor_type(thread_pool& p) ASIO_NOEXCEPT+ : pool_(&p),+ allocator_(),+ bits_(0)+ {+ if (Bits & outstanding_work_tracked)+ pool_->scheduler_.work_started();+ }++ // Constructor used by require().+ basic_executor_type(thread_pool* p,+ const Allocator& a, unsigned int bits) ASIO_NOEXCEPT+ : pool_(p),+ allocator_(a),+ bits_(bits)+ {+ if (Bits & outstanding_work_tracked)+ if (pool_)+ pool_->scheduler_.work_started();+ }++ /// Execution helper implementation for possibly and never blocking.+ template <typename Function>+ void do_execute(ASIO_MOVE_ARG(Function) f, false_type) const;++ /// Execution helper implementation for always blocking.+ template <typename Function>+ void do_execute(ASIO_MOVE_ARG(Function) f, true_type) const;++ /// Bulk execution helper implementation for possibly and never blocking.+ template <typename Function>+ void do_bulk_execute(ASIO_MOVE_ARG(Function) f,+ std::size_t n, false_type) const;++ /// Bulk execution helper implementation for always blocking.+ template <typename Function>+ void do_bulk_execute(ASIO_MOVE_ARG(Function) f,+ std::size_t n, true_type) const;++ // The underlying thread pool.+ thread_pool* pool_;++ // The allocator used for execution functions.+ Allocator allocator_;++ // The runtime-switched properties of the thread pool executor.+ unsigned int bits_;+};++#if !defined(GENERATING_DOCUMENTATION)++namespace traits {++#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++template <typename Allocator, unsigned int Bits>+struct equality_comparable<+ asio::thread_pool::basic_executor_type<Allocator, Bits>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+};++#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++template <typename Allocator, unsigned int Bits, typename Function>+struct execute_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ Function+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef void result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)++template <typename Allocator, unsigned int Bits>+struct schedule_member<+ const asio::thread_pool::basic_executor_type<Allocator, Bits>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::thread_pool::basic_executor_type<+ Allocator, Bits> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)++template <typename Allocator, unsigned int Bits, typename Receiver>+struct connect_member<+ const asio::thread_pool::basic_executor_type<Allocator, Bits>,+ Receiver+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::execution::detail::as_operation<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ Receiver> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::blocking_t::possibly_t+ > : asio::detail::thread_pool_bits+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::thread_pool::basic_executor_type<+ Allocator, Bits & ~blocking_mask> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::blocking_t::always_t+ > : asio::detail::thread_pool_bits+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::thread_pool::basic_executor_type<Allocator,+ (Bits & ~blocking_mask) | blocking_always> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::blocking_t::never_t+ > : asio::detail::thread_pool_bits+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::thread_pool::basic_executor_type<+ Allocator, Bits & ~blocking_mask> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::relationship_t::fork_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::thread_pool::basic_executor_type<+ Allocator, Bits> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::relationship_t::continuation_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::thread_pool::basic_executor_type<+ Allocator, Bits> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::outstanding_work_t::tracked_t+ > : asio::detail::thread_pool_bits+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::thread_pool::basic_executor_type<+ Allocator, Bits | outstanding_work_tracked> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::outstanding_work_t::untracked_t+ > : asio::detail::thread_pool_bits+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::thread_pool::basic_executor_type<+ Allocator, Bits & ~outstanding_work_tracked> result_type;+};++template <typename Allocator, unsigned int Bits>+struct require_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::allocator_t<void>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::thread_pool::basic_executor_type<+ std::allocator<void>, Bits> result_type;+};++template <unsigned int Bits,+ typename Allocator, typename OtherAllocator>+struct require_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::allocator_t<OtherAllocator>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+ typedef asio::thread_pool::basic_executor_type<+ OtherAllocator, Bits> result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++template <typename Allocator, unsigned int Bits, typename Property>+struct query_static_constexpr_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::bulk_guarantee_t+ >::value+ >::type+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::bulk_guarantee_t::parallel_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return result_type();+ }+};++template <typename Allocator, unsigned int Bits, typename Property>+struct query_static_constexpr_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::outstanding_work_t+ >::value+ >::type+ > : asio::detail::thread_pool_bits+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::outstanding_work_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return (Bits & outstanding_work_tracked)+ ? execution::outstanding_work_t(execution::outstanding_work.tracked)+ : execution::outstanding_work_t(execution::outstanding_work.untracked);+ }+};++template <typename Allocator, unsigned int Bits, typename Property>+struct query_static_constexpr_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::mapping_t+ >::value+ >::type+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::mapping_t::thread_t result_type;++ static ASIO_CONSTEXPR result_type value() ASIO_NOEXCEPT+ {+ return result_type();+ }+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++template <typename Allocator, unsigned int Bits, typename Property>+struct query_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::blocking_t+ >::value+ >::type+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::blocking_t result_type;+};++template <typename Allocator, unsigned int Bits, typename Property>+struct query_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ Property,+ typename asio::enable_if<+ asio::is_convertible<+ Property,+ asio::execution::relationship_t+ >::value+ >::type+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::execution::relationship_t result_type;+};++template <typename Allocator, unsigned int Bits>+struct query_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::occupancy_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef std::size_t result_type;+};++template <typename Allocator, unsigned int Bits>+struct query_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::context_t+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef asio::thread_pool& result_type;+};++template <typename Allocator, unsigned int Bits>+struct query_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::allocator_t<void>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef Allocator result_type;+};++template <typename Allocator, unsigned int Bits, typename OtherAllocator>+struct query_member<+ asio::thread_pool::basic_executor_type<Allocator, Bits>,+ asio::execution::allocator_t<OtherAllocator>+ >+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);+ typedef Allocator result_type;+};++#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++} // namespace traits++#endif // !defined(GENERATING_DOCUMENTATION)++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/thread_pool.hpp"+#if defined(ASIO_HEADER_ONLY)+# include "asio/impl/thread_pool.ipp"+#endif // defined(ASIO_HEADER_ONLY)++#endif // ASIO_THREAD_POOL_HPP
+ link/modules/asio-standalone/asio/include/asio/time_traits.hpp view
@@ -0,0 +1,86 @@+//+// time_traits.hpp+// ~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TIME_TRAITS_HPP+#define ASIO_TIME_TRAITS_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/socket_types.hpp" // Must come before posix_time.++#if defined(ASIO_HAS_BOOST_DATE_TIME) \+ || defined(GENERATING_DOCUMENTATION)++#include <boost/date_time/posix_time/posix_time_types.hpp>++#include "asio/detail/push_options.hpp"++namespace asio {++/// Time traits suitable for use with the deadline timer.+template <typename Time>+struct time_traits;++/// Time traits specialised for posix_time.+template <>+struct time_traits<boost::posix_time::ptime>+{+ /// The time type.+ typedef boost::posix_time::ptime time_type;++ /// The duration type.+ typedef boost::posix_time::time_duration duration_type;++ /// Get the current time.+ static time_type now()+ {+#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)+ return boost::posix_time::microsec_clock::universal_time();+#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)+ return boost::posix_time::second_clock::universal_time();+#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)+ }++ /// Add a duration to a time.+ static time_type add(const time_type& t, const duration_type& d)+ {+ return t + d;+ }++ /// Subtract one time from another.+ static duration_type subtract(const time_type& t1, const time_type& t2)+ {+ return t1 - t2;+ }++ /// Test whether one time is less than another.+ static bool less_than(const time_type& t1, const time_type& t2)+ {+ return t1 < t2;+ }++ /// Convert to POSIX duration type.+ static boost::posix_time::time_duration to_posix_duration(+ const duration_type& d)+ {+ return d;+ }+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_BOOST_DATE_TIME)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_TIME_TRAITS_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/bulk_execute_free.hpp view
@@ -0,0 +1,114 @@+//+// traits/bulk_execute_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_BULK_EXECUTE_FREE_HPP+#define ASIO_TRAITS_BULK_EXECUTE_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename F, typename N, typename = void>+struct bulk_execute_free_default;++template <typename T, typename F, typename N, typename = void>+struct bulk_execute_free;++} // namespace traits+namespace detail {++struct no_bulk_execute_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT)++template <typename T, typename F, typename N, typename = void>+struct bulk_execute_free_trait : no_bulk_execute_free+{+};++template <typename T, typename F, typename N>+struct bulk_execute_free_trait<T, F, N,+ typename void_type<+ decltype(bulk_execute(declval<T>(), declval<F>(), declval<N>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ bulk_execute(declval<T>(), declval<F>(), declval<N>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ bulk_execute(declval<T>(), declval<F>(), declval<N>())));+};++#else // defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT)++template <typename T, typename F, typename N, typename = void>+struct bulk_execute_free_trait :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value+ && is_same<F, typename decay<F>::type>::value+ && is_same<N, typename decay<N>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_bulk_execute_free,+ traits::bulk_execute_free<typename add_const<T>::type, F, N>+ >::type,+ traits::bulk_execute_free<+ typename remove_reference<T>::type,+ typename decay<F>::type,+ typename decay<N>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename F, typename N, typename>+struct bulk_execute_free_default :+ detail::bulk_execute_free_trait<T, F, N>+{+};++template <typename T, typename F, typename N, typename>+struct bulk_execute_free :+ bulk_execute_free_default<T, F, N>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_BULK_EXECUTE_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/bulk_execute_member.hpp view
@@ -0,0 +1,114 @@+//+// traits/bulk_execute_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_BULK_EXECUTE_MEMBER_HPP+#define ASIO_TRAITS_BULK_EXECUTE_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename F, typename N, typename = void>+struct bulk_execute_member_default;++template <typename T, typename F, typename N, typename = void>+struct bulk_execute_member;++} // namespace traits+namespace detail {++struct no_bulk_execute_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT)++template <typename T, typename F, typename N, typename = void>+struct bulk_execute_member_trait : no_bulk_execute_member+{+};++template <typename T, typename F, typename N>+struct bulk_execute_member_trait<T, F, N,+ typename void_type<+ decltype(declval<T>().bulk_execute(declval<F>(), declval<N>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ declval<T>().bulk_execute(declval<F>(), declval<N>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ declval<T>().bulk_execute(declval<F>(), declval<N>())));+};++#else // defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT)++template <typename T, typename F, typename N, typename = void>+struct bulk_execute_member_trait :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value+ && is_same<F, typename decay<F>::type>::value+ && is_same<N, typename decay<N>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_bulk_execute_member,+ traits::bulk_execute_member<typename add_const<T>::type, F, N>+ >::type,+ traits::bulk_execute_member<+ typename remove_reference<T>::type,+ typename decay<F>::type,+ typename decay<N>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename F, typename N, typename>+struct bulk_execute_member_default :+ detail::bulk_execute_member_trait<T, F, N>+{+};++template <typename T, typename F, typename N, typename>+struct bulk_execute_member :+ bulk_execute_member_default<T, F, N>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_BULK_EXECUTE_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/connect_free.hpp view
@@ -0,0 +1,112 @@+//+// traits/connect_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_CONNECT_FREE_HPP+#define ASIO_TRAITS_CONNECT_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename S, typename R, typename = void>+struct connect_free_default;++template <typename S, typename R, typename = void>+struct connect_free;++} // namespace traits+namespace detail {++struct no_connect_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT)++template <typename S, typename R, typename = void>+struct connect_free_trait : no_connect_free+{+};++template <typename S, typename R>+struct connect_free_trait<S, R,+ typename void_type<+ decltype(connect(declval<S>(), declval<R>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ connect(declval<S>(), declval<R>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ connect(declval<S>(), declval<R>())));+};++#else // defined(ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT)++template <typename S, typename R, typename = void>+struct connect_free_trait :+ conditional<+ is_same<S, typename remove_reference<S>::type>::value+ && is_same<R, typename decay<R>::type>::value,+ typename conditional<+ is_same<S, typename add_const<S>::type>::value,+ no_connect_free,+ traits::connect_free<typename add_const<S>::type, R>+ >::type,+ traits::connect_free<+ typename remove_reference<S>::type,+ typename decay<R>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename S, typename R, typename>+struct connect_free_default :+ detail::connect_free_trait<S, R>+{+};++template <typename S, typename R, typename>+struct connect_free :+ connect_free_default<S, R>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_CONNECT_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/connect_member.hpp view
@@ -0,0 +1,112 @@+//+// traits/connect_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_CONNECT_MEMBER_HPP+#define ASIO_TRAITS_CONNECT_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename S, typename R, typename = void>+struct connect_member_default;++template <typename S, typename R, typename = void>+struct connect_member;++} // namespace traits+namespace detail {++struct no_connect_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)++template <typename S, typename R, typename = void>+struct connect_member_trait : no_connect_member+{+};++template <typename S, typename R>+struct connect_member_trait<S, R,+ typename void_type<+ decltype(declval<S>().connect(declval<R>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ declval<S>().connect(declval<R>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ declval<S>().connect(declval<R>())));+};++#else // defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)++template <typename S, typename R, typename = void>+struct connect_member_trait :+ conditional<+ is_same<S, typename remove_reference<S>::type>::value+ && is_same<R, typename decay<R>::type>::value,+ typename conditional<+ is_same<S, typename add_const<S>::type>::value,+ no_connect_member,+ traits::connect_member<typename add_const<S>::type, R>+ >::type,+ traits::connect_member<+ typename remove_reference<S>::type,+ typename decay<R>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename S, typename R, typename>+struct connect_member_default :+ detail::connect_member_trait<S, R>+{+};++template <typename S, typename R, typename>+struct connect_member :+ connect_member_default<S, R>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_CONNECT_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/equality_comparable.hpp view
@@ -0,0 +1,100 @@+//+// traits/equality_comparable.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_EQUALITY_COMPARABLE_HPP+#define ASIO_TRAITS_EQUALITY_COMPARABLE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++namespace asio {+namespace traits {++template <typename T, typename = void>+struct equality_comparable_default;++template <typename T, typename = void>+struct equality_comparable;++} // namespace traits+namespace detail {++struct no_equality_comparable+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++template <typename T, typename = void>+struct equality_comparable_trait : no_equality_comparable+{+};++template <typename T>+struct equality_comparable_trait<T,+ typename void_type<+ decltype(+ static_cast<bool>(declval<const T>() == declval<const T>()),+ static_cast<bool>(declval<const T>() != declval<const T>())+ )+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ noexcept(declval<const T>() == declval<const T>())+ && noexcept(declval<const T>() != declval<const T>()));+};++#else // defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++template <typename T, typename = void>+struct equality_comparable_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value,+ no_equality_comparable,+ traits::equality_comparable<typename decay<T>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename>+struct equality_comparable_default : detail::equality_comparable_trait<T>+{+};++template <typename T, typename>+struct equality_comparable : equality_comparable_default<T>+{+};++} // namespace traits+} // namespace asio++#endif // ASIO_TRAITS_EQUALITY_COMPARABLE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/execute_free.hpp view
@@ -0,0 +1,108 @@+//+// traits/execute_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_EXECUTE_FREE_HPP+#define ASIO_TRAITS_EXECUTE_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename F, typename = void>+struct execute_free_default;++template <typename T, typename F, typename = void>+struct execute_free;++} // namespace traits+namespace detail {++struct no_execute_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)++template <typename T, typename F, typename = void>+struct execute_free_trait : no_execute_free+{+};++template <typename T, typename F>+struct execute_free_trait<T, F,+ typename void_type<+ decltype(execute(declval<T>(), declval<F>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ execute(declval<T>(), declval<F>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ execute(declval<T>(), declval<F>())));+};++#else // defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)++template <typename T, typename F, typename = void>+struct execute_free_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<F, typename decay<F>::type>::value,+ no_execute_free,+ traits::execute_free<+ typename decay<T>::type,+ typename decay<F>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename F, typename>+struct execute_free_default :+ detail::execute_free_trait<T, F>+{+};++template <typename T, typename F, typename>+struct execute_free :+ execute_free_default<T, F>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_EXECUTE_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/execute_member.hpp view
@@ -0,0 +1,108 @@+//+// traits/execute_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_EXECUTE_MEMBER_HPP+#define ASIO_TRAITS_EXECUTE_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename F, typename = void>+struct execute_member_default;++template <typename T, typename F, typename = void>+struct execute_member;++} // namespace traits+namespace detail {++struct no_execute_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++template <typename T, typename F, typename = void>+struct execute_member_trait : no_execute_member+{+};++template <typename T, typename F>+struct execute_member_trait<T, F,+ typename void_type<+ decltype(declval<T>().execute(declval<F>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ declval<T>().execute(declval<F>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ declval<T>().execute(declval<F>())));+};++#else // defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++template <typename T, typename F, typename = void>+struct execute_member_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<F, typename decay<F>::type>::value,+ no_execute_member,+ traits::execute_member<+ typename decay<T>::type,+ typename decay<F>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename F, typename>+struct execute_member_default :+ detail::execute_member_trait<T, F>+{+};++template <typename T, typename F, typename>+struct execute_member :+ execute_member_default<T, F>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_EXECUTE_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/prefer_free.hpp view
@@ -0,0 +1,108 @@+//+// traits/prefer_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_PREFER_FREE_HPP+#define ASIO_TRAITS_PREFER_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct prefer_free_default;++template <typename T, typename Property, typename = void>+struct prefer_free;++} // namespace traits+namespace detail {++struct no_prefer_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)++template <typename T, typename Property, typename = void>+struct prefer_free_trait : no_prefer_free+{+};++template <typename T, typename Property>+struct prefer_free_trait<T, Property,+ typename void_type<+ decltype(prefer(declval<T>(), declval<Property>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ prefer(declval<T>(), declval<Property>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ prefer(declval<T>(), declval<Property>())));+};++#else // defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)++template <typename T, typename Property, typename = void>+struct prefer_free_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_prefer_free,+ traits::prefer_free<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct prefer_free_default :+ detail::prefer_free_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct prefer_free :+ prefer_free_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_PREFER_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/prefer_member.hpp view
@@ -0,0 +1,108 @@+//+// traits/prefer_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_PREFER_MEMBER_HPP+#define ASIO_TRAITS_PREFER_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct prefer_member_default;++template <typename T, typename Property, typename = void>+struct prefer_member;++} // namespace traits+namespace detail {++struct no_prefer_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)++template <typename T, typename Property, typename = void>+struct prefer_member_trait : no_prefer_member+{+};++template <typename T, typename Property>+struct prefer_member_trait<T, Property,+ typename void_type<+ decltype(declval<T>().prefer(declval<Property>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ declval<T>().prefer(declval<Property>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ declval<T>().prefer(declval<Property>())));+};++#else // defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)++template <typename T, typename Property, typename = void>+struct prefer_member_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_prefer_member,+ traits::prefer_member<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct prefer_member_default :+ detail::prefer_member_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct prefer_member :+ prefer_member_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_PREFER_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/query_free.hpp view
@@ -0,0 +1,108 @@+//+// traits/query_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_QUERY_FREE_HPP+#define ASIO_TRAITS_QUERY_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct query_free_default;++template <typename T, typename Property, typename = void>+struct query_free;++} // namespace traits+namespace detail {++struct no_query_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++template <typename T, typename Property, typename = void>+struct query_free_trait : no_query_free+{+};++template <typename T, typename Property>+struct query_free_trait<T, Property,+ typename void_type<+ decltype(query(declval<T>(), declval<Property>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ query(declval<T>(), declval<Property>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ query(declval<T>(), declval<Property>())));+};++#else // defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++template <typename T, typename Property, typename = void>+struct query_free_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_query_free,+ traits::query_free<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct query_free_default :+ detail::query_free_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct query_free :+ query_free_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_QUERY_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/query_member.hpp view
@@ -0,0 +1,108 @@+//+// traits/query_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_QUERY_MEMBER_HPP+#define ASIO_TRAITS_QUERY_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct query_member_default;++template <typename T, typename Property, typename = void>+struct query_member;++} // namespace traits+namespace detail {++struct no_query_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++template <typename T, typename Property, typename = void>+struct query_member_trait : no_query_member+{+};++template <typename T, typename Property>+struct query_member_trait<T, Property,+ typename void_type<+ decltype(declval<T>().query(declval<Property>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ declval<T>().query(declval<Property>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ declval<T>().query(declval<Property>())));+};++#else // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++template <typename T, typename Property, typename = void>+struct query_member_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_query_member,+ traits::query_member<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct query_member_default :+ detail::query_member_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct query_member :+ query_member_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_QUERY_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/query_static_constexpr_member.hpp view
@@ -0,0 +1,108 @@+//+// traits/query_static_constexpr_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP+#define ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_CONSTEXPR) \+ && defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_CONSTEXPR)+ // && defined(ASIO_HAS_CONSTANT_EXPRESSION_SFINAE)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct query_static_constexpr_member_default;++template <typename T, typename Property, typename = void>+struct query_static_constexpr_member;++} // namespace traits+namespace detail {++struct no_query_static_constexpr_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+};++template <typename T, typename Property, typename = void>+struct query_static_constexpr_member_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_query_static_constexpr_member,+ traits::query_static_constexpr_member<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#if defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++template <typename T, typename Property>+struct query_static_constexpr_member_trait<T, Property,+ typename enable_if<+ (static_cast<void>(T::query(Property{})), true)+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(T::query(Property{}));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ noexcept(T::query(Property{})));++ static ASIO_CONSTEXPR result_type value() noexcept(is_noexcept)+ {+ return T::query(Property{});+ }+};++#endif // defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct query_static_constexpr_member_default :+ detail::query_static_constexpr_member_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct query_static_constexpr_member :+ query_static_constexpr_member_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/require_concept_free.hpp view
@@ -0,0 +1,108 @@+//+// traits/require_concept_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_REQUIRE_CONCEPT_FREE_HPP+#define ASIO_TRAITS_REQUIRE_CONCEPT_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct require_concept_free_default;++template <typename T, typename Property, typename = void>+struct require_concept_free;++} // namespace traits+namespace detail {++struct no_require_concept_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT)++template <typename T, typename Property, typename = void>+struct require_concept_free_trait : no_require_concept_free+{+};++template <typename T, typename Property>+struct require_concept_free_trait<T, Property,+ typename void_type<+ decltype(require_concept(declval<T>(), declval<Property>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ require_concept(declval<T>(), declval<Property>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ require_concept(declval<T>(), declval<Property>())));+};++#else // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT)++template <typename T, typename Property, typename = void>+struct require_concept_free_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_require_concept_free,+ traits::require_concept_free<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct require_concept_free_default :+ detail::require_concept_free_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct require_concept_free :+ require_concept_free_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/require_concept_member.hpp view
@@ -0,0 +1,108 @@+//+// traits/require_concept_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP+#define ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct require_concept_member_default;++template <typename T, typename Property, typename = void>+struct require_concept_member;++} // namespace traits+namespace detail {++struct no_require_concept_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT)++template <typename T, typename Property, typename = void>+struct require_concept_member_trait : no_require_concept_member+{+};++template <typename T, typename Property>+struct require_concept_member_trait<T, Property,+ typename void_type<+ decltype(declval<T>().require_concept(declval<Property>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ declval<T>().require_concept(declval<Property>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ declval<T>().require_concept(declval<Property>())));+};++#else // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT)++template <typename T, typename Property, typename = void>+struct require_concept_member_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_require_concept_member,+ traits::require_concept_member<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct require_concept_member_default :+ detail::require_concept_member_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct require_concept_member :+ require_concept_member_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/require_free.hpp view
@@ -0,0 +1,108 @@+//+// traits/require_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_REQUIRE_FREE_HPP+#define ASIO_TRAITS_REQUIRE_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct require_free_default;++template <typename T, typename Property, typename = void>+struct require_free;++} // namespace traits+namespace detail {++struct no_require_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)++template <typename T, typename Property, typename = void>+struct require_free_trait : no_require_free+{+};++template <typename T, typename Property>+struct require_free_trait<T, Property,+ typename void_type<+ decltype(require(declval<T>(), declval<Property>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ require(declval<T>(), declval<Property>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ require(declval<T>(), declval<Property>())));+};++#else // defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)++template <typename T, typename Property, typename = void>+struct require_free_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_require_free,+ traits::require_free<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct require_free_default :+ detail::require_free_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct require_free :+ require_free_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_REQUIRE_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/require_member.hpp view
@@ -0,0 +1,108 @@+//+// traits/require_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_REQUIRE_MEMBER_HPP+#define ASIO_TRAITS_REQUIRE_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct require_member_default;++template <typename T, typename Property, typename = void>+struct require_member;++} // namespace traits+namespace detail {++struct no_require_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++template <typename T, typename Property, typename = void>+struct require_member_trait : no_require_member+{+};++template <typename T, typename Property>+struct require_member_trait<T, Property,+ typename void_type<+ decltype(declval<T>().require(declval<Property>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ declval<T>().require(declval<Property>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ declval<T>().require(declval<Property>())));+};++#else // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++template <typename T, typename Property, typename = void>+struct require_member_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_require_member,+ traits::require_member<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct require_member_default :+ detail::require_member_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct require_member :+ require_member_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_REQUIRE_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/schedule_free.hpp view
@@ -0,0 +1,108 @@+//+// traits/schedule_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_SCHEDULE_FREE_HPP+#define ASIO_TRAITS_SCHEDULE_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename = void>+struct schedule_free_default;++template <typename T, typename = void>+struct schedule_free;++} // namespace traits+namespace detail {++struct no_schedule_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT)++template <typename T, typename = void>+struct schedule_free_trait : no_schedule_free+{+};++template <typename T>+struct schedule_free_trait<T,+ typename void_type<+ decltype(schedule(declval<T>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(schedule(declval<T>()));++ ASIO_STATIC_CONSTEXPR(bool,+ is_noexcept = noexcept(schedule(declval<T>())));+};++#else // defined(ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT)++template <typename T, typename = void>+struct schedule_free_trait :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_schedule_free,+ traits::schedule_free<typename add_const<T>::type>+ >::type,+ traits::schedule_free<typename remove_reference<T>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename>+struct schedule_free_default :+ detail::schedule_free_trait<T>+{+};++template <typename T, typename>+struct schedule_free :+ schedule_free_default<T>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_SCHEDULE_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/schedule_member.hpp view
@@ -0,0 +1,108 @@+//+// traits/schedule_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_SCHEDULE_MEMBER_HPP+#define ASIO_TRAITS_SCHEDULE_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename = void>+struct schedule_member_default;++template <typename T, typename = void>+struct schedule_member;++} // namespace traits+namespace detail {++struct no_schedule_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)++template <typename T, typename = void>+struct schedule_member_trait : no_schedule_member+{+};++template <typename T>+struct schedule_member_trait<T,+ typename void_type<+ decltype(declval<T>().schedule())+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(declval<T>().schedule());++ ASIO_STATIC_CONSTEXPR(bool,+ is_noexcept = noexcept(declval<T>().schedule()));+};++#else // defined(ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)++template <typename T, typename = void>+struct schedule_member_trait :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_schedule_member,+ traits::schedule_member<typename add_const<T>::type>+ >::type,+ traits::schedule_member<typename remove_reference<T>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename>+struct schedule_member_default :+ detail::schedule_member_trait<T>+{+};++template <typename T, typename>+struct schedule_member :+ schedule_member_default<T>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_SCHEDULE_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/set_done_free.hpp view
@@ -0,0 +1,108 @@+//+// traits/set_done_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_SET_DONE_FREE_HPP+#define ASIO_TRAITS_SET_DONE_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename = void>+struct set_done_free_default;++template <typename T, typename = void>+struct set_done_free;++} // namespace traits+namespace detail {++struct no_set_done_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT)++template <typename T, typename = void>+struct set_done_free_trait : no_set_done_free+{+};++template <typename T>+struct set_done_free_trait<T,+ typename void_type<+ decltype(set_done(declval<T>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(set_done(declval<T>()));++ ASIO_STATIC_CONSTEXPR(bool,+ is_noexcept = noexcept(set_done(declval<T>())));+};++#else // defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT)++template <typename T, typename = void>+struct set_done_free_trait :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_set_done_free,+ traits::set_done_free<typename add_const<T>::type>+ >::type,+ traits::set_done_free<typename remove_reference<T>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename>+struct set_done_free_default :+ detail::set_done_free_trait<T>+{+};++template <typename T, typename>+struct set_done_free :+ set_done_free_default<T>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_SET_DONE_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/set_done_member.hpp view
@@ -0,0 +1,108 @@+//+// traits/set_done_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_SET_DONE_MEMBER_HPP+#define ASIO_TRAITS_SET_DONE_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename = void>+struct set_done_member_default;++template <typename T, typename = void>+struct set_done_member;++} // namespace traits+namespace detail {++struct no_set_done_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)++template <typename T, typename = void>+struct set_done_member_trait : no_set_done_member+{+};++template <typename T>+struct set_done_member_trait<T,+ typename void_type<+ decltype(declval<T>().set_done())+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(declval<T>().set_done());++ ASIO_STATIC_CONSTEXPR(bool,+ is_noexcept = noexcept(declval<T>().set_done()));+};++#else // defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)++template <typename T, typename = void>+struct set_done_member_trait :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_set_done_member,+ traits::set_done_member<typename add_const<T>::type>+ >::type,+ traits::set_done_member<typename remove_reference<T>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename>+struct set_done_member_default :+ detail::set_done_member_trait<T>+{+};++template <typename T, typename>+struct set_done_member :+ set_done_member_default<T>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_SET_DONE_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/set_error_free.hpp view
@@ -0,0 +1,112 @@+//+// traits/set_error_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_SET_ERROR_FREE_HPP+#define ASIO_TRAITS_SET_ERROR_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename E, typename = void>+struct set_error_free_default;++template <typename T, typename E, typename = void>+struct set_error_free;++} // namespace traits+namespace detail {++struct no_set_error_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT)++template <typename T, typename E, typename = void>+struct set_error_free_trait : no_set_error_free+{+};++template <typename T, typename E>+struct set_error_free_trait<T, E,+ typename void_type<+ decltype(set_error(declval<T>(), declval<E>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ set_error(declval<T>(), declval<E>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ set_error(declval<T>(), declval<E>())));+};++#else // defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT)++template <typename T, typename E, typename = void>+struct set_error_free_trait :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value+ && is_same<E, typename decay<E>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_set_error_free,+ traits::set_error_free<typename add_const<T>::type, E>+ >::type,+ traits::set_error_free<+ typename remove_reference<T>::type,+ typename decay<E>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename E, typename>+struct set_error_free_default :+ detail::set_error_free_trait<T, E>+{+};++template <typename T, typename E, typename>+struct set_error_free :+ set_error_free_default<T, E>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_SET_ERROR_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/set_error_member.hpp view
@@ -0,0 +1,112 @@+//+// traits/set_error_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_SET_ERROR_MEMBER_HPP+#define ASIO_TRAITS_SET_ERROR_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename E, typename = void>+struct set_error_member_default;++template <typename T, typename E, typename = void>+struct set_error_member;++} // namespace traits+namespace detail {++struct no_set_error_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)++template <typename T, typename E, typename = void>+struct set_error_member_trait : no_set_error_member+{+};++template <typename T, typename E>+struct set_error_member_trait<T, E,+ typename void_type<+ decltype(declval<T>().set_error(declval<E>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ declval<T>().set_error(declval<E>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ declval<T>().set_error(declval<E>())));+};++#else // defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)++template <typename T, typename E, typename = void>+struct set_error_member_trait :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value+ && is_same<E, typename decay<E>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_set_error_member,+ traits::set_error_member<typename add_const<T>::type, E>+ >::type,+ traits::set_error_member<+ typename remove_reference<T>::type,+ typename decay<E>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename E, typename>+struct set_error_member_default :+ detail::set_error_member_trait<T, E>+{+};++template <typename T, typename E, typename>+struct set_error_member :+ set_error_member_default<T, E>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_SET_ERROR_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/set_value_free.hpp view
@@ -0,0 +1,234 @@+//+// traits/set_value_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_SET_VALUE_FREE_HPP+#define ASIO_TRAITS_SET_VALUE_FREE_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/variadic_templates.hpp"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Vs, typename = void>+struct set_value_free_default;++template <typename T, typename Vs, typename = void>+struct set_value_free;++} // namespace traits+namespace detail {++struct no_set_value_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT)++template <typename T, typename Vs, typename = void>+struct set_value_free_trait : no_set_value_free+{+};++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename... Vs>+struct set_value_free_trait<T, void(Vs...),+ typename void_type<+ decltype(set_value(declval<T>(), declval<Vs>()...))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ set_value(declval<T>(), declval<Vs>()...));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ set_value(declval<T>(), declval<Vs>()...)));+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T>+struct set_value_free_trait<T, void(),+ typename void_type<+ decltype(set_value(declval<T>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(set_value(declval<T>()));++ ASIO_STATIC_CONSTEXPR(bool,+ is_noexcept = noexcept(set_value(declval<T>())));+};++#define ASIO_PRIVATE_SET_VALUE_FREE_TRAIT_DEF(n) \+ template <typename T, ASIO_VARIADIC_TPARAMS(n)> \+ struct set_value_free_trait<T, void(ASIO_VARIADIC_TARGS(n)), \+ typename void_type< \+ decltype(set_value(declval<T>(), ASIO_VARIADIC_DECLVAL(n))) \+ >::type> \+ { \+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true); \+ \+ using result_type = decltype( \+ set_value(declval<T>(), ASIO_VARIADIC_DECLVAL(n))); \+ \+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( \+ set_value(declval<T>(), ASIO_VARIADIC_DECLVAL(n)))); \+ }; \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_FREE_TRAIT_DEF)+#undef ASIO_PRIVATE_SET_VALUE_FREE_TRAIT_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#else // defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT)++template <typename T, typename Vs, typename = void>+struct set_value_free_trait;++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename... Vs>+struct set_value_free_trait<T, void(Vs...)> :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value+ && conjunction<is_same<Vs, typename decay<Vs>::type>...>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_set_value_free,+ traits::set_value_free<typename add_const<T>::type, void(Vs...)>+ >::type,+ traits::set_value_free<+ typename remove_reference<T>::type,+ void(typename decay<Vs>::type...)>+ >::type+{+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T>+struct set_value_free_trait<T, void()> :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_set_value_free,+ traits::set_value_free<typename add_const<T>::type, void()>+ >::type,+ traits::set_value_free<typename remove_reference<T>::type, void()>+ >::type+{+};++#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n) \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_##n++#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \+ && is_same<T1, typename decay<T1>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \+ && is_same<T2, typename decay<T2>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \+ && is_same<T3, typename decay<T3>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \+ && is_same<T4, typename decay<T4>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \+ && is_same<T5, typename decay<T5>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \+ && is_same<T6, typename decay<T6>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \+ && is_same<T7, typename decay<T7>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \+ && is_same<T8, typename decay<T8>::type>::value++#define ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF(n) \+ template <typename T, ASIO_VARIADIC_TPARAMS(n)> \+ struct set_value_free_trait<T, void(ASIO_VARIADIC_TARGS(n))> : \+ conditional< \+ is_same<T, typename remove_reference<T>::type>::value \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n), \+ typename conditional< \+ is_same<T, typename add_const<T>::type>::value, \+ no_set_value_free, \+ traits::set_value_free< \+ typename add_const<T>::type, \+ void(ASIO_VARIADIC_TARGS(n))> \+ >::type, \+ traits::set_value_free< \+ typename remove_reference<T>::type, \+ void(ASIO_VARIADIC_DECAY(n))> \+ >::type \+ { \+ }; \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF)+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#endif // defined(ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Vs, typename>+struct set_value_free_default :+ detail::set_value_free_trait<T, Vs>+{+};++template <typename T, typename Vs, typename>+struct set_value_free :+ set_value_free_default<T, Vs>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_SET_VALUE_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/set_value_member.hpp view
@@ -0,0 +1,234 @@+//+// traits/set_value_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_SET_VALUE_MEMBER_HPP+#define ASIO_TRAITS_SET_VALUE_MEMBER_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/variadic_templates.hpp"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Vs, typename = void>+struct set_value_member_default;++template <typename T, typename Vs, typename = void>+struct set_value_member;++} // namespace traits+namespace detail {++struct no_set_value_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)++template <typename T, typename Vs, typename = void>+struct set_value_member_trait : no_set_value_member+{+};++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename... Vs>+struct set_value_member_trait<T, void(Vs...),+ typename void_type<+ decltype(declval<T>().set_value(declval<Vs>()...))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ declval<T>().set_value(declval<Vs>()...));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ declval<T>().set_value(declval<Vs>()...)));+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T>+struct set_value_member_trait<T, void(),+ typename void_type<+ decltype(declval<T>().set_value())+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(declval<T>().set_value());++ ASIO_STATIC_CONSTEXPR(bool,+ is_noexcept = noexcept(declval<T>().set_value()));+};++#define ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF(n) \+ template <typename T, ASIO_VARIADIC_TPARAMS(n)> \+ struct set_value_member_trait<T, void(ASIO_VARIADIC_TARGS(n)), \+ typename void_type< \+ decltype(declval<T>().set_value(ASIO_VARIADIC_DECLVAL(n))) \+ >::type> \+ { \+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true); \+ \+ using result_type = decltype( \+ declval<T>().set_value(ASIO_VARIADIC_DECLVAL(n))); \+ \+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( \+ declval<T>().set_value(ASIO_VARIADIC_DECLVAL(n)))); \+ }; \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF)+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#else // defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)++template <typename T, typename Vs, typename = void>+struct set_value_member_trait;++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T, typename... Vs>+struct set_value_member_trait<T, void(Vs...)> :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value+ && conjunction<is_same<Vs, typename decay<Vs>::type>...>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_set_value_member,+ traits::set_value_member<typename add_const<T>::type, void(Vs...)>+ >::type,+ traits::set_value_member<+ typename remove_reference<T>::type,+ void(typename decay<Vs>::type...)>+ >::type+{+};++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename T>+struct set_value_member_trait<T, void()> :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_set_value_member,+ traits::set_value_member<typename add_const<T>::type, void()>+ >::type,+ traits::set_value_member<typename remove_reference<T>::type, void()>+ >::type+{+};++#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n) \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_##n++#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \+ && is_same<T1, typename decay<T1>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \+ && is_same<T2, typename decay<T2>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \+ && is_same<T3, typename decay<T3>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \+ && is_same<T4, typename decay<T4>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \+ && is_same<T5, typename decay<T5>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \+ && is_same<T6, typename decay<T6>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \+ && is_same<T7, typename decay<T7>::type>::value+#define ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8 \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \+ && is_same<T8, typename decay<T8>::type>::value++#define ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF(n) \+ template <typename T, ASIO_VARIADIC_TPARAMS(n)> \+ struct set_value_member_trait<T, void(ASIO_VARIADIC_TARGS(n))> : \+ conditional< \+ is_same<T, typename remove_reference<T>::type>::value \+ ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n), \+ typename conditional< \+ is_same<T, typename add_const<T>::type>::value, \+ no_set_value_member, \+ traits::set_value_member< \+ typename add_const<T>::type, \+ void(ASIO_VARIADIC_TARGS(n))> \+ >::type, \+ traits::set_value_member< \+ typename remove_reference<T>::type, \+ void(ASIO_VARIADIC_DECAY(n))> \+ >::type \+ { \+ }; \+ /**/+ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF)+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7+#undef ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#endif // defined(ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Vs, typename>+struct set_value_member_default :+ detail::set_value_member_trait<T, Vs>+{+};++template <typename T, typename Vs, typename>+struct set_value_member :+ set_value_member_default<T, Vs>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_SET_VALUE_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/start_free.hpp view
@@ -0,0 +1,108 @@+//+// traits/start_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_START_FREE_HPP+#define ASIO_TRAITS_START_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_START_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename = void>+struct start_free_default;++template <typename T, typename = void>+struct start_free;++} // namespace traits+namespace detail {++struct no_start_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT)++template <typename T, typename = void>+struct start_free_trait : no_start_free+{+};++template <typename T>+struct start_free_trait<T,+ typename void_type<+ decltype(start(declval<T>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(start(declval<T>()));++ ASIO_STATIC_CONSTEXPR(bool,+ is_noexcept = noexcept(start(declval<T>())));+};++#else // defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT)++template <typename T, typename = void>+struct start_free_trait :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_start_free,+ traits::start_free<typename add_const<T>::type>+ >::type,+ traits::start_free<typename remove_reference<T>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_START_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename>+struct start_free_default :+ detail::start_free_trait<T>+{+};++template <typename T, typename>+struct start_free :+ start_free_default<T>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_START_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/start_member.hpp view
@@ -0,0 +1,108 @@+//+// traits/start_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_START_MEMBER_HPP+#define ASIO_TRAITS_START_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_START_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename = void>+struct start_member_default;++template <typename T, typename = void>+struct start_member;++} // namespace traits+namespace detail {++struct no_start_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)++template <typename T, typename = void>+struct start_member_trait : no_start_member+{+};++template <typename T>+struct start_member_trait<T,+ typename void_type<+ decltype(declval<T>().start())+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(declval<T>().start());++ ASIO_STATIC_CONSTEXPR(bool,+ is_noexcept = noexcept(declval<T>().start()));+};++#else // defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)++template <typename T, typename = void>+struct start_member_trait :+ conditional<+ is_same<T, typename remove_reference<T>::type>::value,+ typename conditional<+ is_same<T, typename add_const<T>::type>::value,+ no_start_member,+ traits::start_member<typename add_const<T>::type>+ >::type,+ traits::start_member<typename remove_reference<T>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_START_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename>+struct start_member_default :+ detail::start_member_trait<T>+{+};++template <typename T, typename>+struct start_member :+ start_member_default<T>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_START_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/static_query.hpp view
@@ -0,0 +1,108 @@+//+// traits/static_query.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_STATIC_QUERY_HPP+#define ASIO_TRAITS_STATIC_QUERY_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_CONSTEXPR) \+ && defined(ASIO_HAS_VARIABLE_TEMPLATES) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_CONSTEXPR)+ // && defined(ASIO_HAS_VARIABLE_TEMPLATES)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct static_query_default;++template <typename T, typename Property, typename = void>+struct static_query;++} // namespace traits+namespace detail {++struct no_static_query+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++template <typename T, typename Property, typename = void>+struct static_query_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_static_query,+ traits::static_query<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#if defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)++template <typename T, typename Property>+struct static_query_trait<T, Property,+ typename void_type<+ decltype(decay<Property>::type::template static_query_v<T>)+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ decay<Property>::type::template static_query_v<T>);++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept =+ noexcept(decay<Property>::type::template static_query_v<T>));++ static ASIO_CONSTEXPR result_type value() noexcept(is_noexcept)+ {+ return decay<Property>::type::template static_query_v<T>;+ }+};++#endif // defined(ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct static_query_default : detail::static_query_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct static_query : static_query_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_STATIC_QUERY_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/static_require.hpp view
@@ -0,0 +1,123 @@+//+// traits/static_require.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_STATIC_REQUIRE_HPP+#define ASIO_TRAITS_STATIC_REQUIRE_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/traits/static_query.hpp"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT)+# define ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct static_require_default;++template <typename T, typename Property, typename = void>+struct static_require;++} // namespace traits+namespace detail {++struct no_static_require+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+};++template <typename T, typename Property, typename = void>+struct static_require_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_static_require,+ traits::static_require<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#if defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++template <typename T, typename Property>+struct static_require_trait<T, Property,+ typename enable_if<+ decay<Property>::type::value() == traits::static_query<T, Property>::value()+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+};++#else // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++false_type static_require_test(...);++template <typename T, typename Property>+true_type static_require_test(T*, Property*,+ typename enable_if<+ Property::value() == traits::static_query<T, Property>::value()+ >::type* = 0);++template <typename T, typename Property>+struct has_static_require+{+ ASIO_STATIC_CONSTEXPR(bool, value =+ decltype((static_require_test)(+ static_cast<T*>(0), static_cast<Property*>(0)))::value);+};++template <typename T, typename Property>+struct static_require_trait<T, Property,+ typename enable_if<+ has_static_require<typename decay<T>::type,+ typename decay<Property>::type>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+};++#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#endif // defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct static_require_default : detail::static_require_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct static_require : static_require_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_STATIC_REQUIRE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/static_require_concept.hpp view
@@ -0,0 +1,123 @@+//+// traits/static_require_concept.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_STATIC_REQUIRE_CONCEPT_HPP+#define ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_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/traits/static_query.hpp"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT)+# define ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename T, typename Property, typename = void>+struct static_require_concept_default;++template <typename T, typename Property, typename = void>+struct static_require_concept;++} // namespace traits+namespace detail {++struct no_static_require_concept+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+};++template <typename T, typename Property, typename = void>+struct static_require_concept_trait :+ conditional<+ is_same<T, typename decay<T>::type>::value+ && is_same<Property, typename decay<Property>::type>::value,+ no_static_require_concept,+ traits::static_require_concept<+ typename decay<T>::type,+ typename decay<Property>::type>+ >::type+{+};++#if defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT)++#if defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++template <typename T, typename Property>+struct static_require_concept_trait<T, Property,+ typename enable_if<+ decay<Property>::type::value() == traits::static_query<T, Property>::value()+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+};++#else // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++false_type static_require_concept_test(...);++template <typename T, typename Property>+true_type static_require_concept_test(T*, Property*,+ typename enable_if<+ Property::value() == traits::static_query<T, Property>::value()+ >::type* = 0);++template <typename T, typename Property>+struct has_static_require_concept+{+ ASIO_STATIC_CONSTEXPR(bool, value =+ decltype((static_require_concept_test)(+ static_cast<T*>(0), static_cast<Property*>(0)))::value);+};++template <typename T, typename Property>+struct static_require_concept_trait<T, Property,+ typename enable_if<+ has_static_require_concept<T, typename decay<Property>::type>::value+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);+};++#endif // defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#endif // defined(ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT)++} // namespace detail+namespace traits {++template <typename T, typename Property, typename>+struct static_require_concept_default :+ detail::static_require_concept_trait<T, Property>+{+};++template <typename T, typename Property, typename>+struct static_require_concept : static_require_concept_default<T, Property>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/submit_free.hpp view
@@ -0,0 +1,112 @@+//+// traits/submit_free.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_SUBMIT_FREE_HPP+#define ASIO_TRAITS_SUBMIT_FREE_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename S, typename R, typename = void>+struct submit_free_default;++template <typename S, typename R, typename = void>+struct submit_free;++} // namespace traits+namespace detail {++struct no_submit_free+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)++template <typename S, typename R, typename = void>+struct submit_free_trait : no_submit_free+{+};++template <typename S, typename R>+struct submit_free_trait<S, R,+ typename void_type<+ decltype(submit(declval<S>(), declval<R>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ submit(declval<S>(), declval<R>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ submit(declval<S>(), declval<R>())));+};++#else // defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)++template <typename S, typename R, typename = void>+struct submit_free_trait :+ conditional<+ is_same<S, typename remove_reference<S>::type>::value+ && is_same<R, typename decay<R>::type>::value,+ typename conditional<+ is_same<S, typename add_const<S>::type>::value,+ no_submit_free,+ traits::submit_free<typename add_const<S>::type, R>+ >::type,+ traits::submit_free<+ typename remove_reference<S>::type,+ typename decay<R>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT)++} // namespace detail+namespace traits {++template <typename S, typename R, typename>+struct submit_free_default :+ detail::submit_free_trait<S, R>+{+};++template <typename S, typename R, typename>+struct submit_free :+ submit_free_default<S, R>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_SUBMIT_FREE_HPP
+ link/modules/asio-standalone/asio/include/asio/traits/submit_member.hpp view
@@ -0,0 +1,112 @@+//+// traits/submit_member.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TRAITS_SUBMIT_MEMBER_HPP+#define ASIO_TRAITS_SUBMIT_MEMBER_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"++#if defined(ASIO_HAS_DECLTYPE) \+ && defined(ASIO_HAS_NOEXCEPT) \+ && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)+# define ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT 1+#endif // defined(ASIO_HAS_DECLTYPE)+ // && defined(ASIO_HAS_NOEXCEPT)+ // && defined(ASIO_HAS_WORKING_EXPRESSION_SFINAE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace traits {++template <typename S, typename R, typename = void>+struct submit_member_default;++template <typename S, typename R, typename = void>+struct submit_member;++} // namespace traits+namespace detail {++struct no_submit_member+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = false);+ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);+};++#if defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)++template <typename S, typename R, typename = void>+struct submit_member_trait : no_submit_member+{+};++template <typename S, typename R>+struct submit_member_trait<S, R,+ typename void_type<+ decltype(declval<S>().submit(declval<R>()))+ >::type>+{+ ASIO_STATIC_CONSTEXPR(bool, is_valid = true);++ using result_type = decltype(+ declval<S>().submit(declval<R>()));++ ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(+ declval<S>().submit(declval<R>())));+};++#else // defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)++template <typename S, typename R, typename = void>+struct submit_member_trait :+ conditional<+ is_same<S, typename remove_reference<S>::type>::value+ && is_same<R, typename decay<R>::type>::value,+ typename conditional<+ is_same<S, typename add_const<S>::type>::value,+ no_submit_member,+ traits::submit_member<typename add_const<S>::type, R>+ >::type,+ traits::submit_member<+ typename remove_reference<S>::type,+ typename decay<R>::type>+ >::type+{+};++#endif // defined(ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT)++} // namespace detail+namespace traits {++template <typename S, typename R, typename>+struct submit_member_default :+ detail::submit_member_trait<S, R>+{+};++template <typename S, typename R, typename>+struct submit_member :+ submit_member_default<S, R>+{+};++} // namespace traits+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_TRAITS_SUBMIT_MEMBER_HPP
+ link/modules/asio-standalone/asio/include/asio/ts/buffer.hpp view
@@ -0,0 +1,24 @@+//+// ts/buffer.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TS_BUFFER_HPP+#define ASIO_TS_BUFFER_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/buffer.hpp"+#include "asio/completion_condition.hpp"+#include "asio/read.hpp"+#include "asio/write.hpp"+#include "asio/read_until.hpp"++#endif // ASIO_TS_BUFFER_HPP
+ link/modules/asio-standalone/asio/include/asio/ts/executor.hpp view
@@ -0,0 +1,35 @@+//+// ts/executor.hpp+// ~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TS_EXECUTOR_HPP+#define ASIO_TS_EXECUTOR_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/async_result.hpp"+#include "asio/associated_allocator.hpp"+#include "asio/execution_context.hpp"+#include "asio/is_executor.hpp"+#include "asio/associated_executor.hpp"+#include "asio/bind_executor.hpp"+#include "asio/executor_work_guard.hpp"+#include "asio/system_executor.hpp"+#include "asio/executor.hpp"+#include "asio/any_io_executor.hpp"+#include "asio/dispatch.hpp"+#include "asio/post.hpp"+#include "asio/defer.hpp"+#include "asio/strand.hpp"+#include "asio/packaged_task.hpp"+#include "asio/use_future.hpp"++#endif // ASIO_TS_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/ts/internet.hpp view
@@ -0,0 +1,40 @@+//+// ts/internet.hpp+// ~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TS_INTERNET_HPP+#define ASIO_TS_INTERNET_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/ip/address.hpp"+#include "asio/ip/address_v4.hpp"+#include "asio/ip/address_v4_iterator.hpp"+#include "asio/ip/address_v4_range.hpp"+#include "asio/ip/address_v6.hpp"+#include "asio/ip/address_v6_iterator.hpp"+#include "asio/ip/address_v6_range.hpp"+#include "asio/ip/bad_address_cast.hpp"+#include "asio/ip/basic_endpoint.hpp"+#include "asio/ip/basic_resolver_query.hpp"+#include "asio/ip/basic_resolver_entry.hpp"+#include "asio/ip/basic_resolver_iterator.hpp"+#include "asio/ip/basic_resolver.hpp"+#include "asio/ip/host_name.hpp"+#include "asio/ip/network_v4.hpp"+#include "asio/ip/network_v6.hpp"+#include "asio/ip/tcp.hpp"+#include "asio/ip/udp.hpp"+#include "asio/ip/v6_only.hpp"+#include "asio/ip/unicast.hpp"+#include "asio/ip/multicast.hpp"++#endif // ASIO_TS_INTERNET_HPP
+ link/modules/asio-standalone/asio/include/asio/ts/io_context.hpp view
@@ -0,0 +1,20 @@+//+// ts/io_context.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TS_IO_CONTEXT_HPP+#define ASIO_TS_IO_CONTEXT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/io_context.hpp"++#endif // ASIO_TS_IO_CONTEXT_HPP
+ link/modules/asio-standalone/asio/include/asio/ts/net.hpp view
@@ -0,0 +1,26 @@+//+// ts/net.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TS_NET_HPP+#define ASIO_TS_NET_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/ts/netfwd.hpp"+#include "asio/ts/executor.hpp"+#include "asio/ts/io_context.hpp"+#include "asio/ts/timer.hpp"+#include "asio/ts/buffer.hpp"+#include "asio/ts/socket.hpp"+#include "asio/ts/internet.hpp"++#endif // ASIO_TS_NET_HPP
+ link/modules/asio-standalone/asio/include/asio/ts/netfwd.hpp view
@@ -0,0 +1,262 @@+//+// ts/netfwd.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TS_NETFWD_HPP+#define ASIO_TS_NETFWD_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_CHRONO)+# include "asio/detail/chrono.hpp"+#endif // defined(ASIO_HAS_CHRONO)++#if defined(ASIO_HAS_BOOST_DATE_TIME)+# include "asio/detail/date_time_fwd.hpp"+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)++#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)+#include "asio/execution/blocking.hpp"+#include "asio/execution/outstanding_work.hpp"+#include "asio/execution/relationship.hpp"+#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)++#if !defined(GENERATING_DOCUMENTATION)++#include "asio/detail/push_options.hpp"++namespace asio {++class execution_context;++template <typename T, typename Executor>+class executor_binder;++#if !defined(ASIO_EXECUTOR_WORK_GUARD_DECL)+#define ASIO_EXECUTOR_WORK_GUARD_DECL++template <typename Executor, typename = void>+class executor_work_guard;++#endif // !defined(ASIO_EXECUTOR_WORK_GUARD_DECL)++template <typename Blocking, typename Relationship, typename Allocator>+class basic_system_executor;++#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)++class executor;++typedef executor any_io_executor;++#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)++namespace execution {++#if !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)+#define ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL++#if defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename... SupportableProperties>+class any_executor;++#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)++template <typename = void, typename = void, typename = void,+ typename = void, typename = void, typename = void,+ typename = void, typename = void, typename = void>+class any_executor;++#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)++#endif // !defined(ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL)++template <typename U>+struct context_as_t;++template <typename Property>+struct prefer_only;++} // namespace execution++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>+ > any_io_executor;++#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)++template <typename Executor>+class strand;++class io_context;++template <typename Clock>+struct wait_traits;++#if defined(ASIO_HAS_BOOST_DATE_TIME)++template <typename Time>+struct time_traits;++#endif // defined(ASIO_HAS_BOOST_DATE_TIME)++#if !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)+#define ASIO_BASIC_WAITABLE_TIMER_FWD_DECL++template <typename Clock,+ typename WaitTraits = wait_traits<Clock>,+ typename Executor = any_io_executor>+class basic_waitable_timer;++#endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)++#if defined(ASIO_HAS_CHRONO)++typedef basic_waitable_timer<chrono::system_clock> system_timer;++typedef basic_waitable_timer<chrono::steady_clock> steady_timer;++typedef basic_waitable_timer<chrono::high_resolution_clock>+ high_resolution_timer;++#endif // defined(ASIO_HAS_CHRONO)++#if !defined(ASIO_BASIC_SOCKET_FWD_DECL)+#define ASIO_BASIC_SOCKET_FWD_DECL++template <typename Protocol, typename Executor = any_io_executor>+class basic_socket;++#endif // !defined(ASIO_BASIC_SOCKET_FWD_DECL)++#if !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)+#define ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL++template <typename Protocol, typename Executor = any_io_executor>+class basic_datagram_socket;++#endif // !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)++#if !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL)+#define ASIO_BASIC_STREAM_SOCKET_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename Protocol, typename Executor = any_io_executor>+class basic_stream_socket;++#endif // !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL)++#if !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL)+#define ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL++template <typename Protocol, typename Executor = any_io_executor>+class basic_socket_acceptor;++#endif // !defined(ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL)++#if !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)+#define ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename Protocol,+#if defined(ASIO_HAS_BOOST_DATE_TIME) \+ || defined(GENERATING_DOCUMENTATION)+ typename Clock = boost::posix_time::ptime,+ typename WaitTraits = time_traits<Clock> >+#else+ typename Clock = chrono::steady_clock,+ typename WaitTraits = wait_traits<Clock> >+#endif+class basic_socket_streambuf;++#endif // !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)++#if !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)+#define ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL++// Forward declaration with defaulted arguments.+template <typename Protocol,+#if defined(ASIO_HAS_BOOST_DATE_TIME) \+ || defined(GENERATING_DOCUMENTATION)+ typename Clock = boost::posix_time::ptime,+ typename WaitTraits = time_traits<Clock> >+#else+ typename Clock = chrono::steady_clock,+ typename WaitTraits = wait_traits<Clock> >+#endif+class basic_socket_iostream;++#endif // !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)++namespace ip {++class address;++class address_v4;++class address_v6;++template <typename Address>+class basic_address_iterator;++typedef basic_address_iterator<address_v4> address_v4_iterator;++typedef basic_address_iterator<address_v6> address_v6_iterator;++template <typename Address>+class basic_address_range;++typedef basic_address_range<address_v4> address_v4_range;++typedef basic_address_range<address_v6> address_v6_range;++class network_v4;++class network_v6;++template <typename InternetProtocol>+class basic_endpoint;++template <typename InternetProtocol>+class basic_resolver_entry;++template <typename InternetProtocol>+class basic_resolver_results;++#if !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL)+#define ASIO_IP_BASIC_RESOLVER_FWD_DECL++template <typename InternetProtocol, typename Executor = any_io_executor>+class basic_resolver;++#endif // !defined(ASIO_IP_BASIC_RESOLVER_FWD_DECL)++class tcp;++class udp;++} // namespace ip+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // !defined(GENERATING_DOCUMENTATION)++#endif // ASIO_TS_NETFWD_HPP
+ link/modules/asio-standalone/asio/include/asio/ts/socket.hpp view
@@ -0,0 +1,27 @@+//+// ts/socket.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TS_SOCKET_HPP+#define ASIO_TS_SOCKET_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/socket_base.hpp"+#include "asio/basic_socket.hpp"+#include "asio/basic_datagram_socket.hpp"+#include "asio/basic_stream_socket.hpp"+#include "asio/basic_socket_acceptor.hpp"+#include "asio/basic_socket_streambuf.hpp"+#include "asio/basic_socket_iostream.hpp"+#include "asio/connect.hpp"++#endif // ASIO_TS_SOCKET_HPP
+ link/modules/asio-standalone/asio/include/asio/ts/timer.hpp view
@@ -0,0 +1,26 @@+//+// ts/timer.hpp+// ~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_TS_TIMER_HPP+#define ASIO_TS_TIMER_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/chrono.hpp"++#include "asio/wait_traits.hpp"+#include "asio/basic_waitable_timer.hpp"+#include "asio/system_timer.hpp"+#include "asio/steady_timer.hpp"+#include "asio/high_resolution_timer.hpp"++#endif // ASIO_TS_TIMER_HPP
+ link/modules/asio-standalone/asio/include/asio/unyield.hpp view
@@ -0,0 +1,21 @@+//+// unyield.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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)+//++#ifdef reenter+# undef reenter+#endif++#ifdef yield+# undef yield+#endif++#ifdef fork+# undef fork+#endif
+ link/modules/asio-standalone/asio/include/asio/use_awaitable.hpp view
@@ -0,0 +1,169 @@+//+// use_awaitable.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_USE_AWAITABLE_HPP+#define ASIO_USE_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)++#include "asio/awaitable.hpp"+#include "asio/detail/handler_tracking.hpp"++#if defined(ASIO_ENABLE_HANDLER_TRACKING)+# if defined(ASIO_HAS_SOURCE_LOCATION)+# include "asio/detail/source_location.hpp"+# endif // defined(ASIO_HAS_SOURCE_LOCATION)+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)++#include "asio/detail/push_options.hpp"++namespace asio {++/// A completion token that represents the currently executing coroutine.+/**+ * The @c use_awaitable_t class, with its value @c use_awaitable, is used to+ * represent the currently executing coroutine. This completion token may be+ * passed as a handler to an asynchronous operation. For example:+ *+ * @code awaitable<void> my_coroutine()+ * {+ * std::size_t n = co_await my_socket.async_read_some(buffer, use_awaitable);+ * ...+ * } @endcode+ *+ * When used with co_await, the initiating function (@c async_read_some in the+ * above example) suspends the current coroutine. The coroutine is resumed when+ * the asynchronous operation completes, and the result of the operation is+ * returned.+ */+template <typename Executor = any_io_executor>+struct use_awaitable_t+{+ /// Default constructor.+ ASIO_CONSTEXPR use_awaitable_t(+#if defined(ASIO_ENABLE_HANDLER_TRACKING)+# if defined(ASIO_HAS_SOURCE_LOCATION)+ detail::source_location location = detail::source_location::current()+# endif // defined(ASIO_HAS_SOURCE_LOCATION)+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)+ )+#if defined(ASIO_ENABLE_HANDLER_TRACKING)+# if defined(ASIO_HAS_SOURCE_LOCATION)+ : file_name_(location.file_name()),+ line_(location.line()),+ function_name_(location.function_name())+# else // defined(ASIO_HAS_SOURCE_LOCATION)+ : file_name_(0),+ line_(0),+ function_name_(0)+# endif // defined(ASIO_HAS_SOURCE_LOCATION)+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)+ {+ }++ /// Constructor used to specify file name, line, and function name.+ ASIO_CONSTEXPR use_awaitable_t(const char* file_name,+ int line, const char* function_name)+#if defined(ASIO_ENABLE_HANDLER_TRACKING)+ : file_name_(file_name),+ line_(line),+ function_name_(function_name)+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)+ {+#if !defined(ASIO_ENABLE_HANDLER_TRACKING)+ (void)file_name;+ (void)line;+ (void)function_name;+#endif // !defined(ASIO_ENABLE_HANDLER_TRACKING)+ }++ /// Adapts an executor to add the @c use_awaitable_t completion token as the+ /// default.+ template <typename InnerExecutor>+ struct executor_with_default : InnerExecutor+ {+ /// Specify @c use_awaitable_t as the default completion token type.+ typedef use_awaitable_t default_completion_token_type;++ /// Construct the adapted executor from the inner executor type.+ executor_with_default(const InnerExecutor& ex) ASIO_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,+ typename enable_if<+ is_convertible<OtherExecutor, InnerExecutor>::value+ >::type* = 0) ASIO_NOEXCEPT+ : InnerExecutor(ex)+ {+ }+ };++ /// Type alias to adapt an I/O object to use @c use_awaitable_t as its+ /// default completion token type.+#if defined(ASIO_HAS_ALIAS_TEMPLATES) \+ || defined(GENERATING_DOCUMENTATION)+ template <typename T>+ using as_default_on_t = typename T::template rebind_executor<+ executor_with_default<typename T::executor_type> >::other;+#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)+ // || defined(GENERATING_DOCUMENTATION)++ /// Function helper to adapt an I/O object to use @c use_awaitable_t as its+ /// default completion token type.+ template <typename T>+ static typename decay<T>::type::template rebind_executor<+ executor_with_default<typename decay<T>::type::executor_type>+ >::other+ as_default_on(ASIO_MOVE_ARG(T) object)+ {+ return typename decay<T>::type::template rebind_executor<+ executor_with_default<typename decay<T>::type::executor_type>+ >::other(ASIO_MOVE_CAST(T)(object));+ }++#if defined(ASIO_ENABLE_HANDLER_TRACKING)+ const char* file_name_;+ int line_;+ const char* function_name_;+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)+};++/// A completion token object that represents the currently executing coroutine.+/**+ * See the documentation for asio::use_awaitable_t for a usage example.+ */+#if defined(GENERATING_DOCUMENTATION)+constexpr use_awaitable_t<> use_awaitable;+#elif defined(ASIO_HAS_CONSTEXPR)+constexpr use_awaitable_t<> use_awaitable(0, 0, 0);+#elif defined(ASIO_MSVC)+__declspec(selectany) use_awaitable_t<> use_awaitable(0, 0, 0);+#endif++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/use_awaitable.hpp"++#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_USE_AWAITABLE_HPP
+ link/modules/asio-standalone/asio/include/asio/use_future.hpp view
@@ -0,0 +1,160 @@+//+// use_future.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_USE_FUTURE_HPP+#define ASIO_USE_FUTURE_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/future.hpp"++#if defined(ASIO_HAS_STD_FUTURE_CLASS) \+ || defined(GENERATING_DOCUMENTATION)++#include <memory>+#include "asio/detail/type_traits.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace detail {++template <typename Function, typename Allocator>+class packaged_token;++template <typename Function, typename Allocator, typename Result>+class packaged_handler;++} // namespace detail++/// Class used to specify that an asynchronous operation should return a future.+/**+ * The use_future_t class is used to indicate that an asynchronous operation+ * should return a std::future object. A use_future_t object may be passed as a+ * handler to an asynchronous operation, typically using the special value @c+ * asio::use_future. For example:+ *+ * @code std::future<std::size_t> my_future+ * = my_socket.async_read_some(my_buffer, asio::use_future); @endcode+ *+ * The initiating function (async_read_some in the above example) returns a+ * future that will receive the result of the operation. If the operation+ * completes with an error_code indicating failure, it is converted into a+ * system_error and passed back to the caller via the future.+ */+template <typename Allocator = std::allocator<void> >+class use_future_t+{+public:+ /// The allocator type. The allocator is used when constructing the+ /// @c std::promise object for a given asynchronous operation.+ typedef Allocator allocator_type;++ /// Construct using default-constructed allocator.+ ASIO_CONSTEXPR use_future_t()+ {+ }++ /// Construct using specified allocator.+ explicit use_future_t(const Allocator& allocator)+ : allocator_(allocator)+ {+ }++#if !defined(ASIO_NO_DEPRECATED)+ /// (Deprecated: Use rebind().) Specify an alternate allocator.+ template <typename OtherAllocator>+ use_future_t<OtherAllocator> operator[](const OtherAllocator& allocator) const+ {+ return use_future_t<OtherAllocator>(allocator);+ }+#endif // !defined(ASIO_NO_DEPRECATED)++ /// Specify an alternate allocator.+ template <typename OtherAllocator>+ use_future_t<OtherAllocator> rebind(const OtherAllocator& allocator) const+ {+ return use_future_t<OtherAllocator>(allocator);+ }++ /// Obtain allocator.+ allocator_type get_allocator() const+ {+ return allocator_;+ }++ /// Wrap a function object in a packaged task.+ /**+ * The @c package function is used to adapt a function object as a packaged+ * task. When this adapter is passed as a completion token to an asynchronous+ * operation, the result of the function object is retuned via a std::future.+ *+ * @par Example+ *+ * @code std::future<std::size_t> fut =+ * my_socket.async_read_some(buffer,+ * use_future([](asio::error_code ec, std::size_t n)+ * {+ * return ec ? 0 : n;+ * }));+ * ...+ * std::size_t n = fut.get(); @endcode+ */+ template <typename Function>+#if defined(GENERATING_DOCUMENTATION)+ unspecified+#else // defined(GENERATING_DOCUMENTATION)+ detail::packaged_token<typename decay<Function>::type, Allocator>+#endif // defined(GENERATING_DOCUMENTATION)+ operator()(ASIO_MOVE_ARG(Function) f) const;++private:+ // Helper type to ensure that use_future can be constexpr default-constructed+ // even when std::allocator<void> can't be.+ struct std_allocator_void+ {+ ASIO_CONSTEXPR std_allocator_void()+ {+ }++ operator std::allocator<void>() const+ {+ return std::allocator<void>();+ }+ };++ typename conditional<+ is_same<std::allocator<void>, Allocator>::value,+ std_allocator_void, Allocator>::type allocator_;+};++/// A special value, similar to std::nothrow.+/**+ * See the documentation for asio::use_future_t for a usage example.+ */+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr use_future_t<> use_future;+#elif defined(ASIO_MSVC)+__declspec(selectany) use_future_t<> use_future;+#endif++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/use_future.hpp"++#endif // defined(ASIO_HAS_STD_FUTURE_CLASS)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_USE_FUTURE_HPP
+ link/modules/asio-standalone/asio/include/asio/uses_executor.hpp view
@@ -0,0 +1,71 @@+//+// uses_executor.hpp+// ~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_USES_EXECUTOR_HPP+#define ASIO_USES_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/detail/push_options.hpp"++namespace asio {++/// A special type, similar to std::nothrow_t, used to disambiguate+/// constructors that accept executor arguments.+/**+ * The executor_arg_t struct is an empty structure type used as a unique type+ * to disambiguate constructor and function overloading. Specifically, some+ * types have constructors with executor_arg_t as the first argument,+ * immediately followed by an argument of a type that satisfies the Executor+ * type requirements.+ */+struct executor_arg_t+{+ /// Constructor.+ ASIO_CONSTEXPR executor_arg_t() ASIO_NOEXCEPT+ {+ }+};++/// A special value, similar to std::nothrow, used to disambiguate constructors+/// that accept executor arguments.+/**+ * See asio::executor_arg_t and asio::uses_executor+ * for more information.+ */+#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)+constexpr executor_arg_t executor_arg;+#elif defined(ASIO_MSVC)+__declspec(selectany) executor_arg_t executor_arg;+#endif++/// The uses_executor trait detects whether a type T has an associated executor+/// that is convertible from type Executor.+/**+ * Meets the BinaryTypeTrait requirements. The Asio library provides a+ * definition that is derived from false_type. A program may specialize this+ * template to derive from true_type for a user-defined type T that can be+ * constructed with an executor, where the first argument of a constructor has+ * type executor_arg_t and the second argument is convertible from type+ * Executor.+ */+template <typename T, typename Executor>+struct uses_executor : false_type {};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_USES_EXECUTOR_HPP
+ link/modules/asio-standalone/asio/include/asio/version.hpp view
@@ -0,0 +1,23 @@+//+// version.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_VERSION_HPP+#define ASIO_VERSION_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++// ASIO_VERSION % 100 is the sub-minor version+// ASIO_VERSION / 100 % 1000 is the minor version+// ASIO_VERSION / 100000 is the major version+#define ASIO_VERSION 101700 // 1.17.0++#endif // ASIO_VERSION_HPP
+ link/modules/asio-standalone/asio/include/asio/wait_traits.hpp view
@@ -0,0 +1,56 @@+//+// wait_traits.hpp+// ~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WAIT_TRAITS_HPP+#define ASIO_WAIT_TRAITS_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/push_options.hpp"++namespace asio {++/// Wait traits suitable for use with the basic_waitable_timer class template.+template <typename Clock>+struct wait_traits+{+ /// Convert a clock duration into a duration used for waiting.+ /**+ * @returns @c d.+ */+ static typename Clock::duration to_wait_duration(+ const typename Clock::duration& d)+ {+ return d;+ }++ /// Convert a clock duration into a duration used for waiting.+ /**+ * @returns @c d.+ */+ static typename Clock::duration to_wait_duration(+ const typename Clock::time_point& t)+ {+ typename Clock::time_point now = Clock::now();+ if (now + (Clock::duration::max)() < t)+ return (Clock::duration::max)();+ if (now + (Clock::duration::min)() > t)+ return (Clock::duration::min)();+ return t - now;+ }+};++} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // ASIO_WAIT_TRAITS_HPP
+ link/modules/asio-standalone/asio/include/asio/windows/basic_object_handle.hpp view
@@ -0,0 +1,435 @@+//+// windows/basic_object_handle.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2011 Boris Schaeling (boris@highscore.de)+//+// 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_WINDOWS_BASIC_OBJECT_HANDLE_HPP+#define ASIO_WINDOWS_BASIC_OBJECT_HANDLE_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_WINDOWS_OBJECT_HANDLE) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/any_io_executor.hpp"+#include "asio/async_result.hpp"+#include "asio/detail/io_object_impl.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/win_object_handle_service.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"++#if defined(ASIO_HAS_MOVE)+# include <utility>+#endif // defined(ASIO_HAS_MOVE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace windows {++/// Provides object-oriented handle functionality.+/**+ * The windows::basic_object_handle class provides asynchronous and blocking+ * object-oriented handle functionality.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename Executor = any_io_executor>+class basic_object_handle+{+public:+ /// The type of the executor associated with the object.+ typedef Executor executor_type;++ /// Rebinds the handle type to another executor.+ template <typename Executor1>+ struct rebind_executor+ {+ /// The handle type when rebound to the specified executor.+ typedef basic_object_handle<Executor1> other;+ };++ /// The native representation of a handle.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined native_handle_type;+#else+ typedef asio::detail::win_object_handle_service::native_handle_type+ native_handle_type;+#endif++ /// An object handle is always the lowest layer.+ typedef basic_object_handle lowest_layer_type;++ /// Construct an object handle without opening it.+ /**+ * This constructor creates an object handle without opening it.+ *+ * @param ex The I/O executor that the object handle will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * object handle.+ */+ explicit basic_object_handle(const executor_type& ex)+ : impl_(ex)+ {+ }++ /// Construct an object handle without opening it.+ /**+ * This constructor creates an object handle without opening it.+ *+ * @param context An execution context which provides the I/O executor that+ * the object handle will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the object handle.+ */+ template <typename ExecutionContext>+ explicit basic_object_handle(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value,+ basic_object_handle+ >::type* = 0)+ : impl_(context)+ {+ }++ /// Construct an object handle on an existing native handle.+ /**+ * This constructor creates an object handle object to hold an existing native+ * handle.+ *+ * @param ex The I/O executor that the object handle will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the+ * object handle.+ *+ * @param native_handle The new underlying handle implementation.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_object_handle(const executor_type& ex,+ const native_handle_type& native_handle)+ : impl_(ex)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(), native_handle, ec);+ asio::detail::throw_error(ec, "assign");+ }++ /// Construct an object handle on an existing native handle.+ /**+ * This constructor creates an object handle object to hold an existing native+ * handle.+ *+ * @param context An execution context which provides the I/O executor that+ * the object handle will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the object handle.+ *+ * @param native_handle The new underlying handle implementation.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_object_handle(ExecutionContext& context,+ const native_handle_type& native_handle,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(), native_handle, ec);+ asio::detail::throw_error(ec, "assign");+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct an object handle from another.+ /**+ * This constructor moves an object handle from one object to another.+ *+ * @param other The other object handle 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_object_handle(const executor_type&)+ * constructor.+ */+ basic_object_handle(basic_object_handle&& other)+ : impl_(std::move(other.impl_))+ {+ }++ /// Move-assign an object handle from another.+ /**+ * This assignment operator moves an object handle from one object to another.+ *+ * @param other The other object handle 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_object_handle(const executor_type&)+ * constructor.+ */+ basic_object_handle& operator=(basic_object_handle&& other)+ {+ impl_ = std::move(other.impl_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_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 an object handle 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 an object handle 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 handle to the handle.+ /*+ * This function opens the handle to hold an existing native handle.+ *+ * @param handle A native handle.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void assign(const native_handle_type& handle)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(), handle, ec);+ asio::detail::throw_error(ec, "assign");+ }++ /// Assign an existing native handle to the handle.+ /*+ * This function opens the handle to hold an existing native handle.+ *+ * @param handle A native handle.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ ASIO_SYNC_OP_VOID assign(const native_handle_type& handle,+ asio::error_code& ec)+ {+ impl_.get_service().assign(impl_.get_implementation(), handle, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Determine whether the handle is open.+ bool is_open() const+ {+ return impl_.get_service().is_open(impl_.get_implementation());+ }++ /// Close the handle.+ /**+ * This function is used to close the handle. 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.+ */+ void close()+ {+ asio::error_code ec;+ impl_.get_service().close(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "close");+ }++ /// Close the handle.+ /**+ * This function is used to close the handle. 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.+ */+ ASIO_SYNC_OP_VOID close(asio::error_code& ec)+ {+ impl_.get_service().close(impl_.get_implementation(), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Get the native handle representation.+ /**+ * This function may be used to obtain the underlying representation of the+ * handle. This is intended to allow access to native handle 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 handle.+ /**+ * This function causes all outstanding asynchronous read or 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 handle.+ /**+ * This function causes all outstanding asynchronous read or 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);+ }++ /// Perform a blocking wait on the object handle.+ /**+ * This function is used to wait for the object handle to be set to the+ * signalled state. This function blocks and does not return until the object+ * handle has been set to the signalled state.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void wait()+ {+ asio::error_code ec;+ impl_.get_service().wait(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "wait");+ }++ /// Perform a blocking wait on the object handle.+ /**+ * This function is used to wait for the object handle to be set to the+ * signalled state. This function blocks and does not return until the object+ * handle has been set to the signalled state.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ void wait(asio::error_code& ec)+ {+ impl_.get_service().wait(impl_.get_implementation(), ec);+ }++ /// Start an asynchronous wait on the object handle.+ /**+ * This function is be used to initiate an asynchronous wait against the+ * object handle. It always returns immediately.+ *+ * @param handler The handler to be called when the object handle is set to+ * the signalled state. Copies will be made of the handler as required. The+ * function signature of the handler must be:+ * @code void handler(+ * const asio::error_code& error // Result of operation.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+ template <+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))+ WaitHandler ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,+ void (asio::error_code))+ async_wait(+ ASIO_MOVE_ARG(WaitHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WaitHandler, void (asio::error_code)>(+ initiate_async_wait(this), handler);+ }++private:+ // Disallow copying and assignment.+ basic_object_handle(const basic_object_handle&) ASIO_DELETED;+ basic_object_handle& operator=(const basic_object_handle&) ASIO_DELETED;++ class initiate_async_wait+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_wait(basic_object_handle* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WaitHandler>+ void operator()(ASIO_MOVE_ARG(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_object_handle* self_;+ };++ asio::detail::io_object_impl<+ asio::detail::win_object_handle_service, Executor> impl_;+};++} // namespace windows+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP
+ link/modules/asio-standalone/asio/include/asio/windows/basic_overlapped_handle.hpp view
@@ -0,0 +1,361 @@+//+// windows/basic_overlapped_handle.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINDOWS_BASIC_OVERLAPPED_HANDLE_HPP+#define ASIO_WINDOWS_BASIC_OVERLAPPED_HANDLE_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_WINDOWS_RANDOM_ACCESS_HANDLE) \+ || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \+ || defined(GENERATING_DOCUMENTATION)++#include <cstddef>+#include "asio/any_io_executor.hpp"+#include "asio/async_result.hpp"+#include "asio/detail/io_object_impl.hpp"+#include "asio/detail/throw_error.hpp"+#include "asio/detail/win_iocp_handle_service.hpp"+#include "asio/error.hpp"+#include "asio/execution_context.hpp"++#if defined(ASIO_HAS_MOVE)+# include <utility>+#endif // defined(ASIO_HAS_MOVE)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace windows {++/// Provides Windows handle functionality for objects that support+/// overlapped I/O.+/**+ * The windows::overlapped_handle class provides the ability to wrap a Windows+ * handle. The underlying object referred to by the handle must support+ * overlapped I/O.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename Executor = any_io_executor>+class basic_overlapped_handle+{+public:+ /// The type of the executor associated with the object.+ typedef Executor executor_type;++ /// Rebinds the handle type to another executor.+ template <typename Executor1>+ struct rebind_executor+ {+ /// The handle type when rebound to the specified executor.+ typedef basic_overlapped_handle<Executor1> other;+ };++ /// The native representation of a handle.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined native_handle_type;+#else+ typedef asio::detail::win_iocp_handle_service::native_handle_type+ native_handle_type;+#endif++ /// An overlapped_handle is always the lowest layer.+ typedef basic_overlapped_handle lowest_layer_type;++ /// Construct an overlapped handle without opening it.+ /**+ * This constructor creates an overlapped handle without opening it.+ *+ * @param ex The I/O executor that the overlapped handle will use, by default,+ * to dispatch handlers for any asynchronous operations performed on the+ * overlapped handle.+ */+ explicit basic_overlapped_handle(const executor_type& ex)+ : impl_(ex)+ {+ }++ /// Construct an overlapped handle without opening it.+ /**+ * This constructor creates an overlapped handle without opening it.+ *+ * @param context An execution context which provides the I/O executor that+ * the overlapped handle will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the overlapped handle.+ */+ template <typename ExecutionContext>+ explicit basic_overlapped_handle(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value,+ basic_overlapped_handle+ >::type* = 0)+ : impl_(context)+ {+ }++ /// Construct an overlapped handle on an existing native handle.+ /**+ * This constructor creates an overlapped handle object to hold an existing+ * native handle.+ *+ * @param ex The I/O executor that the overlapped handle will use, by default,+ * to dispatch handlers for any asynchronous operations performed on the+ * overlapped handle.+ *+ * @param native_handle The new underlying handle implementation.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_overlapped_handle(const executor_type& ex,+ const native_handle_type& native_handle)+ : impl_(ex)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(), native_handle, ec);+ asio::detail::throw_error(ec, "assign");+ }++ /// Construct an overlapped handle on an existing native handle.+ /**+ * This constructor creates an overlapped handle object to hold an existing+ * native handle.+ *+ * @param context An execution context which provides the I/O executor that+ * the overlapped handle will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the overlapped handle.+ *+ * @param native_handle The new underlying handle implementation.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_overlapped_handle(ExecutionContext& context,+ const native_handle_type& native_handle,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(), native_handle, ec);+ asio::detail::throw_error(ec, "assign");+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct an overlapped handle from another.+ /**+ * This constructor moves a handle from one object to another.+ *+ * @param other The other overlapped handle 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 overlapped_handle(const executor_type&)+ * constructor.+ */+ basic_overlapped_handle(basic_overlapped_handle&& other)+ : impl_(std::move(other.impl_))+ {+ }++ /// Move-assign an overlapped handle from another.+ /**+ * This assignment operator moves a handle from one object to another.+ *+ * @param other The other overlapped handle 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 overlapped_handle(const executor_type&)+ * constructor.+ */+ basic_overlapped_handle& operator=(basic_overlapped_handle&& other)+ {+ impl_ = std::move(other.impl_);+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Get the executor associated with the object.+ executor_type get_executor() ASIO_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 an overlapped_handle 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 an overlapped_handle 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 handle to the handle.+ /*+ * This function opens the handle to hold an existing native handle.+ *+ * @param handle A native handle.+ *+ * @throws asio::system_error Thrown on failure.+ */+ void assign(const native_handle_type& handle)+ {+ asio::error_code ec;+ impl_.get_service().assign(impl_.get_implementation(), handle, ec);+ asio::detail::throw_error(ec, "assign");+ }++ /// Assign an existing native handle to the handle.+ /*+ * This function opens the handle to hold an existing native handle.+ *+ * @param handle A native handle.+ *+ * @param ec Set to indicate what error occurred, if any.+ */+ ASIO_SYNC_OP_VOID assign(const native_handle_type& handle,+ asio::error_code& ec)+ {+ impl_.get_service().assign(impl_.get_implementation(), handle, ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Determine whether the handle is open.+ bool is_open() const+ {+ return impl_.get_service().is_open(impl_.get_implementation());+ }++ /// Close the handle.+ /**+ * This function is used to close the handle. 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.+ */+ void close()+ {+ asio::error_code ec;+ impl_.get_service().close(impl_.get_implementation(), ec);+ asio::detail::throw_error(ec, "close");+ }++ /// Close the handle.+ /**+ * This function is used to close the handle. 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.+ */+ ASIO_SYNC_OP_VOID close(asio::error_code& ec)+ {+ impl_.get_service().close(impl_.get_implementation(), ec);+ ASIO_SYNC_OP_VOID_RETURN(ec);+ }++ /// Get the native handle representation.+ /**+ * This function may be used to obtain the underlying representation of the+ * handle. This is intended to allow access to native handle 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 handle.+ /**+ * This function causes all outstanding asynchronous read or 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 handle.+ /**+ * This function causes all outstanding asynchronous read or 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);+ }++protected:+ /// Protected destructor to prevent deletion through this type.+ /**+ * This function destroys the handle, cancelling any outstanding asynchronous+ * wait operations associated with the handle as if by calling @c cancel.+ */+ ~basic_overlapped_handle()+ {+ }++ asio::detail::io_object_impl<+ asio::detail::win_iocp_handle_service, Executor> impl_;++private:+ // Disallow copying and assignment.+ basic_overlapped_handle(const basic_overlapped_handle&) ASIO_DELETED;+ basic_overlapped_handle& operator=(+ const basic_overlapped_handle&) ASIO_DELETED;+};++} // namespace windows+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)+ // || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_WINDOWS_BASIC_OVERLAPPED_HANDLE_HPP
+ link/modules/asio-standalone/asio/include/asio/windows/basic_random_access_handle.hpp view
@@ -0,0 +1,490 @@+//+// windows/basic_random_access_handle.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP+#define ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/windows/basic_overlapped_handle.hpp"++#if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace windows {++/// Provides random-access handle functionality.+/**+ * The windows::basic_random_access_handle class provides asynchronous and+ * blocking random-access handle functionality.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+template <typename Executor = any_io_executor>+class basic_random_access_handle+ : public basic_overlapped_handle<Executor>+{+public:+ /// The type of the executor associated with the object.+ typedef Executor executor_type;++ /// Rebinds the handle type to another executor.+ template <typename Executor1>+ struct rebind_executor+ {+ /// The handle type when rebound to the specified executor.+ typedef basic_random_access_handle<Executor1> other;+ };++ /// The native representation of a handle.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined native_handle_type;+#else+ typedef asio::detail::win_iocp_handle_service::native_handle_type+ native_handle_type;+#endif++ /// Construct a random-access handle without opening it.+ /**+ * This constructor creates a random-access handle without opening it.+ *+ * @param ex The I/O executor that the random-access handle will use, by+ * default, to dispatch handlers for any asynchronous operations performed on+ * the random-access handle.+ */+ explicit basic_random_access_handle(const executor_type& ex)+ : basic_overlapped_handle<Executor>(ex)+ {+ }++ /// Construct a random-access handle without opening it.+ /**+ * This constructor creates a random-access handle without opening it. The+ * handle needs to be opened or assigned before data can be sent or received+ * on it.+ *+ * @param context An execution context which provides the I/O executor that+ * the random-access handle will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the random-access handle.+ */+ template <typename ExecutionContext>+ explicit basic_random_access_handle(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value,+ basic_random_access_handle+ >::type* = 0)+ : basic_overlapped_handle<Executor>(context)+ {+ }++ /// Construct a random-access handle on an existing native handle.+ /**+ * This constructor creates a random-access handle object to hold an existing+ * native handle.+ *+ * @param ex The I/O executor that the random-access handle will use, by+ * default, to dispatch handlers for any asynchronous operations performed on+ * the random-access handle.+ *+ * @param handle The new underlying handle implementation.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_random_access_handle(const executor_type& ex,+ const native_handle_type& handle)+ : basic_overlapped_handle<Executor>(ex, handle)+ {+ }++ /// Construct a random-access handle on an existing native handle.+ /**+ * This constructor creates a random-access handle object to hold an existing+ * native handle.+ *+ * @param context An execution context which provides the I/O executor that+ * the random-access handle will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the random-access handle.+ *+ * @param handle The new underlying handle implementation.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_random_access_handle(ExecutionContext& context,+ const native_handle_type& handle,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_overlapped_handle<Executor>(context, handle)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a random-access handle from another.+ /**+ * This constructor moves a random-access handle from one object to another.+ *+ * @param other The other random-access handle 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_handle(const executor_type&)+ * constructor.+ */+ basic_random_access_handle(basic_random_access_handle&& other)+ : basic_overlapped_handle<Executor>(std::move(other))+ {+ }++ /// Move-assign a random-access handle from another.+ /**+ * This assignment operator moves a random-access handle from one object to+ * another.+ *+ * @param other The other random-access handle 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_handle(const executor_type&)+ * constructor.+ */+ basic_random_access_handle& operator=(basic_random_access_handle&& other)+ {+ basic_overlapped_handle<Executor>::operator=(std::move(other));+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// 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 connection was closed by the+ * peer.+ *+ * @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 transmit all of the data to the+ * peer. 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. The function call 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 handler is called.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the 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 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().+ *+ * @note The write operation may not transmit all of the data to the peer.+ * 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.+ */+ template <typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_write_some_at(uint64_t offset,+ const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_write_some_at(this), handler, 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 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_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. The function call 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 handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the 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 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().+ *+ * @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.+ */+ template <typename MutableBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_read_some_at(uint64_t offset,+ const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_read_some_at(this), handler, offset, buffers);+ }++private:+ class initiate_async_write_some_at+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_write_some_at(basic_random_access_handle* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(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_handle* self_;+ };++ class initiate_async_read_some_at+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_read_some_at(basic_random_access_handle* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(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_handle* self_;+ };+};++} // namespace windows+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP
+ link/modules/asio-standalone/asio/include/asio/windows/basic_stream_handle.hpp view
@@ -0,0 +1,474 @@+//+// windows/basic_stream_handle.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINDOWS_BASIC_STREAM_HANDLE_HPP+#define ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include "asio/windows/basic_overlapped_handle.hpp"++#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/detail/push_options.hpp"++namespace asio {+namespace windows {++/// Provides stream-oriented handle functionality.+/**+ * The windows::basic_stream_handle class provides asynchronous and blocking+ * stream-oriented handle 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 = any_io_executor>+class basic_stream_handle+ : public basic_overlapped_handle<Executor>+{+public:+ /// The type of the executor associated with the object.+ typedef Executor executor_type;++ /// Rebinds the handle type to another executor.+ template <typename Executor1>+ struct rebind_executor+ {+ /// The handle type when rebound to the specified executor.+ typedef basic_stream_handle<Executor1> other;+ };++ /// The native representation of a handle.+#if defined(GENERATING_DOCUMENTATION)+ typedef implementation_defined native_handle_type;+#else+ typedef asio::detail::win_iocp_handle_service::native_handle_type+ native_handle_type;+#endif++ /// Construct a stream handle without opening it.+ /**+ * This constructor creates a stream handle without opening it.+ *+ * @param ex The I/O executor that the stream handle will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the stream+ * handle.+ */+ explicit basic_stream_handle(const executor_type& ex)+ : basic_overlapped_handle<Executor>(ex)+ {+ }++ /// Construct a stream handle without opening it.+ /**+ * This constructor creates a stream handle without opening it. The handle+ * needs to be opened or assigned before data can be sent or received on it.+ *+ * @param context An execution context which provides the I/O executor that+ * the stream handle will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the stream handle.+ */+ template <typename ExecutionContext>+ explicit basic_stream_handle(ExecutionContext& context,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value,+ basic_stream_handle+ >::type* = 0)+ : basic_overlapped_handle<Executor>(context)+ {+ }++ /// Construct a stream handle on an existing native handle.+ /**+ * This constructor creates a stream handle object to hold an existing native+ * handle.+ *+ * @param ex The I/O executor that the stream handle will use, by default, to+ * dispatch handlers for any asynchronous operations performed on the stream+ * handle.+ *+ * @param handle The new underlying handle implementation.+ *+ * @throws asio::system_error Thrown on failure.+ */+ basic_stream_handle(const executor_type& ex, const native_handle_type& handle)+ : basic_overlapped_handle<Executor>(ex, handle)+ {+ }++ /// Construct a stream handle on an existing native handle.+ /**+ * This constructor creates a stream handle object to hold an existing native+ * handle.+ *+ * @param context An execution context which provides the I/O executor that+ * the stream handle will use, by default, to dispatch handlers for any+ * asynchronous operations performed on the stream handle.+ *+ * @param handle The new underlying handle implementation.+ *+ * @throws asio::system_error Thrown on failure.+ */+ template <typename ExecutionContext>+ basic_stream_handle(ExecutionContext& context,+ const native_handle_type& handle,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : basic_overlapped_handle<Executor>(context, handle)+ {+ }++#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)+ /// Move-construct a stream handle from another.+ /**+ * This constructor moves a stream handle from one object to another.+ *+ * @param other The other stream handle 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_handle(const executor_type&)+ * constructor.+ */+ basic_stream_handle(basic_stream_handle&& other)+ : basic_overlapped_handle<Executor>(std::move(other))+ {+ }++ /// Move-assign a stream handle from another.+ /**+ * This assignment operator moves a stream handle from one object to+ * another.+ *+ * @param other The other stream handle 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_handle(const executor_type&)+ * constructor.+ */+ basic_stream_handle& operator=(basic_stream_handle&& other)+ {+ basic_overlapped_handle<Executor>::operator=(std::move(other));+ return *this;+ }+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)++ /// Write some data to the handle.+ /**+ * This function is used to write data to the stream handle. 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 handle.+ *+ * @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+ * handle.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 handle.+ /**+ * This function is used to write data to the stream handle. 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 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 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 handle.+ * The function call always returns immediately.+ *+ * @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 handler is called.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the 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 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().+ *+ * @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+ * handle.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)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+ async_write_some(const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<WriteHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_write_some(this), handler, buffers);+ }++ /// Read some data from the handle.+ /**+ * This function is used to read data from the stream handle. 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+ * handle.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 handle.+ /**+ * This function is used to read data from the stream handle. 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 handle.+ * The function call 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 handler is called.+ *+ * @param handler The handler to be called when the read operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the 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 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().+ *+ * @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+ * handle.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)) ReadHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>+ ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,+ void (asio::error_code, std::size_t))+ async_read_some(const MutableBufferSequence& buffers,+ ASIO_MOVE_ARG(ReadHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))+ {+ return async_initiate<ReadHandler,+ void (asio::error_code, std::size_t)>(+ initiate_async_read_some(this), handler, buffers);+ }++private:+ class initiate_async_write_some+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_write_some(basic_stream_handle* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename WriteHandler, typename ConstBufferSequence>+ void operator()(ASIO_MOVE_ARG(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_handle* self_;+ };++ class initiate_async_read_some+ {+ public:+ typedef Executor executor_type;++ explicit initiate_async_read_some(basic_stream_handle* self)+ : self_(self)+ {+ }++ executor_type get_executor() const ASIO_NOEXCEPT+ {+ return self_->get_executor();+ }++ template <typename ReadHandler, typename MutableBufferSequence>+ void operator()(ASIO_MOVE_ARG(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_handle* self_;+ };+};++} // namespace windows+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP
+ link/modules/asio-standalone/asio/include/asio/windows/object_handle.hpp view
@@ -0,0 +1,38 @@+//+// windows/object_handle.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+// Copyright (c) 2011 Boris Schaeling (boris@highscore.de)+//+// 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_WINDOWS_OBJECT_HANDLE_HPP+#define ASIO_WINDOWS_OBJECT_HANDLE_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_WINDOWS_OBJECT_HANDLE) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/windows/basic_object_handle.hpp"++namespace asio {+namespace windows {++/// Typedef for the typical usage of an object handle.+typedef basic_object_handle<> object_handle;++} // namespace windows+} // namespace asio++#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_WINDOWS_OBJECT_HANDLE_HPP
+ link/modules/asio-standalone/asio/include/asio/windows/overlapped_handle.hpp view
@@ -0,0 +1,39 @@+//+// windows/overlapped_handle.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINDOWS_OVERLAPPED_HANDLE_HPP+#define ASIO_WINDOWS_OVERLAPPED_HANDLE_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_WINDOWS_RANDOM_ACCESS_HANDLE) \+ || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/windows/basic_overlapped_handle.hpp"++namespace asio {+namespace windows {++/// Typedef for the typical usage of an overlapped handle.+typedef basic_overlapped_handle<> overlapped_handle;++} // namespace windows+} // namespace asio++#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)+ // || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_WINDOWS_OVERLAPPED_HANDLE_HPP
+ link/modules/asio-standalone/asio/include/asio/windows/overlapped_ptr.hpp view
@@ -0,0 +1,145 @@+//+// windows/overlapped_ptr.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINDOWS_OVERLAPPED_PTR_HPP+#define ASIO_WINDOWS_OVERLAPPED_PTR_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_WINDOWS_OVERLAPPED_PTR) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/detail/noncopyable.hpp"+#include "asio/detail/win_iocp_overlapped_ptr.hpp"+#include "asio/io_context.hpp"++#include "asio/detail/push_options.hpp"++namespace asio {+namespace windows {++/// Wraps a handler to create an OVERLAPPED object for use with overlapped I/O.+/**+ * A special-purpose smart pointer used to wrap an application handler so that+ * it can be passed as the LPOVERLAPPED argument to overlapped I/O functions.+ *+ * @par Thread Safety+ * @e Distinct @e objects: Safe.@n+ * @e Shared @e objects: Unsafe.+ */+class overlapped_ptr+ : private noncopyable+{+public:+ /// Construct an empty overlapped_ptr.+ overlapped_ptr()+ : impl_()+ {+ }++ /// Construct an overlapped_ptr to contain the specified handler.+ template <typename ExecutionContext, typename Handler>+ explicit overlapped_ptr(ExecutionContext& context,+ ASIO_MOVE_ARG(Handler) handler,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ : impl_(context.get_executor(), ASIO_MOVE_CAST(Handler)(handler))+ {+ }++ /// Construct an overlapped_ptr to contain the specified handler.+ template <typename Executor, typename Handler>+ explicit overlapped_ptr(const Executor& ex,+ ASIO_MOVE_ARG(Handler) handler,+ typename enable_if<+ execution::is_executor<Executor>::value+ || is_executor<Executor>::value+ >::type* = 0)+ : impl_(ex, ASIO_MOVE_CAST(Handler)(handler))+ {+ }++ /// Destructor automatically frees the OVERLAPPED object unless released.+ ~overlapped_ptr()+ {+ }++ /// Reset to empty.+ void reset()+ {+ impl_.reset();+ }++ /// Reset to contain the specified handler, freeing any current OVERLAPPED+ /// object.+ template <typename ExecutionContext, typename Handler>+ void reset(ExecutionContext& context, ASIO_MOVE_ARG(Handler) handler,+ typename enable_if<+ is_convertible<ExecutionContext&, execution_context&>::value+ >::type* = 0)+ {+ impl_.reset(context.get_executor(), ASIO_MOVE_CAST(Handler)(handler));+ }++ /// Reset to contain the specified handler, freeing any current OVERLAPPED+ /// object.+ template <typename Executor, typename Handler>+ void reset(const Executor& ex, ASIO_MOVE_ARG(Handler) handler,+ typename enable_if<+ execution::is_executor<Executor>::value+ || is_executor<Executor>::value+ >::type* = 0)+ {+ impl_.reset(ex, ASIO_MOVE_CAST(Handler)(handler));+ }++ /// Get the contained OVERLAPPED object.+ OVERLAPPED* get()+ {+ return impl_.get();+ }++ /// Get the contained OVERLAPPED object.+ const OVERLAPPED* get() const+ {+ return impl_.get();+ }++ /// Release ownership of the OVERLAPPED object.+ OVERLAPPED* release()+ {+ return impl_.release();+ }++ /// Post completion notification for overlapped operation. Releases ownership.+ void complete(const asio::error_code& ec,+ std::size_t bytes_transferred)+ {+ impl_.complete(ec, bytes_transferred);+ }++private:+ detail::win_iocp_overlapped_ptr impl_;+};++} // namespace windows+} // namespace asio++#include "asio/detail/pop_options.hpp"++#endif // defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_WINDOWS_OVERLAPPED_PTR_HPP
+ link/modules/asio-standalone/asio/include/asio/windows/random_access_handle.hpp view
@@ -0,0 +1,37 @@+//+// windows/random_access_handle.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINDOWS_RANDOM_ACCESS_HANDLE_HPP+#define ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_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_WINDOWS_RANDOM_ACCESS_HANDLE) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/windows/basic_random_access_handle.hpp"++namespace asio {+namespace windows {++/// Typedef for the typical usage of a random-access handle.+typedef basic_random_access_handle<> random_access_handle;++} // namespace windows+} // namespace asio++#endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP
+ link/modules/asio-standalone/asio/include/asio/windows/stream_handle.hpp view
@@ -0,0 +1,37 @@+//+// windows/stream_handle.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WINDOWS_STREAM_HANDLE_HPP+#define ASIO_WINDOWS_STREAM_HANDLE_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_WINDOWS_STREAM_HANDLE) \+ || defined(GENERATING_DOCUMENTATION)++#include "asio/windows/basic_stream_handle.hpp"++namespace asio {+namespace windows {++/// Typedef for the typical usage of a stream-oriented handle.+typedef basic_stream_handle<> stream_handle;++} // namespace windows+} // namespace asio++#endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)+ // || defined(GENERATING_DOCUMENTATION)++#endif // ASIO_WINDOWS_STREAM_HANDLE_HPP
+ link/modules/asio-standalone/asio/include/asio/write.hpp view
@@ -0,0 +1,1246 @@+//+// write.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WRITE_HPP+#define ASIO_WRITE_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/async_result.hpp"+#include "asio/buffer.hpp"+#include "asio/error.hpp"++#if !defined(ASIO_NO_EXTENSIONS)+# include "asio/basic_streambuf_fwd.hpp"+#endif // !defined(ASIO_NO_EXTENSIONS)++#include "asio/detail/push_options.hpp"++namespace asio {++/**+ * @defgroup write asio::write+ *+ * @brief The @c write function is a composed operation that writes a certain+ * amount of data to a stream before returning.+ */+/*@{*/++/// Write all of the supplied data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers One or more buffers containing the data to be written. The sum+ * of the buffer sizes indicates the maximum number of bytes to write to the+ * stream.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To write a single data buffer use the @ref buffer function as follows:+ * @code asio::write(s, 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.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write(+ * s, buffers,+ * asio::transfer_all()); @endcode+ */+template <typename SyncWriteStream, typename ConstBufferSequence>+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type* = 0);++/// Write all of the supplied data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers One or more buffers containing the data to be written. The sum+ * of the buffer sizes indicates the maximum number of bytes to write to the+ * stream.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @par Example+ * To write a single data buffer use the @ref buffer function as follows:+ * @code asio::write(s, asio::buffer(data, size), ec); @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.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write(+ * s, buffers,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncWriteStream, typename ConstBufferSequence>+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,+ asio::error_code& ec,+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type* = 0);++/// Write a certain amount of data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers One or more buffers containing the data to be written. The sum+ * of the buffer sizes indicates the maximum number of bytes to write to the+ * stream.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's write_some function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To write a single data buffer use the @ref buffer function as follows:+ * @code asio::write(s, asio::buffer(data, size),+ * asio::transfer_at_least(32)); @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 SyncWriteStream, typename ConstBufferSequence,+ typename CompletionCondition>+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type* = 0);++/// Write a certain amount of data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers One or more buffers containing the data to be written. The sum+ * of the buffer sizes indicates the maximum number of bytes to write to the+ * stream.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's write_some function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes written. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncWriteStream, typename ConstBufferSequence,+ typename CompletionCondition>+std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type* = 0);++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Write all of the supplied data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * Successfully written data is automatically consumed from the buffers.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write(+ * s, buffers,+ * asio::transfer_all()); @endcode+ */+template <typename SyncWriteStream, typename DynamicBuffer_v1>+std::size_t write(SyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Write all of the supplied data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * Successfully written data is automatically consumed from the buffers.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write(+ * s, buffers,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncWriteStream, typename DynamicBuffer_v1>+std::size_t write(SyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Write a certain amount of data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * Successfully written data is automatically consumed from the buffers.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's write_some function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ */+template <typename SyncWriteStream, typename DynamicBuffer_v1,+ typename CompletionCondition>+std::size_t write(SyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Write a certain amount of data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * Successfully written data is automatically consumed from the buffers.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's write_some function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes written. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncWriteStream, typename DynamicBuffer_v1,+ typename CompletionCondition>+std::size_t write(SyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++/// Write all of the supplied data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param b The basic_streambuf object from which data will be written.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write(+ * s, b,+ * asio::transfer_all()); @endcode+ */+template <typename SyncWriteStream, typename Allocator>+std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b);++/// Write all of the supplied data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param b The basic_streambuf object from which data will be written.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write(+ * s, b,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncWriteStream, typename Allocator>+std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,+ asio::error_code& ec);++/// Write a certain amount of data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param b The basic_streambuf object from which data will be written.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's write_some function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ */+template <typename SyncWriteStream, typename Allocator,+ typename CompletionCondition>+std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition);++/// Write a certain amount of data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param b The basic_streambuf object from which data will be written.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's write_some function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes written. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncWriteStream, typename Allocator,+ typename CompletionCondition>+std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition, asio::error_code& ec);++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Write all of the supplied data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * Successfully written data is automatically consumed from the buffers.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write(+ * s, buffers,+ * asio::transfer_all()); @endcode+ */+template <typename SyncWriteStream, typename DynamicBuffer_v2>+std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Write all of the supplied data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * Successfully written data is automatically consumed from the buffers.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write(+ * s, buffers,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncWriteStream, typename DynamicBuffer_v2>+std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,+ asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Write a certain amount of data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * Successfully written data is automatically consumed from the buffers.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's write_some function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ */+template <typename SyncWriteStream, typename DynamicBuffer_v2,+ typename CompletionCondition>+std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Write a certain amount of data to a stream before returning.+/**+ * This function is used to write a certain number of bytes of data to a stream.+ * The call will block until one of the following conditions is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * write_some function.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the SyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * Successfully written data is automatically consumed from the buffers.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's write_some function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes written. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncWriteStream, typename DynamicBuffer_v2,+ typename CompletionCondition>+std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition, asio::error_code& ec,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/*@}*/+/**+ * @defgroup async_write asio::async_write+ *+ * @brief The @c async_write function is a composed asynchronous operation that+ * writes a certain amount of data to a stream before completion.+ */+/*@{*/++/// Start an asynchronous operation to write all of the supplied data to a+/// stream.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_write_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other write operations (such+ * as async_write, the stream's async_write_some function, or any other composed+ * operations that perform writes) until this operation completes.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the AsyncWriteStream concept.+ *+ * @param buffers One or more buffers containing the data to be written.+ * 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 handler is called.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes written from the+ * // buffers. If an error occurred,+ * // this will be less than the sum+ * // of the buffer sizes.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To write a single data buffer use the @ref buffer function as follows:+ * @code+ * asio::async_write(s, 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 AsyncWriteStream, typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncWriteStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncWriteStream::executor_type),+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type* = 0);++/// Start an asynchronous operation to write a certain amount of data to a+/// stream.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_write_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other write operations (such+ * as async_write, the stream's async_write_some function, or any other composed+ * operations that perform writes) until this operation completes.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the AsyncWriteStream concept.+ *+ * @param buffers One or more buffers containing the data to be written.+ * 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 handler is called.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's async_write_some function.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes written from the+ * // buffers. If an error occurred,+ * // this will be less than the sum+ * // of the buffer sizes.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To write a single data buffer use the @ref buffer function as follows:+ * @code asio::async_write(s,+ * asio::buffer(data, size),+ * asio::transfer_at_least(32),+ * 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 AsyncWriteStream,+ typename ConstBufferSequence, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler,+ typename enable_if<+ is_const_buffer_sequence<ConstBufferSequence>::value+ >::type* = 0);++#if !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Start an asynchronous operation to write all of the supplied data to a+/// stream.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_write_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other write operations (such+ * as async_write, the stream's async_write_some function, or any other composed+ * operations that perform writes) until this operation completes.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the AsyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * 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 handler is called. Successfully written+ * data is automatically consumed from the buffers.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes written from the+ * // buffers. If an error occurred,+ * // this will be less than the sum+ * // of the buffer sizes.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncWriteStream, typename DynamicBuffer_v1,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncWriteStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncWriteStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++/// Start an asynchronous operation to write a certain amount of data to a+/// stream.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_write_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other write operations (such+ * as async_write, the stream's async_write_some function, or any other composed+ * operations that perform writes) until this operation completes.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the AsyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * 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 handler is called. Successfully written+ * data is automatically consumed from the buffers.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's async_write_some function.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes written from the+ * // buffers. If an error occurred,+ * // this will be less than the sum+ * // of the buffer sizes.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncWriteStream,+ typename DynamicBuffer_v1, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s,+ ASIO_MOVE_ARG(DynamicBuffer_v1) buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value+ && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value+ >::type* = 0);++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++/// Start an asynchronous operation to write all of the supplied data to a+/// stream.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_write_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other write operations (such+ * as async_write, the stream's async_write_some function, or any other composed+ * operations that perform writes) until this operation completes.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the AsyncWriteStream concept.+ *+ * @param b A basic_streambuf object from which data will be written. Ownership+ * of the streambuf is retained by the caller, which must guarantee that it+ * remains valid until the handler is called.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes written from the+ * // buffers. If an error occurred,+ * // this will be less than the sum+ * // of the buffer sizes.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncWriteStream, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncWriteStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncWriteStream::executor_type));++/// Start an asynchronous operation to write a certain amount of data to a+/// stream.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_write_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other write operations (such+ * as async_write, the stream's async_write_some function, or any other composed+ * operations that perform writes) until this operation completes.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the AsyncWriteStream concept.+ *+ * @param b A basic_streambuf object from which data will be written. Ownership+ * of the streambuf is retained by the caller, which must guarantee that it+ * remains valid until the handler is called.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's async_write_some function.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes written from the+ * // buffers. If an error occurred,+ * // this will be less than the sum+ * // of the buffer sizes.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncWriteStream,+ typename Allocator, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler);++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)+#endif // !defined(ASIO_NO_DYNAMIC_BUFFER_V1)++/// Start an asynchronous operation to write all of the supplied data to a+/// stream.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_write_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other write operations (such+ * as async_write, the stream's async_write_some function, or any other composed+ * operations that perform writes) until this operation completes.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the AsyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * 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 handler is called. Successfully written+ * data is automatically consumed from the buffers.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes written from the+ * // buffers. If an error occurred,+ * // this will be less than the sum+ * // of the buffer sizes.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncWriteStream, typename DynamicBuffer_v2,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncWriteStream::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncWriteStream::executor_type),+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/// Start an asynchronous operation to write a certain amount of data to a+/// stream.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a stream. The function call always returns immediately. The+ * asynchronous operation will continue until one of the following conditions+ * is true:+ *+ * @li All of the data in the supplied dynamic buffer sequence has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the stream's+ * async_write_some function, and is known as a <em>composed operation</em>. The+ * program must ensure that the stream performs no other write operations (such+ * as async_write, the stream's async_write_some function, or any other composed+ * operations that perform writes) until this operation completes.+ *+ * @param s The stream to which the data is to be written. The type must support+ * the AsyncWriteStream concept.+ *+ * @param buffers The dynamic buffer sequence from which data will be written.+ * 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 handler is called. Successfully written+ * data is automatically consumed from the buffers.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_write_some operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the stream's async_write_some function.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * const asio::error_code& error, // Result of operation.+ *+ * std::size_t bytes_transferred // Number of bytes written from the+ * // buffers. If an error occurred,+ * // this will be less than the sum+ * // of the buffer sizes.+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncWriteStream,+ typename DynamicBuffer_v2, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler,+ typename enable_if<+ is_dynamic_buffer_v2<DynamicBuffer_v2>::value+ >::type* = 0);++/*@}*/++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/write.hpp"++#endif // ASIO_WRITE_HPP
+ link/modules/asio-standalone/asio/include/asio/write_at.hpp view
@@ -0,0 +1,702 @@+//+// write_at.hpp+// ~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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_WRITE_AT_HPP+#define ASIO_WRITE_AT_HPP++#if defined(_MSC_VER) && (_MSC_VER >= 1200)+# pragma once+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)++#include "asio/detail/config.hpp"+#include <cstddef>+#include "asio/async_result.hpp"+#include "asio/detail/cstdint.hpp"+#include "asio/error.hpp"++#if !defined(ASIO_NO_EXTENSIONS)+# include "asio/basic_streambuf_fwd.hpp"+#endif // !defined(ASIO_NO_EXTENSIONS)++#include "asio/detail/push_options.hpp"++namespace asio {++/**+ * @defgroup write_at asio::write_at+ *+ * @brief The @c write_at function is a composed operation that writes a+ * certain amount of data at a specified offset before returning.+ */+/*@{*/++/// Write all of the supplied data at the specified offset before returning.+/**+ * This function is used to write a certain number of bytes of data to a random+ * access device at a specified offset. The call will block until one of the+ * following conditions is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * write_some_at function.+ *+ * @param d The device to which the data is to be written. The type must support+ * the SyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param buffers One or more buffers containing the data to be written. The sum+ * of the buffer sizes indicates the maximum number of bytes to write to the+ * device.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To write a single data buffer use the @ref buffer function as follows:+ * @code asio::write_at(d, 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.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write_at(+ * d, offset, buffers,+ * asio::transfer_all()); @endcode+ */+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>+std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers);++/// Write all of the supplied data at the specified offset before returning.+/**+ * This function is used to write a certain number of bytes of data to a random+ * access device at a specified offset. The call will block until one of the+ * following conditions is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * write_some_at function.+ *+ * @param d The device to which the data is to be written. The type must support+ * the SyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param buffers One or more buffers containing the data to be written. The sum+ * of the buffer sizes indicates the maximum number of bytes to write to the+ * device.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @par Example+ * To write a single data buffer use the @ref buffer function as follows:+ * @code asio::write_at(d, 42,+ * asio::buffer(data, size), ec); @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.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write_at(+ * d, offset, buffers,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>+std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers,+ asio::error_code& ec);++/// Write a certain amount of data at a specified offset before returning.+/**+ * This function is used to write a certain number of bytes of data to a random+ * access device at a specified offset. The call will block until one of the+ * following conditions is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * write_some_at function.+ *+ * @param d The device to which the data is to be written. The type must support+ * the SyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param buffers One or more buffers containing the data to be written. The sum+ * of the buffer sizes indicates the maximum number of bytes to write to the+ * device.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the device's write_some_at function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @par Example+ * To write a single data buffer use the @ref buffer function as follows:+ * @code asio::write_at(d, 42, asio::buffer(data, size),+ * asio::transfer_at_least(32)); @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 SyncRandomAccessWriteDevice, typename ConstBufferSequence,+ typename CompletionCondition>+std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition);++/// Write a certain amount of data at a specified offset before returning.+/**+ * This function is used to write a certain number of bytes of data to a random+ * access device at a specified offset. The call will block until one of the+ * following conditions is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * write_some_at function.+ *+ * @param d The device to which the data is to be written. The type must support+ * the SyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param buffers One or more buffers containing the data to be written. The sum+ * of the buffer sizes indicates the maximum number of bytes to write to the+ * device.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the device's write_some_at function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes written. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,+ typename CompletionCondition>+std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition, asio::error_code& ec);++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++/// Write all of the supplied data at the specified offset before returning.+/**+ * This function is used to write a certain number of bytes of data to a random+ * access device at a specified offset. The call will block until one of the+ * following conditions is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * write_some_at function.+ *+ * @param d The device to which the data is to be written. The type must support+ * the SyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param b The basic_streambuf object from which data will be written.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write_at(+ * d, 42, b,+ * asio::transfer_all()); @endcode+ */+template <typename SyncRandomAccessWriteDevice, typename Allocator>+std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, basic_streambuf<Allocator>& b);++/// Write all of the supplied data at the specified offset before returning.+/**+ * This function is used to write a certain number of bytes of data to a random+ * access device at a specified offset. The call will block until one of the+ * following conditions is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * write_some_at function.+ *+ * @param d The device to which the data is to be written. The type must support+ * the SyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param b The basic_streambuf object from which data will be written.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes transferred.+ *+ * @note This overload is equivalent to calling:+ * @code asio::write_at(+ * d, 42, b,+ * asio::transfer_all(), ec); @endcode+ */+template <typename SyncRandomAccessWriteDevice, typename Allocator>+std::size_t write_at(SyncRandomAccessWriteDevice& d,+ uint64_t offset, basic_streambuf<Allocator>& b,+ asio::error_code& ec);++/// Write a certain amount of data at a specified offset before returning.+/**+ * This function is used to write a certain number of bytes of data to a random+ * access device at a specified offset. The call will block until one of the+ * following conditions is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * write_some_at function.+ *+ * @param d The device to which the data is to be written. The type must support+ * the SyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param b The basic_streambuf object from which data will be written.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the device's write_some_at function.+ *+ * @returns The number of bytes transferred.+ *+ * @throws asio::system_error Thrown on failure.+ */+template <typename SyncRandomAccessWriteDevice, typename Allocator,+ typename CompletionCondition>+std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset,+ basic_streambuf<Allocator>& b, CompletionCondition completion_condition);++/// Write a certain amount of data at a specified offset before returning.+/**+ * This function is used to write a certain number of bytes of data to a random+ * access device at a specified offset. The call will block until one of the+ * following conditions is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * write_some_at function.+ *+ * @param d The device to which the data is to be written. The type must support+ * the SyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param b The basic_streambuf object from which data will be written.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest write_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the device's write_some_at function.+ *+ * @param ec Set to indicate what error occurred, if any.+ *+ * @returns The number of bytes written. If an error occurs, returns the total+ * number of bytes successfully transferred prior to the error.+ */+template <typename SyncRandomAccessWriteDevice, typename Allocator,+ typename CompletionCondition>+std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset,+ basic_streambuf<Allocator>& b, CompletionCondition completion_condition,+ asio::error_code& ec);++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)++/*@}*/+/**+ * @defgroup async_write_at asio::async_write_at+ *+ * @brief The @c async_write_at function is a composed asynchronous operation+ * that writes a certain amount of data at the specified offset before+ * completion.+ */+/*@{*/++/// Start an asynchronous operation to write all of the supplied data at the+/// specified offset.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a random access device at a specified offset. The function call+ * always returns immediately. The asynchronous operation will continue until+ * one of the following conditions is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * async_write_some_at function, and is known as a <em>composed operation</em>.+ * The program must ensure that the device performs no <em>overlapping</em>+ * write operations (such as async_write_at, the device's async_write_some_at+ * function, or any other composed operations that perform writes) until this+ * operation completes. Operations are overlapping if the regions defined by+ * their offsets, and the numbers of bytes to write, intersect.+ *+ * @param d The device to which the data is to be written. The type must support+ * the AsyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param buffers One or more buffers containing the data to be written.+ * 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 handler is called.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of+ * the handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // Number of bytes written from the buffers. If an error+ * // occurred, this will be less than the sum of the buffer sizes.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To write a single data buffer use the @ref buffer function as follows:+ * @code+ * asio::async_write_at(d, 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.+ */+template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncRandomAccessWriteDevice::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset,+ const ConstBufferSequence& buffers,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncRandomAccessWriteDevice::executor_type));++/// Start an asynchronous operation to write a certain amount of data at the+/// specified offset.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a random access device at a specified offset. The function call+ * always returns immediately. The asynchronous operation will continue until+ * one of the following conditions is true:+ *+ * @li All of the data in the supplied buffers has been written. That is, the+ * bytes transferred is equal to the sum of the buffer sizes.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * async_write_some_at function, and is known as a <em>composed operation</em>.+ * The program must ensure that the device performs no <em>overlapping</em>+ * write operations (such as async_write_at, the device's async_write_some_at+ * function, or any other composed operations that perform writes) until this+ * operation completes. Operations are overlapping if the regions defined by+ * their offsets, and the numbers of bytes to write, intersect.+ *+ * @param d The device to which the data is to be written. The type must support+ * the AsyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param buffers One or more buffers containing the data to be written.+ * 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 handler is called.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_write_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the device's async_write_some_at function.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // Number of bytes written from the buffers. If an error+ * // occurred, this will be less than the sum of the buffer sizes.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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 Example+ * To write a single data buffer use the @ref buffer function as follows:+ * @code asio::async_write_at(d, 42,+ * asio::buffer(data, size),+ * asio::transfer_at_least(32),+ * 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 AsyncRandomAccessWriteDevice,+ typename ConstBufferSequence, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncRandomAccessWriteDevice::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write_at(AsyncRandomAccessWriteDevice& d,+ uint64_t offset, const ConstBufferSequence& buffers,+ CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncRandomAccessWriteDevice::executor_type));++#if !defined(ASIO_NO_EXTENSIONS)+#if !defined(ASIO_NO_IOSTREAM)++/// Start an asynchronous operation to write all of the supplied data at the+/// specified offset.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a random access device at a specified offset. The function call+ * always returns immediately. The asynchronous operation will continue until+ * one of the following conditions is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li An error occurred.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * async_write_some_at function, and is known as a <em>composed operation</em>.+ * The program must ensure that the device performs no <em>overlapping</em>+ * write operations (such as async_write_at, the device's async_write_some_at+ * function, or any other composed operations that perform writes) until this+ * operation completes. Operations are overlapping if the regions defined by+ * their offsets, and the numbers of bytes to write, intersect.+ *+ * @param d The device to which the data is to be written. The type must support+ * the AsyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param b A basic_streambuf object from which data will be written. Ownership+ * of the streambuf is retained by the caller, which must guarantee that it+ * remains valid until the handler is called.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // Number of bytes written from the buffers. If an error+ * // occurred, this will be less than the sum of the buffer sizes.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncRandomAccessWriteDevice, typename Allocator,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncRandomAccessWriteDevice::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write_at(AsyncRandomAccessWriteDevice& d,+ uint64_t offset, basic_streambuf<Allocator>& b,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncRandomAccessWriteDevice::executor_type));++/// Start an asynchronous operation to write a certain amount of data at the+/// specified offset.+/**+ * This function is used to asynchronously write a certain number of bytes of+ * data to a random access device at a specified offset. The function call+ * always returns immediately. The asynchronous operation will continue until+ * one of the following conditions is true:+ *+ * @li All of the data in the supplied basic_streambuf has been written.+ *+ * @li The completion_condition function object returns 0.+ *+ * This operation is implemented in terms of zero or more calls to the device's+ * async_write_some_at function, and is known as a <em>composed operation</em>.+ * The program must ensure that the device performs no <em>overlapping</em>+ * write operations (such as async_write_at, the device's async_write_some_at+ * function, or any other composed operations that perform writes) until this+ * operation completes. Operations are overlapping if the regions defined by+ * their offsets, and the numbers of bytes to write, intersect.+ *+ * @param d The device to which the data is to be written. The type must support+ * the AsyncRandomAccessWriteDevice concept.+ *+ * @param offset The offset at which the data will be written.+ *+ * @param b A basic_streambuf object from which data will be written. Ownership+ * of the streambuf is retained by the caller, which must guarantee that it+ * remains valid until the handler is called.+ *+ * @param completion_condition The function object to be called to determine+ * whether the write operation is complete. The signature of the function object+ * must be:+ * @code std::size_t completion_condition(+ * // Result of latest async_write_some_at operation.+ * const asio::error_code& error,+ *+ * // Number of bytes transferred so far.+ * std::size_t bytes_transferred+ * ); @endcode+ * A return value of 0 indicates that the write operation is complete. A+ * non-zero return value indicates the maximum number of bytes to be written on+ * the next call to the device's async_write_some_at function.+ *+ * @param handler The handler to be called when the write operation completes.+ * Copies will be made of the handler as required. The function signature of the+ * handler must be:+ * @code void handler(+ * // Result of operation.+ * const asio::error_code& error,+ *+ * // Number of bytes written from the buffers. If an error+ * // occurred, this will be less than the sum of the buffer sizes.+ * std::size_t bytes_transferred+ * ); @endcode+ * Regardless of whether the asynchronous operation completes immediately or+ * not, the 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().+ */+template <typename AsyncRandomAccessWriteDevice,+ typename Allocator, typename CompletionCondition,+ ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,+ std::size_t)) WriteHandler+ ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(+ typename AsyncRandomAccessWriteDevice::executor_type)>+ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,+ void (asio::error_code, std::size_t))+async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset,+ basic_streambuf<Allocator>& b, CompletionCondition completion_condition,+ ASIO_MOVE_ARG(WriteHandler) handler+ ASIO_DEFAULT_COMPLETION_TOKEN(+ typename AsyncRandomAccessWriteDevice::executor_type));++#endif // !defined(ASIO_NO_IOSTREAM)+#endif // !defined(ASIO_NO_EXTENSIONS)++/*@}*/++} // namespace asio++#include "asio/detail/pop_options.hpp"++#include "asio/impl/write_at.hpp"++#endif // ASIO_WRITE_AT_HPP
+ link/modules/asio-standalone/asio/include/asio/yield.hpp view
@@ -0,0 +1,23 @@+//+// yield.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)+//+// Distributed under the Boost Software License, Version 1.0. (See accompanying+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)+//++#include "coroutine.hpp"++#ifndef reenter+# define reenter(c) ASIO_CORO_REENTER(c)+#endif++#ifndef yield+# define yield ASIO_CORO_YIELD+#endif++#ifndef fork+# define fork ASIO_CORO_FORK+#endif
+ link/modules/asio-standalone/asio/src/examples/cpp03/chat/chat_message.hpp view
@@ -0,0 +1,93 @@+//+// chat_message.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 CHAT_MESSAGE_HPP+#define CHAT_MESSAGE_HPP++#include <cstdio>+#include <cstdlib>+#include <cstring>++class chat_message+{+public:+ enum { header_length = 4 };+ enum { max_body_length = 512 };++ chat_message()+ : body_length_(0)+ {+ }++ const char* data() const+ {+ return data_;+ }++ char* data()+ {+ return data_;+ }++ size_t length() const+ {+ return header_length + body_length_;+ }++ const char* body() const+ {+ return data_ + header_length;+ }++ char* body()+ {+ return data_ + header_length;+ }++ size_t body_length() const+ {+ return body_length_;+ }++ void body_length(size_t new_length)+ {+ body_length_ = new_length;+ if (body_length_ > max_body_length)+ body_length_ = max_body_length;+ }++ bool decode_header()+ {+ using namespace std; // For strncat and atoi.+ char header[header_length + 1] = "";+ strncat(header, data_, header_length);+ body_length_ = atoi(header);+ if (body_length_ > max_body_length)+ {+ body_length_ = 0;+ return false;+ }+ return true;+ }++ void encode_header()+ {+ using namespace std; // For sprintf and memcpy.+ char header[header_length + 1] = "";+ sprintf(header, "%4d", static_cast<int>(body_length_));+ memcpy(data_, header, header_length);+ }++private:+ char data_[header_length + max_body_length];+ size_t body_length_;+};++#endif // CHAT_MESSAGE_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server/connection.hpp view
@@ -0,0 +1,83 @@+//+// connection.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_CONNECTION_HPP+#define HTTP_CONNECTION_HPP++#include <asio.hpp>+#include <boost/array.hpp>+#include <boost/noncopyable.hpp>+#include <boost/shared_ptr.hpp>+#include <boost/enable_shared_from_this.hpp>+#include "reply.hpp"+#include "request.hpp"+#include "request_handler.hpp"+#include "request_parser.hpp"++namespace http {+namespace server {++class connection_manager;++/// Represents a single connection from a client.+class connection+ : public boost::enable_shared_from_this<connection>,+ private boost::noncopyable+{+public:+ /// Construct a connection with the given io_context.+ explicit connection(asio::io_context& io_context,+ connection_manager& manager, request_handler& handler);++ /// Get the socket associated with the connection.+ asio::ip::tcp::socket& socket();++ /// Start the first asynchronous operation for the connection.+ void start();++ /// Stop all asynchronous operations associated with the connection.+ void stop();++private:+ /// Handle completion of a read operation.+ void handle_read(const asio::error_code& e,+ std::size_t bytes_transferred);++ /// Handle completion of a write operation.+ void handle_write(const asio::error_code& e);++ /// Socket for the connection.+ asio::ip::tcp::socket socket_;++ /// The manager for this connection.+ connection_manager& connection_manager_;++ /// The handler used to process the incoming request.+ request_handler& request_handler_;++ /// Buffer for incoming data.+ boost::array<char, 8192> buffer_;++ /// The incoming request.+ request request_;++ /// The parser for the incoming request.+ request_parser request_parser_;++ /// The reply to be sent back to the client.+ reply reply_;+};++typedef boost::shared_ptr<connection> connection_ptr;++} // namespace server+} // namespace http++#endif // HTTP_CONNECTION_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server/connection_manager.hpp view
@@ -0,0 +1,44 @@+//+// connection_manager.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_CONNECTION_MANAGER_HPP+#define HTTP_CONNECTION_MANAGER_HPP++#include <set>+#include <boost/noncopyable.hpp>+#include "connection.hpp"++namespace http {+namespace server {++/// Manages open connections so that they may be cleanly stopped when the server+/// needs to shut down.+class connection_manager+ : private boost::noncopyable+{+public:+ /// Add the specified connection to the manager and start it.+ void start(connection_ptr c);++ /// Stop the specified connection.+ void stop(connection_ptr c);++ /// Stop all connections.+ void stop_all();++private:+ /// The managed connections.+ std::set<connection_ptr> connections_;+};++} // namespace server+} // namespace http++#endif // HTTP_CONNECTION_MANAGER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server/header.hpp view
@@ -0,0 +1,28 @@+//+// header.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_HEADER_HPP+#define HTTP_HEADER_HPP++#include <string>++namespace http {+namespace server {++struct header+{+ std::string name;+ std::string value;+};++} // namespace server+} // namespace http++#endif // HTTP_HEADER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server/mime_types.hpp view
@@ -0,0 +1,27 @@+//+// mime_types.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_MIME_TYPES_HPP+#define HTTP_MIME_TYPES_HPP++#include <string>++namespace http {+namespace server {+namespace mime_types {++/// Convert a file extension into a MIME type.+std::string extension_to_type(const std::string& extension);++} // namespace mime_types+} // namespace server+} // namespace http++#endif // HTTP_MIME_TYPES_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server/reply.hpp view
@@ -0,0 +1,64 @@+//+// reply.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_REPLY_HPP+#define HTTP_REPLY_HPP++#include <string>+#include <vector>+#include <asio.hpp>+#include "header.hpp"++namespace http {+namespace server {++/// A reply to be sent to a client.+struct reply+{+ /// The status of the reply.+ enum status_type+ {+ ok = 200,+ created = 201,+ accepted = 202,+ no_content = 204,+ multiple_choices = 300,+ moved_permanently = 301,+ moved_temporarily = 302,+ not_modified = 304,+ bad_request = 400,+ unauthorized = 401,+ forbidden = 403,+ not_found = 404,+ internal_server_error = 500,+ not_implemented = 501,+ bad_gateway = 502,+ service_unavailable = 503+ } status;++ /// The headers to be included in the reply.+ std::vector<header> headers;++ /// The content to be sent in the reply.+ std::string content;++ /// Convert the reply into a vector of buffers. The buffers do not own the+ /// underlying memory blocks, therefore the reply object must remain valid and+ /// not be changed until the write operation has completed.+ std::vector<asio::const_buffer> to_buffers();++ /// Get a stock reply.+ static reply stock_reply(status_type status);+};++} // namespace server+} // namespace http++#endif // HTTP_REPLY_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request.hpp view
@@ -0,0 +1,34 @@+//+// request.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_REQUEST_HPP+#define HTTP_REQUEST_HPP++#include <string>+#include <vector>+#include "header.hpp"++namespace http {+namespace server {++/// A request received from a client.+struct request+{+ std::string method;+ std::string uri;+ int http_version_major;+ int http_version_minor;+ std::vector<header> headers;+};++} // namespace server+} // namespace http++#endif // HTTP_REQUEST_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request_handler.hpp view
@@ -0,0 +1,46 @@+//+// request_handler.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_REQUEST_HANDLER_HPP+#define HTTP_REQUEST_HANDLER_HPP++#include <string>+#include <boost/noncopyable.hpp>++namespace http {+namespace server {++struct reply;+struct request;++/// The common handler for all incoming requests.+class request_handler+ : private boost::noncopyable+{+public:+ /// Construct with a directory containing files to be served.+ explicit request_handler(const std::string& doc_root);++ /// Handle a request and produce a reply.+ void handle_request(const request& req, reply& rep);++private:+ /// The directory containing the files to be served.+ std::string doc_root_;++ /// Perform URL-decoding on a string. Returns false if the encoding was+ /// invalid.+ static bool url_decode(const std::string& in, std::string& out);+};++} // namespace server+} // namespace http++#endif // HTTP_REQUEST_HANDLER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server/request_parser.hpp view
@@ -0,0 +1,95 @@+//+// request_parser.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_REQUEST_PARSER_HPP+#define HTTP_REQUEST_PARSER_HPP++#include <boost/logic/tribool.hpp>+#include <boost/tuple/tuple.hpp>++namespace http {+namespace server {++struct request;++/// Parser for incoming requests.+class request_parser+{+public:+ /// Construct ready to parse the request method.+ request_parser();++ /// Reset to initial parser state.+ void reset();++ /// Parse some data. The tribool return value is true when a complete request+ /// has been parsed, false if the data is invalid, indeterminate when more+ /// data is required. The InputIterator return value indicates how much of the+ /// input has been consumed.+ template <typename InputIterator>+ boost::tuple<boost::tribool, InputIterator> parse(request& req,+ InputIterator begin, InputIterator end)+ {+ while (begin != end)+ {+ boost::tribool result = consume(req, *begin++);+ if (result || !result)+ return boost::make_tuple(result, begin);+ }+ boost::tribool result = boost::indeterminate;+ return boost::make_tuple(result, begin);+ }++private:+ /// Handle the next character of input.+ boost::tribool consume(request& req, char input);++ /// Check if a byte is an HTTP character.+ static bool is_char(int c);++ /// Check if a byte is an HTTP control character.+ static bool is_ctl(int c);++ /// Check if a byte is defined as an HTTP tspecial character.+ static bool is_tspecial(int c);++ /// Check if a byte is a digit.+ static bool is_digit(int c);++ /// The current state of the parser.+ enum state+ {+ method_start,+ method,+ uri,+ http_version_h,+ http_version_t_1,+ http_version_t_2,+ http_version_p,+ http_version_slash,+ http_version_major_start,+ http_version_major,+ http_version_minor_start,+ http_version_minor,+ expecting_newline_1,+ header_line_start,+ header_lws,+ header_name,+ space_before_header_value,+ header_value,+ expecting_newline_2,+ expecting_newline_3+ } state_;+};++} // namespace server+} // namespace http++#endif // HTTP_REQUEST_PARSER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server/server.hpp view
@@ -0,0 +1,69 @@+//+// server.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER_HPP+#define HTTP_SERVER_HPP++#include <asio.hpp>+#include <string>+#include <boost/noncopyable.hpp>+#include "connection.hpp"+#include "connection_manager.hpp"+#include "request_handler.hpp"++namespace http {+namespace server {++/// The top-level class of the HTTP server.+class server+ : private boost::noncopyable+{+public:+ /// Construct the server to listen on the specified TCP address and port, and+ /// serve up files from the given directory.+ explicit server(const std::string& address, const std::string& port,+ const std::string& doc_root);++ /// Run the server's io_context loop.+ void run();++private:+ /// Initiate an asynchronous accept operation.+ void start_accept();++ /// Handle completion of an asynchronous accept operation.+ void handle_accept(const asio::error_code& e);++ /// Handle a request to stop the server.+ void handle_stop();++ /// The io_context used to perform asynchronous operations.+ asio::io_context io_context_;++ /// The signal_set is used to register for process termination notifications.+ asio::signal_set signals_;++ /// Acceptor used to listen for incoming connections.+ asio::ip::tcp::acceptor acceptor_;++ /// The connection manager which owns all live connections.+ connection_manager connection_manager_;++ /// The next connection to be accepted.+ connection_ptr new_connection_;++ /// The handler for all incoming requests.+ request_handler request_handler_;+};++} // namespace server+} // namespace http++#endif // HTTP_SERVER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/connection.hpp view
@@ -0,0 +1,75 @@+//+// connection.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER2_CONNECTION_HPP+#define HTTP_SERVER2_CONNECTION_HPP++#include <asio.hpp>+#include <boost/array.hpp>+#include <boost/noncopyable.hpp>+#include <boost/shared_ptr.hpp>+#include <boost/enable_shared_from_this.hpp>+#include "reply.hpp"+#include "request.hpp"+#include "request_handler.hpp"+#include "request_parser.hpp"++namespace http {+namespace server2 {++/// Represents a single connection from a client.+class connection+ : public boost::enable_shared_from_this<connection>,+ private boost::noncopyable+{+public:+ /// Construct a connection with the given io_context.+ explicit connection(asio::io_context& io_context,+ request_handler& handler);++ /// Get the socket associated with the connection.+ asio::ip::tcp::socket& socket();++ /// Start the first asynchronous operation for the connection.+ void start();++private:+ /// Handle completion of a read operation.+ void handle_read(const asio::error_code& e,+ std::size_t bytes_transferred);++ /// Handle completion of a write operation.+ void handle_write(const asio::error_code& e);++ /// Socket for the connection.+ asio::ip::tcp::socket socket_;++ /// The handler used to process the incoming request.+ request_handler& request_handler_;++ /// Buffer for incoming data.+ boost::array<char, 8192> buffer_;++ /// The incoming request.+ request request_;++ /// The parser for the incoming request.+ request_parser request_parser_;++ /// The reply to be sent back to the client.+ reply reply_;+};++typedef boost::shared_ptr<connection> connection_ptr;++} // namespace server2+} // namespace http++#endif // HTTP_SERVER2_CONNECTION_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/header.hpp view
@@ -0,0 +1,28 @@+//+// header.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER2_HEADER_HPP+#define HTTP_SERVER2_HEADER_HPP++#include <string>++namespace http {+namespace server2 {++struct header+{+ std::string name;+ std::string value;+};++} // namespace server2+} // namespace http++#endif // HTTP_SERVER2_HEADER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/io_context_pool.hpp view
@@ -0,0 +1,56 @@+//+// io_context_pool.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER2_IO_SERVICE_POOL_HPP+#define HTTP_SERVER2_IO_SERVICE_POOL_HPP++#include <asio.hpp>+#include <list>+#include <vector>+#include <boost/noncopyable.hpp>+#include <boost/shared_ptr.hpp>++namespace http {+namespace server2 {++/// A pool of io_context objects.+class io_context_pool+ : private boost::noncopyable+{+public:+ /// Construct the io_context pool.+ explicit io_context_pool(std::size_t pool_size);++ /// Run all io_context objects in the pool.+ void run();++ /// Stop all io_context objects in the pool.+ void stop();++ /// Get an io_context to use.+ asio::io_context& get_io_context();++private:+ typedef boost::shared_ptr<asio::io_context> io_context_ptr;++ /// The pool of io_contexts.+ std::vector<io_context_ptr> io_contexts_;++ /// The work-tracking executors that keep the io_contexts running.+ std::list<asio::any_io_executor> work_;++ /// The next io_context to use for a connection.+ std::size_t next_io_context_;+};++} // namespace server2+} // namespace http++#endif // HTTP_SERVER2_IO_SERVICE_POOL_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/mime_types.hpp view
@@ -0,0 +1,27 @@+//+// mime_types.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER2_MIME_TYPES_HPP+#define HTTP_SERVER2_MIME_TYPES_HPP++#include <string>++namespace http {+namespace server2 {+namespace mime_types {++/// Convert a file extension into a MIME type.+std::string extension_to_type(const std::string& extension);++} // namespace mime_types+} // namespace server2+} // namespace http++#endif // HTTP_SERVER2_MIME_TYPES_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/reply.hpp view
@@ -0,0 +1,64 @@+//+// reply.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER2_REPLY_HPP+#define HTTP_SERVER2_REPLY_HPP++#include <string>+#include <vector>+#include <asio.hpp>+#include "header.hpp"++namespace http {+namespace server2 {++/// A reply to be sent to a client.+struct reply+{+ /// The status of the reply.+ enum status_type+ {+ ok = 200,+ created = 201,+ accepted = 202,+ no_content = 204,+ multiple_choices = 300,+ moved_permanently = 301,+ moved_temporarily = 302,+ not_modified = 304,+ bad_request = 400,+ unauthorized = 401,+ forbidden = 403,+ not_found = 404,+ internal_server_error = 500,+ not_implemented = 501,+ bad_gateway = 502,+ service_unavailable = 503+ } status;++ /// The headers to be included in the reply.+ std::vector<header> headers;++ /// The content to be sent in the reply.+ std::string content;++ /// Convert the reply into a vector of buffers. The buffers do not own the+ /// underlying memory blocks, therefore the reply object must remain valid and+ /// not be changed until the write operation has completed.+ std::vector<asio::const_buffer> to_buffers();++ /// Get a stock reply.+ static reply stock_reply(status_type status);+};++} // namespace server2+} // namespace http++#endif // HTTP_SERVER2_REPLY_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request.hpp view
@@ -0,0 +1,34 @@+//+// request.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER2_REQUEST_HPP+#define HTTP_SERVER2_REQUEST_HPP++#include <string>+#include <vector>+#include "header.hpp"++namespace http {+namespace server2 {++/// A request received from a client.+struct request+{+ std::string method;+ std::string uri;+ int http_version_major;+ int http_version_minor;+ std::vector<header> headers;+};++} // namespace server2+} // namespace http++#endif // HTTP_SERVER2_REQUEST_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request_handler.hpp view
@@ -0,0 +1,46 @@+//+// request_handler.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER2_REQUEST_HANDLER_HPP+#define HTTP_SERVER2_REQUEST_HANDLER_HPP++#include <string>+#include <boost/noncopyable.hpp>++namespace http {+namespace server2 {++struct reply;+struct request;++/// The common handler for all incoming requests.+class request_handler+ : private boost::noncopyable+{+public:+ /// Construct with a directory containing files to be served.+ explicit request_handler(const std::string& doc_root);++ /// Handle a request and produce a reply.+ void handle_request(const request& req, reply& rep);++private:+ /// The directory containing the files to be served.+ std::string doc_root_;++ /// Perform URL-decoding on a string. Returns false if the encoding was+ /// invalid.+ static bool url_decode(const std::string& in, std::string& out);+};++} // namespace server2+} // namespace http++#endif // HTTP_SERVER2_REQUEST_HANDLER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/request_parser.hpp view
@@ -0,0 +1,95 @@+//+// request_parser.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER2_REQUEST_PARSER_HPP+#define HTTP_SERVER2_REQUEST_PARSER_HPP++#include <boost/logic/tribool.hpp>+#include <boost/tuple/tuple.hpp>++namespace http {+namespace server2 {++struct request;++/// Parser for incoming requests.+class request_parser+{+public:+ /// Construct ready to parse the request method.+ request_parser();++ /// Reset to initial parser state.+ void reset();++ /// Parse some data. The tribool return value is true when a complete request+ /// has been parsed, false if the data is invalid, indeterminate when more+ /// data is required. The InputIterator return value indicates how much of the+ /// input has been consumed.+ template <typename InputIterator>+ boost::tuple<boost::tribool, InputIterator> parse(request& req,+ InputIterator begin, InputIterator end)+ {+ while (begin != end)+ {+ boost::tribool result = consume(req, *begin++);+ if (result || !result)+ return boost::make_tuple(result, begin);+ }+ boost::tribool result = boost::indeterminate;+ return boost::make_tuple(result, begin);+ }++private:+ /// Handle the next character of input.+ boost::tribool consume(request& req, char input);++ /// Check if a byte is an HTTP character.+ static bool is_char(int c);++ /// Check if a byte is an HTTP control character.+ static bool is_ctl(int c);++ /// Check if a byte is defined as an HTTP tspecial character.+ static bool is_tspecial(int c);++ /// Check if a byte is a digit.+ static bool is_digit(int c);++ /// The current state of the parser.+ enum state+ {+ method_start,+ method,+ uri,+ http_version_h,+ http_version_t_1,+ http_version_t_2,+ http_version_p,+ http_version_slash,+ http_version_major_start,+ http_version_major,+ http_version_minor_start,+ http_version_minor,+ expecting_newline_1,+ header_line_start,+ header_lws,+ header_name,+ space_before_header_value,+ header_value,+ expecting_newline_2,+ expecting_newline_3+ } state_;+};++} // namespace server2+} // namespace http++#endif // HTTP_SERVER2_REQUEST_PARSER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server2/server.hpp view
@@ -0,0 +1,68 @@+//+// server.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER2_SERVER_HPP+#define HTTP_SERVER2_SERVER_HPP++#include <asio.hpp>+#include <string>+#include <vector>+#include <boost/noncopyable.hpp>+#include <boost/shared_ptr.hpp>+#include "connection.hpp"+#include "io_context_pool.hpp"+#include "request_handler.hpp"++namespace http {+namespace server2 {++/// The top-level class of the HTTP server.+class server+ : private boost::noncopyable+{+public:+ /// Construct the server to listen on the specified TCP address and port, and+ /// serve up files from the given directory.+ explicit server(const std::string& address, const std::string& port,+ const std::string& doc_root, std::size_t io_context_pool_size);++ /// Run the server's io_context loop.+ void run();++private:+ /// Initiate an asynchronous accept operation.+ void start_accept();++ /// Handle completion of an asynchronous accept operation.+ void handle_accept(const asio::error_code& e);++ /// Handle a request to stop the server.+ void handle_stop();++ /// The pool of io_context objects used to perform asynchronous operations.+ io_context_pool io_context_pool_;++ /// The signal_set is used to register for process termination notifications.+ asio::signal_set signals_;++ /// Acceptor used to listen for incoming connections.+ asio::ip::tcp::acceptor acceptor_;++ /// The next connection to be accepted.+ connection_ptr new_connection_;++ /// The handler for all incoming requests.+ request_handler request_handler_;+};++} // namespace server2+} // namespace http++#endif // HTTP_SERVER2_SERVER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/connection.hpp view
@@ -0,0 +1,78 @@+//+// connection.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER3_CONNECTION_HPP+#define HTTP_SERVER3_CONNECTION_HPP++#include <asio.hpp>+#include <boost/array.hpp>+#include <boost/noncopyable.hpp>+#include <boost/shared_ptr.hpp>+#include <boost/enable_shared_from_this.hpp>+#include "reply.hpp"+#include "request.hpp"+#include "request_handler.hpp"+#include "request_parser.hpp"++namespace http {+namespace server3 {++/// Represents a single connection from a client.+class connection+ : public boost::enable_shared_from_this<connection>,+ private boost::noncopyable+{+public:+ /// Construct a connection with the given io_context.+ explicit connection(asio::io_context& io_context,+ request_handler& handler);++ /// Get the socket associated with the connection.+ asio::ip::tcp::socket& socket();++ /// Start the first asynchronous operation for the connection.+ void start();++private:+ /// Handle completion of a read operation.+ void handle_read(const asio::error_code& e,+ std::size_t bytes_transferred);++ /// Handle completion of a write operation.+ void handle_write(const asio::error_code& e);++ /// Strand to ensure the connection's handlers are not called concurrently.+ asio::strand<asio::io_context::executor_type> strand_;++ /// Socket for the connection.+ asio::ip::tcp::socket socket_;++ /// The handler used to process the incoming request.+ request_handler& request_handler_;++ /// Buffer for incoming data.+ boost::array<char, 8192> buffer_;++ /// The incoming request.+ request request_;++ /// The parser for the incoming request.+ request_parser request_parser_;++ /// The reply to be sent back to the client.+ reply reply_;+};++typedef boost::shared_ptr<connection> connection_ptr;++} // namespace server3+} // namespace http++#endif // HTTP_SERVER3_CONNECTION_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/header.hpp view
@@ -0,0 +1,28 @@+//+// header.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER3_HEADER_HPP+#define HTTP_SERVER3_HEADER_HPP++#include <string>++namespace http {+namespace server3 {++struct header+{+ std::string name;+ std::string value;+};++} // namespace server3+} // namespace http++#endif // HTTP_SERVER3_HEADER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/mime_types.hpp view
@@ -0,0 +1,27 @@+//+// mime_types.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER3_MIME_TYPES_HPP+#define HTTP_SERVER3_MIME_TYPES_HPP++#include <string>++namespace http {+namespace server3 {+namespace mime_types {++/// Convert a file extension into a MIME type.+std::string extension_to_type(const std::string& extension);++} // namespace mime_types+} // namespace server3+} // namespace http++#endif // HTTP_SERVER3_MIME_TYPES_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/reply.hpp view
@@ -0,0 +1,64 @@+//+// reply.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER3_REPLY_HPP+#define HTTP_SERVER3_REPLY_HPP++#include <string>+#include <vector>+#include <asio.hpp>+#include "header.hpp"++namespace http {+namespace server3 {++/// A reply to be sent to a client.+struct reply+{+ /// The status of the reply.+ enum status_type+ {+ ok = 200,+ created = 201,+ accepted = 202,+ no_content = 204,+ multiple_choices = 300,+ moved_permanently = 301,+ moved_temporarily = 302,+ not_modified = 304,+ bad_request = 400,+ unauthorized = 401,+ forbidden = 403,+ not_found = 404,+ internal_server_error = 500,+ not_implemented = 501,+ bad_gateway = 502,+ service_unavailable = 503+ } status;++ /// The headers to be included in the reply.+ std::vector<header> headers;++ /// The content to be sent in the reply.+ std::string content;++ /// Convert the reply into a vector of buffers. The buffers do not own the+ /// underlying memory blocks, therefore the reply object must remain valid and+ /// not be changed until the write operation has completed.+ std::vector<asio::const_buffer> to_buffers();++ /// Get a stock reply.+ static reply stock_reply(status_type status);+};++} // namespace server3+} // namespace http++#endif // HTTP_SERVER3_REPLY_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request.hpp view
@@ -0,0 +1,34 @@+//+// request.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER3_REQUEST_HPP+#define HTTP_SERVER3_REQUEST_HPP++#include <string>+#include <vector>+#include "header.hpp"++namespace http {+namespace server3 {++/// A request received from a client.+struct request+{+ std::string method;+ std::string uri;+ int http_version_major;+ int http_version_minor;+ std::vector<header> headers;+};++} // namespace server3+} // namespace http++#endif // HTTP_SERVER3_REQUEST_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request_handler.hpp view
@@ -0,0 +1,46 @@+//+// request_handler.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER3_REQUEST_HANDLER_HPP+#define HTTP_SERVER3_REQUEST_HANDLER_HPP++#include <string>+#include <boost/noncopyable.hpp>++namespace http {+namespace server3 {++struct reply;+struct request;++/// The common handler for all incoming requests.+class request_handler+ : private boost::noncopyable+{+public:+ /// Construct with a directory containing files to be served.+ explicit request_handler(const std::string& doc_root);++ /// Handle a request and produce a reply.+ void handle_request(const request& req, reply& rep);++private:+ /// The directory containing the files to be served.+ std::string doc_root_;++ /// Perform URL-decoding on a string. Returns false if the encoding was+ /// invalid.+ static bool url_decode(const std::string& in, std::string& out);+};++} // namespace server3+} // namespace http++#endif // HTTP_SERVER3_REQUEST_HANDLER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/request_parser.hpp view
@@ -0,0 +1,95 @@+//+// request_parser.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER3_REQUEST_PARSER_HPP+#define HTTP_SERVER3_REQUEST_PARSER_HPP++#include <boost/logic/tribool.hpp>+#include <boost/tuple/tuple.hpp>++namespace http {+namespace server3 {++struct request;++/// Parser for incoming requests.+class request_parser+{+public:+ /// Construct ready to parse the request method.+ request_parser();++ /// Reset to initial parser state.+ void reset();++ /// Parse some data. The tribool return value is true when a complete request+ /// has been parsed, false if the data is invalid, indeterminate when more+ /// data is required. The InputIterator return value indicates how much of the+ /// input has been consumed.+ template <typename InputIterator>+ boost::tuple<boost::tribool, InputIterator> parse(request& req,+ InputIterator begin, InputIterator end)+ {+ while (begin != end)+ {+ boost::tribool result = consume(req, *begin++);+ if (result || !result)+ return boost::make_tuple(result, begin);+ }+ boost::tribool result = boost::indeterminate;+ return boost::make_tuple(result, begin);+ }++private:+ /// Handle the next character of input.+ boost::tribool consume(request& req, char input);++ /// Check if a byte is an HTTP character.+ static bool is_char(int c);++ /// Check if a byte is an HTTP control character.+ static bool is_ctl(int c);++ /// Check if a byte is defined as an HTTP tspecial character.+ static bool is_tspecial(int c);++ /// Check if a byte is a digit.+ static bool is_digit(int c);++ /// The current state of the parser.+ enum state+ {+ method_start,+ method,+ uri,+ http_version_h,+ http_version_t_1,+ http_version_t_2,+ http_version_p,+ http_version_slash,+ http_version_major_start,+ http_version_major,+ http_version_minor_start,+ http_version_minor,+ expecting_newline_1,+ header_line_start,+ header_lws,+ header_name,+ space_before_header_value,+ header_value,+ expecting_newline_2,+ expecting_newline_3+ } state_;+};++} // namespace server3+} // namespace http++#endif // HTTP_SERVER3_REQUEST_PARSER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server3/server.hpp view
@@ -0,0 +1,70 @@+//+// server.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER3_SERVER_HPP+#define HTTP_SERVER3_SERVER_HPP++#include <asio.hpp>+#include <string>+#include <vector>+#include <boost/noncopyable.hpp>+#include <boost/shared_ptr.hpp>+#include "connection.hpp"+#include "request_handler.hpp"++namespace http {+namespace server3 {++/// The top-level class of the HTTP server.+class server+ : private boost::noncopyable+{+public:+ /// Construct the server to listen on the specified TCP address and port, and+ /// serve up files from the given directory.+ explicit server(const std::string& address, const std::string& port,+ const std::string& doc_root, std::size_t thread_pool_size);++ /// Run the server's io_context loop.+ void run();++private:+ /// Initiate an asynchronous accept operation.+ void start_accept();++ /// Handle completion of an asynchronous accept operation.+ void handle_accept(const asio::error_code& e);++ /// Handle a request to stop the server.+ void handle_stop();++ /// The number of threads that will call io_context::run().+ std::size_t thread_pool_size_;++ /// The io_context used to perform asynchronous operations.+ asio::io_context io_context_;++ /// The signal_set is used to register for process termination notifications.+ asio::signal_set signals_;++ /// Acceptor used to listen for incoming connections.+ asio::ip::tcp::acceptor acceptor_;++ /// The next connection to be accepted.+ connection_ptr new_connection_;++ /// The handler for all incoming requests.+ request_handler request_handler_;+};++} // namespace server3+} // namespace http++#endif // HTTP_SERVER3_SERVER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/file_handler.hpp view
@@ -0,0 +1,44 @@+//+// file_handler.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER4_FILE_HANDLER_HPP+#define HTTP_SERVER4_FILE_HANDLER_HPP++#include <string>++namespace http {+namespace server4 {++struct reply;+struct request;++/// The common handler for all incoming requests.+class file_handler+{+public:+ /// Construct with a directory containing files to be served.+ explicit file_handler(const std::string& doc_root);++ /// Handle a request and produce a reply.+ void operator()(const request& req, reply& rep);++private:+ /// The directory containing the files to be served.+ std::string doc_root_;++ /// Perform URL-decoding on a string. Returns false if the encoding was+ /// invalid.+ static bool url_decode(const std::string& in, std::string& out);+};++} // namespace server4+} // namespace http++#endif // HTTP_SERVER4_FILE_HANDLER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/header.hpp view
@@ -0,0 +1,28 @@+//+// header.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER4_HEADER_HPP+#define HTTP_SERVER4_HEADER_HPP++#include <string>++namespace http {+namespace server4 {++struct header+{+ std::string name;+ std::string value;+};++} // namespace server4+} // namespace http++#endif // HTTP_SERVER4_HEADER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/mime_types.hpp view
@@ -0,0 +1,27 @@+//+// mime_types.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER4_MIME_TYPES_HPP+#define HTTP_SERVER4_MIME_TYPES_HPP++#include <string>++namespace http {+namespace server4 {+namespace mime_types {++/// Convert a file extension into a MIME type.+std::string extension_to_type(const std::string& extension);++} // namespace mime_types+} // namespace server4+} // namespace http++#endif // HTTP_SERVER4_MIME_TYPES_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/reply.hpp view
@@ -0,0 +1,64 @@+//+// reply.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER4_REPLY_HPP+#define HTTP_SERVER4_REPLY_HPP++#include <string>+#include <vector>+#include <asio.hpp>+#include "header.hpp"++namespace http {+namespace server4 {++/// A reply to be sent to a client.+struct reply+{+ /// The status of the reply.+ enum status_type+ {+ ok = 200,+ created = 201,+ accepted = 202,+ no_content = 204,+ multiple_choices = 300,+ moved_permanently = 301,+ moved_temporarily = 302,+ not_modified = 304,+ bad_request = 400,+ unauthorized = 401,+ forbidden = 403,+ not_found = 404,+ internal_server_error = 500,+ not_implemented = 501,+ bad_gateway = 502,+ service_unavailable = 503+ } status;++ /// The headers to be included in the reply.+ std::vector<header> headers;++ /// The content to be sent in the reply.+ std::string content;++ /// Convert the reply into a vector of buffers. The buffers do not own the+ /// underlying memory blocks, therefore the reply object must remain valid and+ /// not be changed until the write operation has completed.+ std::vector<asio::const_buffer> to_buffers();++ /// Get a stock reply.+ static reply stock_reply(status_type status);+};++} // namespace server4+} // namespace http++#endif // HTTP_SERVER4_REPLY_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/request.hpp view
@@ -0,0 +1,46 @@+//+// request.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER4_REQUEST_HPP+#define HTTP_SERVER4_REQUEST_HPP++#include <string>+#include <vector>+#include "header.hpp"++namespace http {+namespace server4 {++/// A request received from a client.+struct request+{+ /// The request method, e.g. "GET", "POST".+ std::string method;++ /// The requested URI, such as a path to a file.+ std::string uri;++ /// Major version number, usually 1.+ int http_version_major;++ /// Minor version number, usually 0 or 1.+ int http_version_minor;++ /// The headers included with the request.+ std::vector<header> headers;++ /// The optional content sent with the request.+ std::string content;+};++} // namespace server4+} // namespace http++#endif // HTTP_SERVER4_REQUEST_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/request_parser.hpp view
@@ -0,0 +1,78 @@+//+// request_parser.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER4_REQUEST_PARSER_HPP+#define HTTP_SERVER4_REQUEST_PARSER_HPP++#include <string>+#include <boost/logic/tribool.hpp>+#include <boost/tuple/tuple.hpp>+#include <asio/coroutine.hpp>++namespace http {+namespace server4 {++struct request;++/// Parser for incoming requests.+class request_parser : asio::coroutine+{+public:+ /// Parse some data. The tribool return value is true when a complete request+ /// has been parsed, false if the data is invalid, indeterminate when more+ /// data is required. The InputIterator return value indicates how much of the+ /// input has been consumed.+ template <typename InputIterator>+ boost::tuple<boost::tribool, InputIterator> parse(request& req,+ InputIterator begin, InputIterator end)+ {+ while (begin != end)+ {+ boost::tribool result = consume(req, *begin++);+ if (result || !result)+ return boost::make_tuple(result, begin);+ }+ boost::tribool result = boost::indeterminate;+ return boost::make_tuple(result, begin);+ }++private:+ /// The name of the content length header.+ static std::string content_length_name_;++ /// Content length as decoded from headers. Defaults to 0.+ std::size_t content_length_;++ /// Handle the next character of input.+ boost::tribool consume(request& req, char input);++ /// Check if a byte is an HTTP character.+ static bool is_char(int c);++ /// Check if a byte is an HTTP control character.+ static bool is_ctl(int c);++ /// Check if a byte is defined as an HTTP tspecial character.+ static bool is_tspecial(int c);++ /// Check if a byte is a digit.+ static bool is_digit(int c);++ /// Check if two characters are equal, without regard to case.+ static bool tolower_compare(char a, char b);++ /// Check whether the two request header names match.+ bool headers_equal(const std::string& a, const std::string& b);+};++} // namespace server4+} // namespace http++#endif // HTTP_SERVER4_REQUEST_PARSER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/http/server4/server.hpp view
@@ -0,0 +1,73 @@+//+// server.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER4_SERVER_HPP+#define HTTP_SERVER4_SERVER_HPP++#include <asio.hpp>+#include <string>+#include <boost/array.hpp>+#include <boost/function.hpp>+#include <boost/shared_ptr.hpp>+#include "request_parser.hpp"++namespace http {+namespace server4 {++struct request;+struct reply;++/// The top-level coroutine of the HTTP server.+class server : asio::coroutine+{+public:+ /// Construct the server to listen on the specified TCP address and port, and+ /// serve up files from the given directory.+ explicit server(asio::io_context& io_context,+ const std::string& address, const std::string& port,+ boost::function<void(const request&, reply&)> request_handler);++ /// Perform work associated with the server.+ void operator()(+ asio::error_code ec = asio::error_code(),+ std::size_t length = 0);++private:+ typedef asio::ip::tcp tcp;++ /// The user-supplied handler for all incoming requests.+ boost::function<void(const request&, reply&)> request_handler_;++ /// Acceptor used to listen for incoming connections.+ boost::shared_ptr<tcp::acceptor> acceptor_;++ /// The current connection from a client.+ boost::shared_ptr<tcp::socket> socket_;++ /// Buffer for incoming data.+ boost::shared_ptr<boost::array<char, 8192> > buffer_;++ /// The incoming request.+ boost::shared_ptr<request> request_;++ /// Whether the request is valid or not.+ boost::tribool valid_request_;++ /// The parser for the incoming request.+ request_parser request_parser_;++ /// The reply to be sent back to the client.+ boost::shared_ptr<reply> reply_;+};++} // namespace server4+} // namespace http++#endif // HTTP_SERVER4_SERVER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/icmp/icmp_header.hpp view
@@ -0,0 +1,94 @@+//+// icmp_header.hpp+// ~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 ICMP_HEADER_HPP+#define ICMP_HEADER_HPP++#include <istream>+#include <ostream>+#include <algorithm>++// ICMP header for both IPv4 and IPv6.+//+// The wire format of an ICMP header is:+// +// 0 8 16 31+// +---------------+---------------+------------------------------+ ---+// | | | | ^+// | type | code | checksum | |+// | | | | |+// +---------------+---------------+------------------------------+ 8 bytes+// | | | |+// | identifier | sequence number | |+// | | | v+// +-------------------------------+------------------------------+ ---++class icmp_header+{+public:+ enum { echo_reply = 0, destination_unreachable = 3, source_quench = 4,+ redirect = 5, echo_request = 8, time_exceeded = 11, parameter_problem = 12,+ timestamp_request = 13, timestamp_reply = 14, info_request = 15,+ info_reply = 16, address_request = 17, address_reply = 18 };++ icmp_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }++ unsigned char type() const { return rep_[0]; }+ unsigned char code() const { return rep_[1]; }+ unsigned short checksum() const { return decode(2, 3); }+ unsigned short identifier() const { return decode(4, 5); }+ unsigned short sequence_number() const { return decode(6, 7); }++ void type(unsigned char n) { rep_[0] = n; }+ void code(unsigned char n) { rep_[1] = n; }+ void checksum(unsigned short n) { encode(2, 3, n); }+ void identifier(unsigned short n) { encode(4, 5, n); }+ void sequence_number(unsigned short n) { encode(6, 7, n); }++ friend std::istream& operator>>(std::istream& is, icmp_header& header)+ { return is.read(reinterpret_cast<char*>(header.rep_), 8); }++ friend std::ostream& operator<<(std::ostream& os, const icmp_header& header)+ { return os.write(reinterpret_cast<const char*>(header.rep_), 8); }++private:+ unsigned short decode(int a, int b) const+ { return (rep_[a] << 8) + rep_[b]; }++ void encode(int a, int b, unsigned short n)+ {+ rep_[a] = static_cast<unsigned char>(n >> 8);+ rep_[b] = static_cast<unsigned char>(n & 0xFF);+ }++ unsigned char rep_[8];+};++template <typename Iterator>+void compute_checksum(icmp_header& header,+ Iterator body_begin, Iterator body_end)+{+ unsigned int sum = (header.type() << 8) + header.code()+ + header.identifier() + header.sequence_number();++ Iterator body_iter = body_begin;+ while (body_iter != body_end)+ {+ sum += (static_cast<unsigned char>(*body_iter++) << 8);+ if (body_iter != body_end)+ sum += static_cast<unsigned char>(*body_iter++);+ }++ sum = (sum >> 16) + (sum & 0xFFFF);+ sum += (sum >> 16);+ header.checksum(static_cast<unsigned short>(~sum));+}++#endif // ICMP_HEADER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/icmp/ipv4_header.hpp view
@@ -0,0 +1,102 @@+//+// ipv4_header.hpp+// ~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 IPV4_HEADER_HPP+#define IPV4_HEADER_HPP++#include <algorithm>+#include <asio/ip/address_v4.hpp>++// Packet header for IPv4.+//+// The wire format of an IPv4 header is:+// +// 0 8 16 31+// +-------+-------+---------------+------------------------------+ ---+// | | | | | ^+// |version|header | type of | total length in bytes | |+// | (4) | length| service | | |+// +-------+-------+---------------+-+-+-+------------------------+ |+// | | | | | | |+// | identification |0|D|M| fragment offset | |+// | | |F|F| | |+// +---------------+---------------+-+-+-+------------------------+ |+// | | | | |+// | time to live | protocol | header checksum | 20 bytes+// | | | | |+// +---------------+---------------+------------------------------+ |+// | | |+// | source IPv4 address | |+// | | |+// +--------------------------------------------------------------+ |+// | | |+// | destination IPv4 address | |+// | | v+// +--------------------------------------------------------------+ ---+// | | ^+// | | |+// / options (if any) / 0 - 40+// / / bytes+// | | |+// | | v+// +--------------------------------------------------------------+ ---++class ipv4_header+{+public:+ ipv4_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); }++ unsigned char version() const { return (rep_[0] >> 4) & 0xF; }+ unsigned short header_length() const { return (rep_[0] & 0xF) * 4; }+ unsigned char type_of_service() const { return rep_[1]; }+ unsigned short total_length() const { return decode(2, 3); }+ unsigned short identification() const { return decode(4, 5); }+ bool dont_fragment() const { return (rep_[6] & 0x40) != 0; }+ bool more_fragments() const { return (rep_[6] & 0x20) != 0; }+ unsigned short fragment_offset() const { return decode(6, 7) & 0x1FFF; }+ unsigned int time_to_live() const { return rep_[8]; }+ unsigned char protocol() const { return rep_[9]; }+ unsigned short header_checksum() const { return decode(10, 11); }++ asio::ip::address_v4 source_address() const+ {+ asio::ip::address_v4::bytes_type bytes+ = { { rep_[12], rep_[13], rep_[14], rep_[15] } };+ return asio::ip::address_v4(bytes);+ }++ asio::ip::address_v4 destination_address() const+ {+ asio::ip::address_v4::bytes_type bytes+ = { { rep_[16], rep_[17], rep_[18], rep_[19] } };+ return asio::ip::address_v4(bytes);+ }++ friend std::istream& operator>>(std::istream& is, ipv4_header& header)+ {+ is.read(reinterpret_cast<char*>(header.rep_), 20);+ if (header.version() != 4)+ is.setstate(std::ios::failbit);+ std::streamsize options_length = header.header_length() - 20;+ if (options_length < 0 || options_length > 40)+ is.setstate(std::ios::failbit);+ else+ is.read(reinterpret_cast<char*>(header.rep_) + 20, options_length);+ return is;+ }++private:+ unsigned short decode(int a, int b) const+ { return (rep_[a] << 8) + rep_[b]; }++ unsigned char rep_[60];+};++#endif // IPV4_HEADER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/porthopper/protocol.hpp view
@@ -0,0 +1,156 @@+//+// protocol.hpp+// ~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 PORTHOPPER_PROTOCOL_HPP+#define PORTHOPPER_PROTOCOL_HPP++#include <boost/array.hpp>+#include <asio.hpp>+#include <cstring>+#include <iomanip>+#include <string>+#include <strstream>++// This request is sent by the client to the server over a TCP connection.+// The client uses it to perform three functions:+// - To request that data start being sent to a given port.+// - To request that data is no longer sent to a given port.+// - To change the target port to another.+class control_request+{+public:+ // Construct an empty request. Used when receiving.+ control_request()+ {+ }++ // Create a request to start sending data to a given port.+ static const control_request start(unsigned short port)+ {+ return control_request(0, port);+ }++ // Create a request to stop sending data to a given port.+ static const control_request stop(unsigned short port)+ {+ return control_request(port, 0);+ }++ // Create a request to change the port that data is sent to.+ static const control_request change(+ unsigned short old_port, unsigned short new_port)+ {+ return control_request(old_port, new_port);+ }++ // Get the old port. Returns 0 for start requests.+ unsigned short old_port() const+ {+ std::istrstream is(data_, encoded_port_size);+ unsigned short port = 0;+ is >> std::setw(encoded_port_size) >> std::hex >> port;+ return port;+ }++ // Get the new port. Returns 0 for stop requests.+ unsigned short new_port() const+ {+ std::istrstream is(data_ + encoded_port_size, encoded_port_size);+ unsigned short port = 0;+ is >> std::setw(encoded_port_size) >> std::hex >> port;+ return port;+ }++ // Obtain buffers for reading from or writing to a socket.+ boost::array<asio::mutable_buffer, 1> to_buffers()+ {+ boost::array<asio::mutable_buffer, 1> buffers+ = { { asio::buffer(data_) } };+ return buffers;+ }++private:+ // Construct with specified old and new ports.+ control_request(unsigned short old_port_number,+ unsigned short new_port_number)+ {+ std::ostrstream os(data_, control_request_size);+ os << std::setw(encoded_port_size) << std::hex << old_port_number;+ os << std::setw(encoded_port_size) << std::hex << new_port_number;+ }++ // The length in bytes of a control_request and its components.+ enum+ {+ encoded_port_size = 4, // 16-bit port in hex.+ control_request_size = encoded_port_size * 2+ };++ // The encoded request data.+ char data_[control_request_size];+};++// This frame is sent from the server to subscribed clients over UDP.+class frame+{+public:+ // The maximum allowable length of the payload.+ enum { payload_size = 32 };++ // Construct an empty frame. Used when receiving.+ frame()+ {+ }++ // Construct a frame with specified frame number and payload.+ frame(unsigned long frame_number, const std::string& payload_data)+ {+ std::ostrstream os(data_, frame_size);+ os << std::setw(encoded_number_size) << std::hex << frame_number;+ os << std::setw(payload_size)+ << std::setfill(' ') << payload_data.substr(0, payload_size);+ }++ // Get the frame number.+ unsigned long number() const+ {+ std::istrstream is(data_, encoded_number_size);+ unsigned long frame_number = 0;+ is >> std::setw(encoded_number_size) >> std::hex >> frame_number;+ return frame_number;+ }++ // Get the payload data.+ const std::string payload() const+ {+ return std::string(data_ + encoded_number_size, payload_size);+ }++ // Obtain buffers for reading from or writing to a socket.+ boost::array<asio::mutable_buffer, 1> to_buffers()+ {+ boost::array<asio::mutable_buffer, 1> buffers+ = { { asio::buffer(data_) } };+ return buffers;+ }++private:+ // The length in bytes of a frame and its components.+ enum+ {+ encoded_number_size = 8, // Frame number in hex.+ frame_size = encoded_number_size + payload_size+ };++ // The encoded frame data.+ char data_[frame_size];+};++#endif // PORTHOPPER_PROTOCOL_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/serialization/connection.hpp view
@@ -0,0 +1,188 @@+//+// connection.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 SERIALIZATION_CONNECTION_HPP+#define SERIALIZATION_CONNECTION_HPP++#include <asio.hpp>+#include <boost/archive/text_iarchive.hpp>+#include <boost/archive/text_oarchive.hpp>+#include <boost/bind/bind.hpp>+#include <boost/shared_ptr.hpp>+#include <boost/tuple/tuple.hpp>+#include <iomanip>+#include <string>+#include <sstream>+#include <vector>++namespace s11n_example {++/// The connection class provides serialization primitives on top of a socket.+/**+ * Each message sent using this class consists of:+ * @li An 8-byte header containing the length of the serialized data in+ * hexadecimal.+ * @li The serialized data.+ */+class connection+{+public:+ /// Constructor.+ connection(const asio::executor& ex)+ : socket_(ex)+ {+ }++ /// Get the underlying socket. Used for making a connection or for accepting+ /// an incoming connection.+ asio::ip::tcp::socket& socket()+ {+ return socket_;+ }++ /// Asynchronously write a data structure to the socket.+ template <typename T, typename Handler>+ void async_write(const T& t, Handler handler)+ {+ // Serialize the data first so we know how large it is.+ std::ostringstream archive_stream;+ boost::archive::text_oarchive archive(archive_stream);+ archive << t;+ outbound_data_ = archive_stream.str();++ // Format the header.+ std::ostringstream header_stream;+ header_stream << std::setw(header_length)+ << std::hex << outbound_data_.size();+ if (!header_stream || header_stream.str().size() != header_length)+ {+ // Something went wrong, inform the caller.+ asio::error_code error(asio::error::invalid_argument);+ asio::post(socket_.get_executor(), boost::bind(handler, error));+ return;+ }+ outbound_header_ = header_stream.str();++ // Write the serialized data to the socket. We use "gather-write" to send+ // both the header and the data in a single write operation.+ std::vector<asio::const_buffer> buffers;+ buffers.push_back(asio::buffer(outbound_header_));+ buffers.push_back(asio::buffer(outbound_data_));+ asio::async_write(socket_, buffers, handler);+ }++ /// Asynchronously read a data structure from the socket.+ template <typename T, typename Handler>+ void async_read(T& t, Handler handler)+ {+ // Issue a read operation to read exactly the number of bytes in a header.+ void (connection::*f)(+ const asio::error_code&,+ T&, boost::tuple<Handler>)+ = &connection::handle_read_header<T, Handler>;+ asio::async_read(socket_, asio::buffer(inbound_header_),+ boost::bind(f,+ this, asio::placeholders::error, boost::ref(t),+ boost::make_tuple(handler)));+ }++ /// Handle a completed read of a message header. The handler is passed using+ /// a tuple since boost::bind seems to have trouble binding a function object+ /// created using boost::bind as a parameter.+ template <typename T, typename Handler>+ void handle_read_header(const asio::error_code& e,+ T& t, boost::tuple<Handler> handler)+ {+ if (e)+ {+ boost::get<0>(handler)(e);+ }+ else+ {+ // Determine the length of the serialized data.+ std::istringstream is(std::string(inbound_header_, header_length));+ std::size_t inbound_data_size = 0;+ if (!(is >> std::hex >> inbound_data_size))+ {+ // Header doesn't seem to be valid. Inform the caller.+ asio::error_code error(asio::error::invalid_argument);+ boost::get<0>(handler)(error);+ return;+ }++ // Start an asynchronous call to receive the data.+ inbound_data_.resize(inbound_data_size);+ void (connection::*f)(+ const asio::error_code&,+ T&, boost::tuple<Handler>)+ = &connection::handle_read_data<T, Handler>;+ asio::async_read(socket_, asio::buffer(inbound_data_),+ boost::bind(f, this,+ asio::placeholders::error, boost::ref(t), handler));+ }+ }++ /// Handle a completed read of message data.+ template <typename T, typename Handler>+ void handle_read_data(const asio::error_code& e,+ T& t, boost::tuple<Handler> handler)+ {+ if (e)+ {+ boost::get<0>(handler)(e);+ }+ else+ {+ // Extract the data structure from the data just received.+ try+ {+ std::string archive_data(&inbound_data_[0], inbound_data_.size());+ std::istringstream archive_stream(archive_data);+ boost::archive::text_iarchive archive(archive_stream);+ archive >> t;+ }+ catch (std::exception& e)+ {+ // Unable to decode data.+ asio::error_code error(asio::error::invalid_argument);+ boost::get<0>(handler)(error);+ return;+ }++ // Inform caller that data has been received ok.+ boost::get<0>(handler)(e);+ }+ }++private:+ /// The underlying socket.+ asio::ip::tcp::socket socket_;++ /// The size of a fixed length header.+ enum { header_length = 8 };++ /// Holds an outbound header.+ std::string outbound_header_;++ /// Holds the outbound data.+ std::string outbound_data_;++ /// Holds an inbound header.+ char inbound_header_[header_length];++ /// Holds the inbound data.+ std::vector<char> inbound_data_;+};++typedef boost::shared_ptr<connection> connection_ptr;++} // namespace s11n_example++#endif // SERIALIZATION_CONNECTION_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/serialization/stock.hpp view
@@ -0,0 +1,50 @@+//+// stock.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 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 SERIALIZATION_STOCK_HPP+#define SERIALIZATION_STOCK_HPP++#include <string>++namespace s11n_example {++/// Structure to hold information about a single stock.+struct stock+{+ std::string code;+ std::string name;+ double open_price;+ double high_price;+ double low_price;+ double last_price;+ double buy_price;+ int buy_quantity;+ double sell_price;+ int sell_quantity;++ template <typename Archive>+ void serialize(Archive& ar, const unsigned int version)+ {+ ar & code;+ ar & name;+ ar & open_price;+ ar & high_price;+ ar & low_price;+ ar & last_price;+ ar & buy_price;+ ar & buy_quantity;+ ar & sell_price;+ ar & sell_quantity;+ }+};++} // namespace s11n_example++#endif // SERIALIZATION_STOCK_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/services/basic_logger.hpp view
@@ -0,0 +1,77 @@+//+// basic_logger.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 SERVICES_BASIC_LOGGER_HPP+#define SERVICES_BASIC_LOGGER_HPP++#include <asio.hpp>+#include <boost/noncopyable.hpp>+#include <string>++namespace services {++/// Class to provide simple logging functionality. Use the services::logger+/// typedef.+template <typename Service>+class basic_logger+ : private boost::noncopyable+{+public:+ /// The type of the service that will be used to provide timer operations.+ typedef Service service_type;++ /// The native implementation type of the timer.+ typedef typename service_type::impl_type impl_type;++ /// Constructor.+ /**+ * This constructor creates a logger.+ *+ * @param context The execution context used to locate the logger service.+ *+ * @param identifier An identifier for this logger.+ */+ explicit basic_logger(asio::execution_context& context,+ const std::string& identifier)+ : service_(asio::use_service<Service>(context)),+ impl_(service_.null())+ {+ service_.create(impl_, identifier);+ }++ /// Destructor.+ ~basic_logger()+ {+ service_.destroy(impl_);+ }++ /// Set the output file for all logger instances.+ void use_file(const std::string& file)+ {+ service_.use_file(impl_, file);+ }++ /// Log a message.+ void log(const std::string& message)+ {+ service_.log(impl_, message);+ }++private:+ /// The backend service implementation.+ service_type& service_;++ /// The underlying native implementation.+ impl_type impl_;+};++} // namespace services++#endif // SERVICES_BASIC_LOGGER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/services/logger.hpp view
@@ -0,0 +1,24 @@+//+// logger.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 SERVICES_LOGGER_HPP+#define SERVICES_LOGGER_HPP++#include "basic_logger.hpp"+#include "logger_service.hpp"++namespace services {++/// Typedef for typical logger usage.+typedef basic_logger<logger_service> logger;++} // namespace services++#endif // SERVICES_LOGGER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/services/logger_service.hpp view
@@ -0,0 +1,145 @@+//+// logger_service.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 SERVICES_LOGGER_SERVICE_HPP+#define SERVICES_LOGGER_SERVICE_HPP++#include <asio.hpp>+#include <boost/bind/bind.hpp>+#include <boost/date_time/posix_time/posix_time.hpp>+#include <boost/noncopyable.hpp>+#include <boost/scoped_ptr.hpp>+#include <fstream>+#include <sstream>+#include <string>++namespace services {++/// Service implementation for the logger.+class logger_service+ : public asio::execution_context::service+{+public:+ /// The type used to identify this service in the execution context.+ typedef logger_service key_type;++ /// The backend implementation of a logger.+ struct logger_impl+ {+ explicit logger_impl(const std::string& ident) : identifier(ident) {}+ std::string identifier;+ };++ /// The type for an implementation of the logger.+ typedef logger_impl* impl_type;++ /// Constructor creates a thread to run a private io_context.+ logger_service(asio::execution_context& context)+ : asio::execution_context::service(context),+ work_io_context_(),+ work_(asio::require(work_io_context_.get_executor(),+ asio::execution::outstanding_work.tracked)),+ work_thread_(new asio::thread(+ boost::bind(&asio::io_context::run, &work_io_context_)))+ {+ }++ /// Destructor shuts down the private io_context.+ ~logger_service()+ {+ /// Indicate that we have finished with the private io_context. Its+ /// io_context::run() function will exit once all other work has completed.+ work_ = asio::any_io_executor();+ if (work_thread_)+ work_thread_->join();+ }++ /// Destroy all user-defined handler objects owned by the service.+ void shutdown()+ {+ }++ /// Return a null logger implementation.+ impl_type null() const+ {+ return 0;+ }++ /// Create a new logger implementation.+ void create(impl_type& impl, const std::string& identifier)+ {+ impl = new logger_impl(identifier);+ }++ /// Destroy a logger implementation.+ void destroy(impl_type& impl)+ {+ delete impl;+ impl = null();+ }++ /// Set the output file for the logger. The current implementation sets the+ /// output file for all logger instances, and so the impl parameter is not+ /// actually needed. It is retained here to illustrate how service functions+ /// are typically defined.+ void use_file(impl_type& /*impl*/, const std::string& file)+ {+ // Pass the work of opening the file to the background thread.+ asio::post(work_io_context_, boost::bind(+ &logger_service::use_file_impl, this, file));+ }++ /// Log a message.+ void log(impl_type& impl, const std::string& message)+ {+ // Format the text to be logged.+ std::ostringstream os;+ os << impl->identifier << ": " << message;++ // Pass the work of writing to the file to the background thread.+ asio::post(work_io_context_, boost::bind(+ &logger_service::log_impl, this, os.str()));+ }++private:+ /// Helper function used to open the output file from within the private+ /// io_context's thread.+ void use_file_impl(const std::string& file)+ {+ ofstream_.close();+ ofstream_.clear();+ ofstream_.open(file.c_str());+ }++ /// Helper function used to log a message from within the private io_context's+ /// thread.+ void log_impl(const std::string& text)+ {+ ofstream_ << text << std::endl;+ }++ /// Private io_context used for performing logging operations.+ asio::io_context work_io_context_;++ /// A work-tracking executor giving work for the private io_context to+ /// perform. If we do not give the io_context some work to do then the+ /// io_context::run() function will exit immediately.+ asio::any_io_executor work_;++ /// Thread used for running the work io_context's run loop.+ boost::scoped_ptr<asio::thread> work_thread_;++ /// The file to which log messages will be written.+ std::ofstream ofstream_;+};++} // namespace services++#endif // SERVICES_LOGGER_SERVICE_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp03/socks4/socks4.hpp view
@@ -0,0 +1,144 @@+//+// socks4.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 SOCKS4_HPP+#define SOCKS4_HPP++#include <string>+#include <asio.hpp>+#include <boost/array.hpp>++namespace socks4 {++const unsigned char version = 0x04;++class request+{+public:+ enum command_type+ {+ connect = 0x01,+ bind = 0x02+ };++ request(command_type cmd, const asio::ip::tcp::endpoint& endpoint,+ const std::string& user_id)+ : version_(version),+ command_(cmd),+ user_id_(user_id),+ null_byte_(0)+ {+ // Only IPv4 is supported by the SOCKS 4 protocol.+ if (endpoint.protocol() != asio::ip::tcp::v4())+ {+ throw asio::system_error(+ asio::error::address_family_not_supported);+ }++ // Convert port number to network byte order.+ unsigned short port = endpoint.port();+ port_high_byte_ = (port >> 8) & 0xff;+ port_low_byte_ = port & 0xff;++ // Save IP address in network byte order.+ address_ = endpoint.address().to_v4().to_bytes();+ }++ boost::array<asio::const_buffer, 7> buffers() const+ {+ boost::array<asio::const_buffer, 7> bufs =+ {+ {+ asio::buffer(&version_, 1),+ asio::buffer(&command_, 1),+ asio::buffer(&port_high_byte_, 1),+ asio::buffer(&port_low_byte_, 1),+ asio::buffer(address_),+ asio::buffer(user_id_),+ asio::buffer(&null_byte_, 1)+ }+ };+ return bufs;+ }++private:+ unsigned char version_;+ unsigned char command_;+ unsigned char port_high_byte_;+ unsigned char port_low_byte_;+ asio::ip::address_v4::bytes_type address_;+ std::string user_id_;+ unsigned char null_byte_;+};++class reply+{+public:+ enum status_type+ {+ request_granted = 0x5a,+ request_failed = 0x5b,+ request_failed_no_identd = 0x5c,+ request_failed_bad_user_id = 0x5d+ };++ reply()+ : null_byte_(0),+ status_()+ {+ }++ boost::array<asio::mutable_buffer, 5> buffers()+ {+ boost::array<asio::mutable_buffer, 5> bufs =+ {+ {+ asio::buffer(&null_byte_, 1),+ asio::buffer(&status_, 1),+ asio::buffer(&port_high_byte_, 1),+ asio::buffer(&port_low_byte_, 1),+ asio::buffer(address_)+ }+ };+ return bufs;+ }++ bool success() const+ {+ return null_byte_ == 0 && status_ == request_granted;+ }++ unsigned char status() const+ {+ return status_;+ }++ asio::ip::tcp::endpoint endpoint() const+ {+ unsigned short port = port_high_byte_;+ port = (port << 8) & 0xff00;+ port = port | port_low_byte_;++ asio::ip::address_v4 address(address_);++ return asio::ip::tcp::endpoint(address, port);+ }++private:+ unsigned char null_byte_;+ unsigned char status_;+ unsigned char port_high_byte_;+ unsigned char port_low_byte_;+ asio::ip::address_v4::bytes_type address_;+};++} // namespace socks4++#endif // SOCKS4_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/chat/chat_message.hpp view
@@ -0,0 +1,91 @@+//+// chat_message.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 CHAT_MESSAGE_HPP+#define CHAT_MESSAGE_HPP++#include <cstdio>+#include <cstdlib>+#include <cstring>++class chat_message+{+public:+ enum { header_length = 4 };+ enum { max_body_length = 512 };++ chat_message()+ : body_length_(0)+ {+ }++ const char* data() const+ {+ return data_;+ }++ char* data()+ {+ return data_;+ }++ std::size_t length() const+ {+ return header_length + body_length_;+ }++ const char* body() const+ {+ return data_ + header_length;+ }++ char* body()+ {+ return data_ + header_length;+ }++ std::size_t body_length() const+ {+ return body_length_;+ }++ void body_length(std::size_t new_length)+ {+ body_length_ = new_length;+ if (body_length_ > max_body_length)+ body_length_ = max_body_length;+ }++ bool decode_header()+ {+ char header[header_length + 1] = "";+ std::strncat(header, data_, header_length);+ body_length_ = std::atoi(header);+ if (body_length_ > max_body_length)+ {+ body_length_ = 0;+ return false;+ }+ return true;+ }++ void encode_header()+ {+ char header[header_length + 1] = "";+ std::sprintf(header, "%4d", static_cast<int>(body_length_));+ std::memcpy(data_, header, header_length);+ }++private:+ char data_[header_length + max_body_length];+ std::size_t body_length_;+};++#endif // CHAT_MESSAGE_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/handler_tracking/custom_tracking.hpp view
@@ -0,0 +1,211 @@+//+// custom_tracking.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 CUSTOM_TRACKING_HPP+#define CUSTOM_TRACKING_HPP++#include <cinttypes>+#include <cstdint>+#include <cstdio>++# define ASIO_INHERIT_TRACKED_HANDLER \+ : public ::custom_tracking::tracked_handler++# define ASIO_ALSO_INHERIT_TRACKED_HANDLER \+ , public ::custom_tracking::tracked_handler++# define ASIO_HANDLER_TRACKING_INIT \+ ::custom_tracking::init()++# define ASIO_HANDLER_LOCATION(args) \+ ::custom_tracking::location args++# define ASIO_HANDLER_CREATION(args) \+ ::custom_tracking::creation args++# define ASIO_HANDLER_COMPLETION(args) \+ ::custom_tracking::completion tracked_completion args++# define ASIO_HANDLER_INVOCATION_BEGIN(args) \+ tracked_completion.invocation_begin args++# define ASIO_HANDLER_INVOCATION_END \+ tracked_completion.invocation_end()++# define ASIO_HANDLER_OPERATION(args) \+ ::custom_tracking::operation args++# define ASIO_HANDLER_REACTOR_REGISTRATION(args) \+ ::custom_tracking::reactor_registration args++# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \+ ::custom_tracking::reactor_deregistration args++# define ASIO_HANDLER_REACTOR_READ_EVENT 1+# define ASIO_HANDLER_REACTOR_WRITE_EVENT 2+# define ASIO_HANDLER_REACTOR_ERROR_EVENT 4++# define ASIO_HANDLER_REACTOR_EVENTS(args) \+ ::custom_tracking::reactor_events args++# define ASIO_HANDLER_REACTOR_OPERATION(args) \+ ::custom_tracking::reactor_operation args++struct custom_tracking+{+ // Base class for objects containing tracked handlers.+ struct tracked_handler+ {+ std::uintmax_t handler_id_ = 0; // To uniquely identify a handler.+ std::uintmax_t tree_id_ = 0; // To identify related handlers.+ const char* object_type_; // The object type associated with the handler.+ std::uintmax_t native_handle_; // Native handle, if any.+ };++ // Initialise the tracking system.+ static void init()+ {+ }++ // Record a source location.+ static void location(const char* file_name,+ int line, const char* function_name)+ {+ std::printf("At location %s:%d in %s\n", file_name, line, function_name);+ }++ // Record the creation of a tracked handler.+ static void creation(asio::execution_context& /*ctx*/,+ tracked_handler& h, const char* object_type, void* /*object*/,+ std::uintmax_t native_handle, const char* op_name)+ {+ // Generate a unique id for the new handler.+ static std::atomic<std::uintmax_t> next_handler_id{1};+ h.handler_id_ = next_handler_id++;++ // Copy the tree identifier forward from the current handler.+ if (*current_completion())+ h.tree_id_ = (*current_completion())->handler_.tree_id_;++ // Store various attributes of the operation to use in later output.+ h.object_type_ = object_type;+ h.native_handle_ = native_handle;++ std::printf(+ "Starting operation %s.%s for native_handle = %" PRIuMAX+ ", handler = %" PRIuMAX ", tree = %" PRIuMAX "\n",+ object_type, op_name, h.native_handle_, h.handler_id_, h.tree_id_);+ }++ struct completion+ {+ explicit completion(const tracked_handler& h)+ : handler_(h),+ next_(*current_completion())+ {+ *current_completion() = this;+ }++ completion(const completion&) = delete;+ completion& operator=(const completion&) = delete;++ // Destructor records only when an exception is thrown from the handler, or+ // if the memory is being freed without the handler having been invoked.+ ~completion()+ {+ *current_completion() = next_;+ }++ // Records that handler is to be invoked with the specified arguments.+ template <class... Args>+ void invocation_begin(Args&&... /*args*/)+ {+ std::printf("Entering handler %" PRIuMAX " in tree %" PRIuMAX "\n",+ handler_.handler_id_, handler_.tree_id_);+ }++ // Record that handler invocation has ended.+ void invocation_end()+ {+ std::printf("Leaving handler %" PRIuMAX " in tree %" PRIuMAX "\n",+ handler_.handler_id_, handler_.tree_id_);+ }++ tracked_handler handler_;++ // Completions may nest. Here we stash a pointer to the outer completion.+ completion* next_;+ };++ static completion** current_completion()+ {+ static ASIO_THREAD_KEYWORD completion* current = nullptr;+ return ¤t;+ }++ // Record an operation that is not directly associated with a handler.+ static void operation(asio::execution_context& /*ctx*/,+ const char* /*object_type*/, void* /*object*/,+ std::uintmax_t /*native_handle*/, const char* /*op_name*/)+ {+ }++ // Record that a descriptor has been registered with the reactor.+ static void reactor_registration(asio::execution_context& context,+ uintmax_t native_handle, uintmax_t registration)+ {+ std::printf("Adding to reactor native_handle = %" PRIuMAX+ ", registration = %" PRIuMAX "\n", native_handle, registration);+ }++ // Record that a descriptor has been deregistered from the reactor.+ static void reactor_deregistration(asio::execution_context& context,+ uintmax_t native_handle, uintmax_t registration)+ {+ std::printf("Removing from reactor native_handle = %" PRIuMAX+ ", registration = %" PRIuMAX "\n", native_handle, registration);+ }++ // Record reactor-based readiness events associated with a descriptor.+ static void reactor_events(asio::execution_context& context,+ uintmax_t registration, unsigned events)+ {+ std::printf(+ "Reactor readiness for registration = %" PRIuMAX ", events =%s%s%s\n",+ registration,+ (events & ASIO_HANDLER_REACTOR_READ_EVENT) ? " read" : "",+ (events & ASIO_HANDLER_REACTOR_WRITE_EVENT) ? " write" : "",+ (events & ASIO_HANDLER_REACTOR_ERROR_EVENT) ? " error" : "");+ }++ // Record a reactor-based operation that is associated with a handler.+ static void reactor_operation(const tracked_handler& h,+ const char* op_name, const asio::error_code& ec)+ {+ std::printf(+ "Performed operation %s.%s for native_handle = %" PRIuMAX+ ", ec = %s:%d\n", h.object_type_, op_name, h.native_handle_,+ ec.category().name(), ec.value());+ }++ // Record a reactor-based operation that is associated with a handler.+ static void reactor_operation(const tracked_handler& h,+ const char* op_name, const asio::error_code& ec,+ std::size_t bytes_transferred)+ {+ std::printf(+ "Performed operation %s.%s for native_handle = %" PRIuMAX+ ", ec = %s:%d, n = %" PRIuMAX "\n", h.object_type_, op_name,+ h.native_handle_, ec.category().name(), ec.value(),+ static_cast<uintmax_t>(bytes_transferred));+ }+};++#endif // CUSTOM_TRACKING_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/http/server/connection.hpp view
@@ -0,0 +1,79 @@+//+// connection.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_CONNECTION_HPP+#define HTTP_CONNECTION_HPP++#include <array>+#include <memory>+#include <asio.hpp>+#include "reply.hpp"+#include "request.hpp"+#include "request_handler.hpp"+#include "request_parser.hpp"++namespace http {+namespace server {++class connection_manager;++/// Represents a single connection from a client.+class connection+ : public std::enable_shared_from_this<connection>+{+public:+ connection(const connection&) = delete;+ connection& operator=(const connection&) = delete;++ /// Construct a connection with the given socket.+ explicit connection(asio::ip::tcp::socket socket,+ connection_manager& manager, request_handler& handler);++ /// Start the first asynchronous operation for the connection.+ void start();++ /// Stop all asynchronous operations associated with the connection.+ void stop();++private:+ /// Perform an asynchronous read operation.+ void do_read();++ /// Perform an asynchronous write operation.+ void do_write();++ /// Socket for the connection.+ asio::ip::tcp::socket socket_;++ /// The manager for this connection.+ connection_manager& connection_manager_;++ /// The handler used to process the incoming request.+ request_handler& request_handler_;++ /// Buffer for incoming data.+ std::array<char, 8192> buffer_;++ /// The incoming request.+ request request_;++ /// The parser for the incoming request.+ request_parser request_parser_;++ /// The reply to be sent back to the client.+ reply reply_;+};++typedef std::shared_ptr<connection> connection_ptr;++} // namespace server+} // namespace http++#endif // HTTP_CONNECTION_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/http/server/connection_manager.hpp view
@@ -0,0 +1,48 @@+//+// connection_manager.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_CONNECTION_MANAGER_HPP+#define HTTP_CONNECTION_MANAGER_HPP++#include <set>+#include "connection.hpp"++namespace http {+namespace server {++/// Manages open connections so that they may be cleanly stopped when the server+/// needs to shut down.+class connection_manager+{+public:+ connection_manager(const connection_manager&) = delete;+ connection_manager& operator=(const connection_manager&) = delete;++ /// Construct a connection manager.+ connection_manager();++ /// Add the specified connection to the manager and start it.+ void start(connection_ptr c);++ /// Stop the specified connection.+ void stop(connection_ptr c);++ /// Stop all connections.+ void stop_all();++private:+ /// The managed connections.+ std::set<connection_ptr> connections_;+};++} // namespace server+} // namespace http++#endif // HTTP_CONNECTION_MANAGER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/http/server/header.hpp view
@@ -0,0 +1,28 @@+//+// header.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_HEADER_HPP+#define HTTP_HEADER_HPP++#include <string>++namespace http {+namespace server {++struct header+{+ std::string name;+ std::string value;+};++} // namespace server+} // namespace http++#endif // HTTP_HEADER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/http/server/mime_types.hpp view
@@ -0,0 +1,27 @@+//+// mime_types.hpp+// ~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_MIME_TYPES_HPP+#define HTTP_MIME_TYPES_HPP++#include <string>++namespace http {+namespace server {+namespace mime_types {++/// Convert a file extension into a MIME type.+std::string extension_to_type(const std::string& extension);++} // namespace mime_types+} // namespace server+} // namespace http++#endif // HTTP_MIME_TYPES_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/http/server/reply.hpp view
@@ -0,0 +1,64 @@+//+// reply.hpp+// ~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_REPLY_HPP+#define HTTP_REPLY_HPP++#include <string>+#include <vector>+#include <asio.hpp>+#include "header.hpp"++namespace http {+namespace server {++/// A reply to be sent to a client.+struct reply+{+ /// The status of the reply.+ enum status_type+ {+ ok = 200,+ created = 201,+ accepted = 202,+ no_content = 204,+ multiple_choices = 300,+ moved_permanently = 301,+ moved_temporarily = 302,+ not_modified = 304,+ bad_request = 400,+ unauthorized = 401,+ forbidden = 403,+ not_found = 404,+ internal_server_error = 500,+ not_implemented = 501,+ bad_gateway = 502,+ service_unavailable = 503+ } status;++ /// The headers to be included in the reply.+ std::vector<header> headers;++ /// The content to be sent in the reply.+ std::string content;++ /// Convert the reply into a vector of buffers. The buffers do not own the+ /// underlying memory blocks, therefore the reply object must remain valid and+ /// not be changed until the write operation has completed.+ std::vector<asio::const_buffer> to_buffers();++ /// Get a stock reply.+ static reply stock_reply(status_type status);+};++} // namespace server+} // namespace http++#endif // HTTP_REPLY_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request.hpp view
@@ -0,0 +1,34 @@+//+// request.hpp+// ~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_REQUEST_HPP+#define HTTP_REQUEST_HPP++#include <string>+#include <vector>+#include "header.hpp"++namespace http {+namespace server {++/// A request received from a client.+struct request+{+ std::string method;+ std::string uri;+ int http_version_major;+ int http_version_minor;+ std::vector<header> headers;+};++} // namespace server+} // namespace http++#endif // HTTP_REQUEST_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request_handler.hpp view
@@ -0,0 +1,47 @@+//+// request_handler.hpp+// ~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_REQUEST_HANDLER_HPP+#define HTTP_REQUEST_HANDLER_HPP++#include <string>++namespace http {+namespace server {++struct reply;+struct request;++/// The common handler for all incoming requests.+class request_handler+{+public:+ request_handler(const request_handler&) = delete;+ request_handler& operator=(const request_handler&) = delete;++ /// Construct with a directory containing files to be served.+ explicit request_handler(const std::string& doc_root);++ /// Handle a request and produce a reply.+ void handle_request(const request& req, reply& rep);++private:+ /// The directory containing the files to be served.+ std::string doc_root_;++ /// Perform URL-decoding on a string. Returns false if the encoding was+ /// invalid.+ static bool url_decode(const std::string& in, std::string& out);+};++} // namespace server+} // namespace http++#endif // HTTP_REQUEST_HANDLER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/http/server/request_parser.hpp view
@@ -0,0 +1,96 @@+//+// request_parser.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_REQUEST_PARSER_HPP+#define HTTP_REQUEST_PARSER_HPP++#include <tuple>++namespace http {+namespace server {++struct request;++/// Parser for incoming requests.+class request_parser+{+public:+ /// Construct ready to parse the request method.+ request_parser();++ /// Reset to initial parser state.+ void reset();++ /// Result of parse.+ enum result_type { good, bad, indeterminate };++ /// Parse some data. The enum return value is good when a complete request has+ /// been parsed, bad if the data is invalid, indeterminate when more data is+ /// required. The InputIterator return value indicates how much of the input+ /// has been consumed.+ template <typename InputIterator>+ std::tuple<result_type, InputIterator> parse(request& req,+ InputIterator begin, InputIterator end)+ {+ while (begin != end)+ {+ result_type result = consume(req, *begin++);+ if (result == good || result == bad)+ return std::make_tuple(result, begin);+ }+ return std::make_tuple(indeterminate, begin);+ }++private:+ /// Handle the next character of input.+ result_type consume(request& req, char input);++ /// Check if a byte is an HTTP character.+ static bool is_char(int c);++ /// Check if a byte is an HTTP control character.+ static bool is_ctl(int c);++ /// Check if a byte is defined as an HTTP tspecial character.+ static bool is_tspecial(int c);++ /// Check if a byte is a digit.+ static bool is_digit(int c);++ /// The current state of the parser.+ enum state+ {+ method_start,+ method,+ uri,+ http_version_h,+ http_version_t_1,+ http_version_t_2,+ http_version_p,+ http_version_slash,+ http_version_major_start,+ http_version_major,+ http_version_minor_start,+ http_version_minor,+ expecting_newline_1,+ header_line_start,+ header_lws,+ header_name,+ space_before_header_value,+ header_value,+ expecting_newline_2,+ expecting_newline_3+ } state_;+};++} // namespace server+} // namespace http++#endif // HTTP_REQUEST_PARSER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/http/server/server.hpp view
@@ -0,0 +1,64 @@+//+// server.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HTTP_SERVER_HPP+#define HTTP_SERVER_HPP++#include <asio.hpp>+#include <string>+#include "connection.hpp"+#include "connection_manager.hpp"+#include "request_handler.hpp"++namespace http {+namespace server {++/// The top-level class of the HTTP server.+class server+{+public:+ server(const server&) = delete;+ server& operator=(const server&) = delete;++ /// Construct the server to listen on the specified TCP address and port, and+ /// serve up files from the given directory.+ explicit server(const std::string& address, const std::string& port,+ const std::string& doc_root);++ /// Run the server's io_context loop.+ void run();++private:+ /// Perform an asynchronous accept operation.+ void do_accept();++ /// Wait for a request to stop the server.+ void do_await_stop();++ /// The io_context used to perform asynchronous operations.+ asio::io_context io_context_;++ /// The signal_set is used to register for process termination notifications.+ asio::signal_set signals_;++ /// Acceptor used to listen for incoming connections.+ asio::ip::tcp::acceptor acceptor_;++ /// The connection manager which owns all live connections.+ connection_manager connection_manager_;++ /// The handler for all incoming requests.+ request_handler request_handler_;+};++} // namespace server+} // namespace http++#endif // HTTP_SERVER_HPP
+ link/modules/asio-standalone/asio/src/examples/cpp11/socks4/socks4.hpp view
@@ -0,0 +1,143 @@+//+// socks4.hpp+// ~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 SOCKS4_HPP+#define SOCKS4_HPP++#include <array>+#include <string>+#include <asio/buffer.hpp>+#include <asio/ip/tcp.hpp>++namespace socks4 {++const unsigned char version = 0x04;++class request+{+public:+ enum command_type+ {+ connect = 0x01,+ bind = 0x02+ };++ request(command_type cmd, const asio::ip::tcp::endpoint& endpoint,+ const std::string& user_id)+ : version_(version),+ command_(cmd),+ user_id_(user_id),+ null_byte_(0)+ {+ // Only IPv4 is supported by the SOCKS 4 protocol.+ if (endpoint.protocol() != asio::ip::tcp::v4())+ {+ throw asio::system_error(+ asio::error::address_family_not_supported);+ }++ // Convert port number to network byte order.+ unsigned short port = endpoint.port();+ port_high_byte_ = (port >> 8) & 0xff;+ port_low_byte_ = port & 0xff;++ // Save IP address in network byte order.+ address_ = endpoint.address().to_v4().to_bytes();+ }++ std::array<asio::const_buffer, 7> buffers() const+ {+ return+ {+ {+ asio::buffer(&version_, 1),+ asio::buffer(&command_, 1),+ asio::buffer(&port_high_byte_, 1),+ asio::buffer(&port_low_byte_, 1),+ asio::buffer(address_),+ asio::buffer(user_id_),+ asio::buffer(&null_byte_, 1)+ }+ };+ }++private:+ unsigned char version_;+ unsigned char command_;+ unsigned char port_high_byte_;+ unsigned char port_low_byte_;+ asio::ip::address_v4::bytes_type address_;+ std::string user_id_;+ unsigned char null_byte_;+};++class reply+{+public:+ enum status_type+ {+ request_granted = 0x5a,+ request_failed = 0x5b,+ request_failed_no_identd = 0x5c,+ request_failed_bad_user_id = 0x5d+ };++ reply()+ : null_byte_(0),+ status_()+ {+ }++ std::array<asio::mutable_buffer, 5> buffers()+ {+ return+ {+ {+ asio::buffer(&null_byte_, 1),+ asio::buffer(&status_, 1),+ asio::buffer(&port_high_byte_, 1),+ asio::buffer(&port_low_byte_, 1),+ asio::buffer(address_)+ }+ };+ }++ bool success() const+ {+ return null_byte_ == 0 && status_ == request_granted;+ }++ unsigned char status() const+ {+ return status_;+ }++ asio::ip::tcp::endpoint endpoint() const+ {+ unsigned short port = port_high_byte_;+ port = (port << 8) & 0xff00;+ port = port | port_low_byte_;++ asio::ip::address_v4 address(address_);++ return asio::ip::tcp::endpoint(address, port);+ }++private:+ unsigned char null_byte_;+ unsigned char status_;+ unsigned char port_high_byte_;+ unsigned char port_low_byte_;+ asio::ip::address_v4::bytes_type address_;+};++} // namespace socks4++#endif // SOCKS4_HPP
+ link/modules/asio-standalone/asio/src/tests/latency/allocator.hpp view
@@ -0,0 +1,52 @@+//+// allocator.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 ALLOCATOR_HPP+#define ALLOCATOR_HPP++#include <boost/aligned_storage.hpp>++// Represents a single connection from a client.+class allocator+{+public:+ allocator()+ : in_use_(false)+ {+ }++ void* allocate(std::size_t n)+ {+ if (in_use_ || n >= 1024)+ return ::operator new(n);+ in_use_ = true;+ return static_cast<void*>(&space_);+ }++ void deallocate(void* p)+ {+ if (p != static_cast<void*>(&space_))+ ::operator delete(p);+ else+ in_use_ = false;+ }++private:+ allocator(const allocator&);+ allocator& operator=(const allocator&);++ // Whether the reusable memory space is currently in use.+ bool in_use_;++ // The reusable memory space made available by the allocator.+ boost::aligned_storage<1024>::type space_;+};++#endif // ALLOCATOR_HPP
+ link/modules/asio-standalone/asio/src/tests/latency/high_res_clock.hpp view
@@ -0,0 +1,53 @@+//+// high_res_clock.hpp+// ~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HIGH_RES_CLOCK_HPP+#define HIGH_RES_CLOCK_HPP++#include <boost/config.hpp>+#include <boost/cstdint.hpp>++#if defined(ASIO_WINDOWS)++inline boost::uint64_t high_res_clock()+{+ LARGE_INTEGER i;+ QueryPerformanceCounter(&i);+ return i.QuadPart;+}++#elif defined(__GNUC__) && defined(__x86_64__)++inline boost::uint64_t high_res_clock()+{+ unsigned long low, high;+ __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));+ return (((boost::uint64_t)high) << 32) | low;+}++#else++#include <boost/date_time/posix_time/posix_time_types.hpp>++inline boost::uint64_t high_res_clock()+{+ boost::posix_time::ptime now =+ boost::posix_time::microsec_clock::universal_time();++ boost::posix_time::ptime epoch(+ boost::gregorian::date(1970, 1, 1),+ boost::posix_time::seconds(0));++ return (now - epoch).total_microseconds();+}++#endif++#endif // HIGH_RES_CLOCK_HPP
+ link/modules/asio-standalone/asio/src/tests/performance/handler_allocator.hpp view
@@ -0,0 +1,112 @@+//+// handler_allocator.cpp+// ~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 HANDLER_ALLOCATOR_HPP+#define HANDLER_ALLOCATOR_HPP++#include "asio.hpp"+#include <boost/aligned_storage.hpp>+#include <boost/noncopyable.hpp>++// Class to manage the memory to be used for handler-based custom allocation.+// It contains a single block of memory which may be returned for allocation+// requests. If the memory is in use when an allocation request is made, the+// allocator delegates allocation to the global heap.+class handler_allocator+ : private boost::noncopyable+{+public:+ handler_allocator()+ : in_use_(false)+ {+ }++ void* allocate(std::size_t size)+ {+ if (!in_use_ && size < storage_.size)+ {+ in_use_ = true;+ return storage_.address();+ }++ return ::operator new(size);+ }++ void deallocate(void* pointer)+ {+ if (pointer == storage_.address())+ {+ in_use_ = false;+ }+ else+ {+ ::operator delete(pointer);+ }+ }++private:+ // Storage space used for handler-based custom memory allocation.+ boost::aligned_storage<1024> storage_;++ // Whether the handler-based custom allocation storage has been used.+ bool in_use_;+};++// Wrapper class template for handler objects to allow handler memory+// allocation to be customised. Calls to operator() are forwarded to the+// encapsulated handler.+template <typename Handler>+class custom_alloc_handler+{+public:+ custom_alloc_handler(handler_allocator& a, Handler h)+ : allocator_(a),+ handler_(h)+ {+ }++ template <typename Arg1>+ void operator()(Arg1 arg1)+ {+ handler_(arg1);+ }++ template <typename Arg1, typename Arg2>+ void operator()(Arg1 arg1, Arg2 arg2)+ {+ handler_(arg1, arg2);+ }++ friend void* asio_handler_allocate(std::size_t size,+ custom_alloc_handler<Handler>* this_handler)+ {+ return this_handler->allocator_.allocate(size);+ }++ friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,+ custom_alloc_handler<Handler>* this_handler)+ {+ this_handler->allocator_.deallocate(pointer);+ }++private:+ handler_allocator& allocator_;+ Handler handler_;+};++// Helper function to wrap a handler object to add custom allocation.+template <typename Handler>+inline custom_alloc_handler<Handler> make_custom_alloc_handler(+ handler_allocator& a, Handler h)+{+ return custom_alloc_handler<Handler>(a, h);+}++#endif // HANDLER_ALLOCATOR_HPP
+ link/modules/asio-standalone/asio/src/tests/unit/archetypes/async_ops.hpp view
@@ -0,0 +1,415 @@+//+// async_ops.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 ARCHETYPES_ASYNC_OPS_HPP+#define ARCHETYPES_ASYNC_OPS_HPP++#include <asio/associated_allocator.hpp>+#include <asio/associated_executor.hpp>+#include <asio/async_result.hpp>+#include <asio/error.hpp>++#if defined(ASIO_HAS_BOOST_BIND)+# include <boost/bind/bind.hpp>+#else // defined(ASIO_HAS_BOOST_BIND)+# include <functional>+#endif // defined(ASIO_HAS_BOOST_BIND)++namespace archetypes {++#if defined(ASIO_HAS_BOOST_BIND)+namespace bindns = boost;+#else // defined(ASIO_HAS_BOOST_BIND)+namespace bindns = std;+#endif // defined(ASIO_HAS_BOOST_BIND)++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken, void())+async_op_0(ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void()>::completion_handler_type handler_type;++ asio::async_completion<CompletionToken,+ void()> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ ex.post(ASIO_MOVE_CAST(handler_type)(completion.completion_handler), a);++ return completion.result.get();+}++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(asio::error_code))+async_op_ec_0(bool ok, ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void(asio::error_code)>::completion_handler_type handler_type;++ asio::async_completion<CompletionToken,+ void(asio::error_code)> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ if (ok)+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ asio::error_code()), a);+ }+ else+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ asio::error_code(asio::error::operation_aborted)), a);+ }++ return completion.result.get();+}++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(std::exception_ptr))+async_op_ex_0(bool ok, ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void(std::exception_ptr)>::completion_handler_type handler_type;++ asio::async_completion<CompletionToken,+ void(std::exception_ptr)> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ if (ok)+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ std::exception_ptr()), a);+ }+ else+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ std::make_exception_ptr(std::runtime_error("blah"))), a);+ }++ return completion.result.get();+}++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(int))+async_op_1(ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void(int)>::completion_handler_type handler_type;++ asio::async_completion<CompletionToken,+ void(int)> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ 42), a);++ return completion.result.get();+}++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken,+ void(asio::error_code, int))+async_op_ec_1(bool ok, ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void(asio::error_code, int)>::completion_handler_type+ handler_type;++ asio::async_completion<CompletionToken,+ void(asio::error_code, int)> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ if (ok)+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ asio::error_code(), 42), a);+ }+ else+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ asio::error_code(asio::error::operation_aborted),+ 0), a);+ }++ return completion.result.get();+}++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(std::exception_ptr, int))+async_op_ex_1(bool ok, ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void(std::exception_ptr, int)>::completion_handler_type+ handler_type;++ asio::async_completion<CompletionToken,+ void(std::exception_ptr, int)> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ if (ok)+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ std::exception_ptr(), 42), a);+ }+ else+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ std::make_exception_ptr(std::runtime_error("blah")), 0), a);+ }++ return completion.result.get();+}++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(int, double))+async_op_2(ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void(int, double)>::completion_handler_type handler_type;++ asio::async_completion<CompletionToken,+ void(int, double)> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ 42, 2.0), a);++ return completion.result.get();+}++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken,+ void(asio::error_code, int, double))+async_op_ec_2(bool ok, ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void(asio::error_code, int, double)>::completion_handler_type+ handler_type;++ asio::async_completion<CompletionToken,+ void(asio::error_code, int, double)> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ if (ok)+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ asio::error_code(), 42, 2.0), a);+ }+ else+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ asio::error_code(asio::error::operation_aborted),+ 0, 0.0), a);+ }++ return completion.result.get();+}++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken,+ void(std::exception_ptr, int, double))+async_op_ex_2(bool ok, ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void(std::exception_ptr, int, double)>::completion_handler_type+ handler_type;++ asio::async_completion<CompletionToken,+ void(std::exception_ptr, int, double)> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ if (ok)+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ std::exception_ptr(), 42, 2.0), a);+ }+ else+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ std::make_exception_ptr(std::runtime_error("blah")), 0, 0.0), a);+ }++ return completion.result.get();+}++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken, void(int, double, char))+async_op_3(ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void(int, double, char)>::completion_handler_type handler_type;++ asio::async_completion<CompletionToken,+ void(int, double, char)> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ 42, 2.0, 'a'), a);++ return completion.result.get();+}++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken,+ void(asio::error_code, int, double, char))+async_op_ec_3(bool ok, ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void(asio::error_code, int, double, char)>::completion_handler_type+ handler_type;++ asio::async_completion<CompletionToken,+ void(asio::error_code, int, double, char)> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ if (ok)+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ asio::error_code(), 42, 2.0, 'a'), a);+ }+ else+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ asio::error_code(asio::error::operation_aborted),+ 0, 0.0, 'z'), a);+ }++ return completion.result.get();+}++template <typename CompletionToken>+ASIO_INITFN_RESULT_TYPE(CompletionToken,+ void(std::exception_ptr, int, double, char))+async_op_ex_3(bool ok, ASIO_MOVE_ARG(CompletionToken) token)+{+ typedef typename asio::async_completion<CompletionToken,+ void(std::exception_ptr, int, double, char)>::completion_handler_type+ handler_type;++ asio::async_completion<CompletionToken,+ void(std::exception_ptr, int, double, char)> completion(token);++ typename asio::associated_allocator<handler_type>::type a+ = asio::get_associated_allocator(completion.completion_handler);++ typename asio::associated_executor<handler_type>::type ex+ = asio::get_associated_executor(completion.completion_handler);++ if (ok)+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ std::exception_ptr(), 42, 2.0, 'a'), a);+ }+ else+ {+ ex.post(+ bindns::bind(+ ASIO_MOVE_CAST(handler_type)(completion.completion_handler),+ std::make_exception_ptr(std::runtime_error("blah")),+ 0, 0.0, 'z'), a);+ }++ return completion.result.get();+}++} // namespace archetypes++#endif // ARCHETYPES_ASYNC_OPS_HPP
+ link/modules/asio-standalone/asio/src/tests/unit/archetypes/async_result.hpp view
@@ -0,0 +1,94 @@+//+// async_result.hpp+// ~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 ARCHETYPES_ASYNC_RESULT_HPP+#define ARCHETYPES_ASYNC_RESULT_HPP++#include <asio/async_result.hpp>++namespace archetypes {++struct lazy_handler+{+};++template <typename Signature>+struct concrete_handler;++template <typename R, typename Arg1>+struct concrete_handler<R(Arg1)>+{+ concrete_handler(lazy_handler)+ {+ }++ void operator()(typename asio::decay<Arg1>::type)+ {+ }++#if defined(ASIO_HAS_MOVE)+ concrete_handler(concrete_handler&&) {}+private:+ concrete_handler(const concrete_handler&);+#endif // defined(ASIO_HAS_MOVE)+};++template <typename R, typename Arg1, typename Arg2>+struct concrete_handler<R(Arg1, Arg2)>+{+ concrete_handler(lazy_handler)+ {+ }++ void operator()(typename asio::decay<Arg1>::type, typename asio::decay<Arg2>::type)+ {+ }++#if defined(ASIO_HAS_MOVE)+ concrete_handler(concrete_handler&&) {}+private:+ concrete_handler(const concrete_handler&);+#endif // defined(ASIO_HAS_MOVE)+};++} // namespace archetypes++namespace asio {++template <typename Signature>+class async_result<archetypes::lazy_handler, Signature>+{+public:+ // The concrete completion handler type.+ typedef archetypes::concrete_handler<Signature> completion_handler_type;++ // The return type of the initiating function.+ typedef int return_type;++ // Construct an async_result from a given handler.+ explicit async_result(completion_handler_type&)+ {+ }++ // Obtain the value to be returned from the initiating function.+ return_type get()+ {+ return 42;+ }++private:+ // Disallow copying and assignment.+ async_result(const async_result&) ASIO_DELETED;+ async_result& operator=(const async_result&) ASIO_DELETED;+};++} // namespace asio++#endif // ARCHETYPES_ASYNC_RESULT_HPP
+ link/modules/asio-standalone/asio/src/tests/unit/archetypes/gettable_socket_option.hpp view
@@ -0,0 +1,54 @@+//+// gettable_socket_option.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP+#define ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP++#include <cstddef>++namespace archetypes {++template <typename PointerType>+class gettable_socket_option+{+public:+ template <typename Protocol>+ int level(const Protocol&) const+ {+ return 0;+ }++ template <typename Protocol>+ int name(const Protocol&) const+ {+ return 0;+ }++ template <typename Protocol>+ PointerType* data(const Protocol&)+ {+ return 0;+ }++ template <typename Protocol>+ std::size_t size(const Protocol&) const+ {+ return 0;+ }++ template <typename Protocol>+ void resize(const Protocol&, std::size_t)+ {+ }+};++} // namespace archetypes++#endif // ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP
+ link/modules/asio-standalone/asio/src/tests/unit/archetypes/io_control_command.hpp view
@@ -0,0 +1,32 @@+//+// io_control_command.hpp+// ~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 ARCHETYPES_IO_CONTROL_COMMAND_HPP+#define ARCHETYPES_IO_CONTROL_COMMAND_HPP++namespace archetypes {++class io_control_command+{+public:+ int name() const+ {+ return 0;+ }++ void* data()+ {+ return 0;+ }+};++} // namespace archetypes++#endif // ARCHETYPES_IO_CONTROL_COMMAND_HPP
+ link/modules/asio-standalone/asio/src/tests/unit/archetypes/settable_socket_option.hpp view
@@ -0,0 +1,49 @@+//+// settable_socket_option.hpp+// ~~~~~~~~~~~~~~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP+#define ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP++#include <cstddef>++namespace archetypes {++template <typename PointerType>+class settable_socket_option+{+public:+ template <typename Protocol>+ int level(const Protocol&) const+ {+ return 0;+ }++ template <typename Protocol>+ int name(const Protocol&) const+ {+ return 0;+ }++ template <typename Protocol>+ const PointerType* data(const Protocol&) const+ {+ return 0;+ }++ template <typename Protocol>+ std::size_t size(const Protocol&) const+ {+ return 0;+ }+};++} // namespace archetypes++#endif // ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP
+ link/modules/asio-standalone/asio/src/tests/unit/unit_test.hpp view
@@ -0,0 +1,190 @@+//+// unit_test.hpp+// ~~~~~~~~~~~~~+//+// Copyright (c) 2003-2020 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 UNIT_TEST_HPP+#define UNIT_TEST_HPP++#include "asio/detail/config.hpp"+#include <iostream>+#include "asio/detail/atomic_count.hpp"++#if defined(__sun)+# include <stdlib.h> // Needed for lrand48.+#endif // defined(__sun)++#if defined(__BORLANDC__) && !defined(__clang__)++// Prevent use of intrinsic for strcmp.+# include <cstring>+# undef strcmp+ +// Suppress error about condition always being true.+# pragma option -w-ccc++#endif // defined(__BORLANDC__) && !defined(__clang__)++#if defined(ASIO_MSVC)+# pragma warning (disable:4127)+# pragma warning (push)+# pragma warning (disable:4244)+# pragma warning (disable:4702)+#endif // defined(ASIO_MSVC)++#if !defined(ASIO_TEST_IOSTREAM)+# define ASIO_TEST_IOSTREAM std::cerr+#endif // !defined(ASIO_TEST_IOSTREAM)++namespace asio {+namespace detail {++inline const char*& test_name()+{+ static const char* name = 0;+ return name;+}++inline atomic_count& test_errors()+{+ static atomic_count errors(0);+ return errors;+}++inline void begin_test_suite(const char* name)+{+ asio::detail::test_name();+ asio::detail::test_errors();+ ASIO_TEST_IOSTREAM << name << " test suite begins" << std::endl;+}++inline int end_test_suite(const char* name)+{+ ASIO_TEST_IOSTREAM << name << " test suite ends" << std::endl;+ ASIO_TEST_IOSTREAM << "\n*** ";+ long errors = asio::detail::test_errors();+ if (errors == 0)+ ASIO_TEST_IOSTREAM << "No errors detected.";+ else if (errors == 1)+ ASIO_TEST_IOSTREAM << "1 error detected.";+ else+ ASIO_TEST_IOSTREAM << errors << " errors detected." << std::endl;+ ASIO_TEST_IOSTREAM << std::endl;+ return errors == 0 ? 0 : 1;+}++template <void (*Test)()>+inline void run_test(const char* name)+{+ test_name() = name;+ long errors_before = asio::detail::test_errors();+ Test();+ if (test_errors() == errors_before)+ ASIO_TEST_IOSTREAM << name << " passed" << std::endl;+ else+ ASIO_TEST_IOSTREAM << name << " failed" << std::endl;+}++template <void (*)()>+inline void compile_test(const char* name)+{+ ASIO_TEST_IOSTREAM << name << " passed" << std::endl;+}++#if defined(ASIO_NO_EXCEPTIONS)++template <typename T>+void throw_exception(const T& t)+{+ ASIO_TEST_IOSTREAM << "Exception: " << t.what() << std::endl;+ std::abort();+}++#endif // defined(ASIO_NO_EXCEPTIONS)++} // namespace detail+} // namespace asio++#define ASIO_CHECK(expr) \+ do { if (!(expr)) { \+ ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \+ << asio::detail::test_name() << ": " \+ << "check '" << #expr << "' failed" << std::endl; \+ ++asio::detail::test_errors(); \+ } } while (0)++#define ASIO_CHECK_MESSAGE(expr, msg) \+ do { if (!(expr)) { \+ ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \+ << asio::detail::test_name() << ": " \+ << msg << std::endl; \+ ++asio::detail::test_errors(); \+ } } while (0)++#define ASIO_WARN_MESSAGE(expr, msg) \+ do { if (!(expr)) { \+ ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \+ << asio::detail::test_name() << ": " \+ << msg << std::endl; \+ } } while (0)++#define ASIO_ERROR(msg) \+ do { \+ ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \+ << asio::detail::test_name() << ": " \+ << msg << std::endl; \+ ++asio::detail::test_errors(); \+ } while (0)++#define ASIO_TEST_SUITE(name, tests) \+ int main() \+ { \+ asio::detail::begin_test_suite(name); \+ tests \+ return asio::detail::end_test_suite(name); \+ }++#define ASIO_TEST_CASE(test) \+ asio::detail::run_test<&test>(#test);++#define ASIO_TEST_CASE2(test1, test2) \+ asio::detail::run_test<&test1, test2>(#test1 "," #test2);++#define ASIO_TEST_CASE3(test1, test2, test3) \+ asio::detail::run_test<&test1, test2, test3>( \+ #test1 "," #test2 "," #test3);++#define ASIO_TEST_CASE4(test1, test2, test3, test4) \+ asio::detail::run_test<&test1, test2, test3, test4>( \+ #test1 "," #test2 "," #test3 "," #test4);++#define ASIO_TEST_CASE5(test1, test2, test3, test4, test5) \+ asio::detail::run_test<&test1, test2, test3, test4, test5>( \+ #test1 "," #test2 "," #test3 "," #test4 "," #test5);++#define ASIO_COMPILE_TEST_CASE(test) \+ asio::detail::compile_test<&test>(#test);++inline void null_test()+{+}++#if defined(__GNUC__) && defined(_AIX)++// AIX needs this symbol defined in asio, even if it doesn't do anything.+int test_main(int, char**)+{+}++#endif // defined(__GNUC__) && defined(_AIX)++#if defined(ASIO_MSVC)+# pragma warning (pop)+#endif // defined(ASIO_MSVC)++#endif // UNIT_TEST_HPP
+ link/third_party/catch/catch.hpp view
@@ -0,0 +1,17959 @@+/*+ * Catch v2.13.7+ * Generated: 2021-07-28 20:29:27.753164+ * ----------------------------------------------------------+ * This file has been merged from multiple headers. Please don't edit it directly+ * Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved.+ *+ * 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 TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED+#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED+// start catch.hpp+++#define CATCH_VERSION_MAJOR 2+#define CATCH_VERSION_MINOR 13+#define CATCH_VERSION_PATCH 7++#ifdef __clang__+# pragma clang system_header+#elif defined __GNUC__+# pragma GCC system_header+#endif++// start catch_suppress_warnings.h++#ifdef __clang__+# ifdef __ICC // icpc defines the __clang__ macro+# pragma warning(push)+# pragma warning(disable: 161 1682)+# else // __ICC+# pragma clang diagnostic push+# pragma clang diagnostic ignored "-Wpadded"+# pragma clang diagnostic ignored "-Wswitch-enum"+# pragma clang diagnostic ignored "-Wcovered-switch-default"+# endif+#elif defined __GNUC__+ // Because REQUIREs trigger GCC's -Wparentheses, and because still+ // supported version of g++ have only buggy support for _Pragmas,+ // Wparentheses have to be suppressed globally.+# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details++# pragma GCC diagnostic push+# pragma GCC diagnostic ignored "-Wunused-variable"+# pragma GCC diagnostic ignored "-Wpadded"+#endif+// end catch_suppress_warnings.h+#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)+# define CATCH_IMPL+# define CATCH_CONFIG_ALL_PARTS+#endif++// In the impl file, we want to have access to all parts of the headers+// Can also be used to sanely support PCHs+#if defined(CATCH_CONFIG_ALL_PARTS)+# define CATCH_CONFIG_EXTERNAL_INTERFACES+# if defined(CATCH_CONFIG_DISABLE_MATCHERS)+# undef CATCH_CONFIG_DISABLE_MATCHERS+# endif+# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)+# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER+# endif+#endif++#if !defined(CATCH_CONFIG_IMPL_ONLY)+// start catch_platform.h++// See e.g.:+// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html+#ifdef __APPLE__+# include <TargetConditionals.h>+# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \+ (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)+# define CATCH_PLATFORM_MAC+# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)+# define CATCH_PLATFORM_IPHONE+# endif++#elif defined(linux) || defined(__linux) || defined(__linux__)+# define CATCH_PLATFORM_LINUX++#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)+# define CATCH_PLATFORM_WINDOWS+#endif++// end catch_platform.h++#ifdef CATCH_IMPL+# ifndef CLARA_CONFIG_MAIN+# define CLARA_CONFIG_MAIN_NOT_DEFINED+# define CLARA_CONFIG_MAIN+# endif+#endif++// start catch_user_interfaces.h++namespace Catch {+ unsigned int rngSeed();+}++// end catch_user_interfaces.h+// start catch_tag_alias_autoregistrar.h++// start catch_common.h++// start catch_compiler_capabilities.h++// Detect a number of compiler features - by compiler+// The following features are defined:+//+// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?+// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?+// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?+// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?+// ****************+// Note to maintainers: if new toggles are added please document them+// in configuration.md, too+// ****************++// In general each macro has a _NO_<feature name> form+// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature.+// Many features, at point of detection, define an _INTERNAL_ macro, so they+// can be combined, en-mass, with the _NO_ forms later.++#ifdef __cplusplus++# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)+# define CATCH_CPP14_OR_GREATER+# endif++# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)+# define CATCH_CPP17_OR_GREATER+# endif++#endif++// Only GCC compiler should be used in this block, so other compilers trying to+// mask themselves as GCC should be ignored.+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )++# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)++#endif++#if defined(__clang__)++# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )++// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug+// which results in calls to destructors being emitted for each temporary,+// without a matching initialization. In practice, this can result in something+// like `std::string::~string` being called on an uninitialized value.+//+// For example, this code will likely segfault under IBM XL:+// ```+// REQUIRE(std::string("12") + "34" == "1234")+// ```+//+// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.+# if !defined(__ibmxl__) && !defined(__CUDACC__)+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */+# endif++# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \+ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")++# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \+ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )++# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \+ _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )++# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \+ _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )++# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \+ _Pragma( "clang diagnostic ignored \"-Wunused-template\"" )++#endif // __clang__++////////////////////////////////////////////////////////////////////////////////+// Assume that non-Windows platforms support posix signals by default+#if !defined(CATCH_PLATFORM_WINDOWS)+ #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS+#endif++////////////////////////////////////////////////////////////////////////////////+// We know some environments not to support full POSIX signals+#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__)+ #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS+#endif++#ifdef __OS400__+# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS+# define CATCH_CONFIG_COLOUR_NONE+#endif++////////////////////////////////////////////////////////////////////////////////+// Android somehow still does not support std::to_string+#if defined(__ANDROID__)+# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING+# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE+#endif++////////////////////////////////////////////////////////////////////////////////+// Not all Windows environments support SEH properly+#if defined(__MINGW32__)+# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH+#endif++////////////////////////////////////////////////////////////////////////////////+// PS4+#if defined(__ORBIS__)+# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE+#endif++////////////////////////////////////////////////////////////////////////////////+// Cygwin+#ifdef __CYGWIN__++// Required for some versions of Cygwin to declare gettimeofday+// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin+# define _BSD_SOURCE+// some versions of cygwin (most) do not support std::to_string. Use the libstd check.+// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813+# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \+ && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))++# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING++# endif+#endif // __CYGWIN__++////////////////////////////////////////////////////////////////////////////////+// Visual C+++#if defined(_MSC_VER)++# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) )++// Universal Windows platform does not support SEH+// Or console colours (or console at all...)+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)+# define CATCH_CONFIG_COLOUR_NONE+# else+# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH+# endif++// MSVC traditional preprocessor needs some workaround for __VA_ARGS__+// _MSVC_TRADITIONAL == 0 means new conformant preprocessor+// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor+# if !defined(__clang__) // Handle Clang masquerading for msvc+# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)+# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+# endif // MSVC_TRADITIONAL+# endif // __clang__++#endif // _MSC_VER++#if defined(_REENTRANT) || defined(_MSC_VER)+// Enable async processing, as -pthread is specified or no additional linking is required+# define CATCH_INTERNAL_CONFIG_USE_ASYNC+#endif // _MSC_VER++////////////////////////////////////////////////////////////////////////////////+// Check if we are compiled with -fno-exceptions or equivalent+#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)+# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED+#endif++////////////////////////////////////////////////////////////////////////////////+// DJGPP+#ifdef __DJGPP__+# define CATCH_INTERNAL_CONFIG_NO_WCHAR+#endif // __DJGPP__++////////////////////////////////////////////////////////////////////////////////+// Embarcadero C++Build+#if defined(__BORLANDC__)+ #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN+#endif++////////////////////////////////////////////////////////////////////////////////++// Use of __COUNTER__ is suppressed during code analysis in+// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly+// handled by it.+// Otherwise all supported compilers support COUNTER macro,+// but user still might want to turn it off+#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )+ #define CATCH_INTERNAL_CONFIG_COUNTER+#endif++////////////////////////////////////////////////////////////////////////////////++// RTX is a special version of Windows that is real time.+// This means that it is detected as Windows, but does not provide+// the same set of capabilities as real Windows does.+#if defined(UNDER_RTSS) || defined(RTX64_BUILD)+ #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH+ #define CATCH_INTERNAL_CONFIG_NO_ASYNC+ #define CATCH_CONFIG_COLOUR_NONE+#endif++#if !defined(_GLIBCXX_USE_C99_MATH_TR1)+#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER+#endif++// Various stdlib support checks that require __has_include+#if defined(__has_include)+ // Check if string_view is available and usable+ #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)+ # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW+ #endif++ // Check if optional is available and usable+ # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)+ # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL+ # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)++ // Check if byte is available and usable+ # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)+ # include <cstddef>+ # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0)+ # define CATCH_INTERNAL_CONFIG_CPP17_BYTE+ # endif+ # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)++ // Check if variant is available and usable+ # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)+ # if defined(__clang__) && (__clang_major__ < 8)+ // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852+ // fix should be in clang 8, workaround in libstdc++ 8.2+ # include <ciso646>+ # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)+ # define CATCH_CONFIG_NO_CPP17_VARIANT+ # else+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT+ # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)+ # else+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT+ # endif // defined(__clang__) && (__clang_major__ < 8)+ # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)+#endif // defined(__has_include)++#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)+# define CATCH_CONFIG_COUNTER+#endif+#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH)+# define CATCH_CONFIG_WINDOWS_SEH+#endif+// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.+#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)+# define CATCH_CONFIG_POSIX_SIGNALS+#endif+// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions.+#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR)+# define CATCH_CONFIG_WCHAR+#endif++#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)+# define CATCH_CONFIG_CPP11_TO_STRING+#endif++#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)+# define CATCH_CONFIG_CPP17_OPTIONAL+#endif++#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)+# define CATCH_CONFIG_CPP17_STRING_VIEW+#endif++#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT)+# define CATCH_CONFIG_CPP17_VARIANT+#endif++#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)+# define CATCH_CONFIG_CPP17_BYTE+#endif++#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)+# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE+#endif++#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE)+# define CATCH_CONFIG_NEW_CAPTURE+#endif++#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+# define CATCH_CONFIG_DISABLE_EXCEPTIONS+#endif++#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN)+# define CATCH_CONFIG_POLYFILL_ISNAN+#endif++#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)+# define CATCH_CONFIG_USE_ASYNC+#endif++#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE)+# define CATCH_CONFIG_ANDROID_LOGWRITE+#endif++#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)+# define CATCH_CONFIG_GLOBAL_NEXTAFTER+#endif++// Even if we do not think the compiler has that warning, we still have+// to provide a macro that can be used by the code.+#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION)+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION+#endif+#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION)+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION+#endif+#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS+#endif+#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)+# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS+#endif+#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)+# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS+#endif+#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)+# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS+#endif++// The goal of this macro is to avoid evaluation of the arguments, but+// still have the compiler warn on problems inside...+#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN)+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...)+#endif++#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS+#elif defined(__clang__) && (__clang_major__ < 5)+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS+#endif++#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS)+# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS+#endif++#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+#define CATCH_TRY if ((true))+#define CATCH_CATCH_ALL if ((false))+#define CATCH_CATCH_ANON(type) if ((false))+#else+#define CATCH_TRY try+#define CATCH_CATCH_ALL catch (...)+#define CATCH_CATCH_ANON(type) catch (type)+#endif++#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR)+#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+#endif++// end catch_compiler_capabilities.h+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line+#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )+#ifdef CATCH_CONFIG_COUNTER+# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )+#else+# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )+#endif++#include <iosfwd>+#include <string>+#include <cstdint>++// We need a dummy global operator<< so we can bring it into Catch namespace later+struct Catch_global_namespace_dummy {};+std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);++namespace Catch {++ struct CaseSensitive { enum Choice {+ Yes,+ No+ }; };++ class NonCopyable {+ NonCopyable( NonCopyable const& ) = delete;+ NonCopyable( NonCopyable && ) = delete;+ NonCopyable& operator = ( NonCopyable const& ) = delete;+ NonCopyable& operator = ( NonCopyable && ) = delete;++ protected:+ NonCopyable();+ virtual ~NonCopyable();+ };++ struct SourceLineInfo {++ SourceLineInfo() = delete;+ SourceLineInfo( char const* _file, std::size_t _line ) noexcept+ : file( _file ),+ line( _line )+ {}++ SourceLineInfo( SourceLineInfo const& other ) = default;+ SourceLineInfo& operator = ( SourceLineInfo const& ) = default;+ SourceLineInfo( SourceLineInfo&& ) noexcept = default;+ SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;++ bool empty() const noexcept { return file[0] == '\0'; }+ bool operator == ( SourceLineInfo const& other ) const noexcept;+ bool operator < ( SourceLineInfo const& other ) const noexcept;++ char const* file;+ std::size_t line;+ };++ std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );++ // Bring in operator<< from global namespace into Catch namespace+ // This is necessary because the overload of operator<< above makes+ // lookup stop at namespace Catch+ using ::operator<<;++ // Use this in variadic streaming macros to allow+ // >> +StreamEndStop+ // as well as+ // >> stuff +StreamEndStop+ struct StreamEndStop {+ std::string operator+() const;+ };+ template<typename T>+ T const& operator + ( T const& value, StreamEndStop ) {+ return value;+ }+}++#define CATCH_INTERNAL_LINEINFO \+ ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )++// end catch_common.h+namespace Catch {++ struct RegistrarForTagAliases {+ RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );+ };++} // end namespace Catch++#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION++// end catch_tag_alias_autoregistrar.h+// start catch_test_registry.h++// start catch_interfaces_testcase.h++#include <vector>++namespace Catch {++ class TestSpec;++ struct ITestInvoker {+ virtual void invoke () const = 0;+ virtual ~ITestInvoker();+ };++ class TestCase;+ struct IConfig;++ struct ITestCaseRegistry {+ virtual ~ITestCaseRegistry();+ virtual std::vector<TestCase> const& getAllTests() const = 0;+ virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;+ };++ bool isThrowSafe( TestCase const& testCase, IConfig const& config );+ bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );+ std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );+ std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );++}++// end catch_interfaces_testcase.h+// start catch_stringref.h++#include <cstddef>+#include <string>+#include <iosfwd>+#include <cassert>++namespace Catch {++ /// A non-owning string class (similar to the forthcoming std::string_view)+ /// Note that, because a StringRef may be a substring of another string,+ /// it may not be null terminated.+ class StringRef {+ public:+ using size_type = std::size_t;+ using const_iterator = const char*;++ private:+ static constexpr char const* const s_empty = "";++ char const* m_start = s_empty;+ size_type m_size = 0;++ public: // construction+ constexpr StringRef() noexcept = default;++ StringRef( char const* rawChars ) noexcept;++ constexpr StringRef( char const* rawChars, size_type size ) noexcept+ : m_start( rawChars ),+ m_size( size )+ {}++ StringRef( std::string const& stdString ) noexcept+ : m_start( stdString.c_str() ),+ m_size( stdString.size() )+ {}++ explicit operator std::string() const {+ return std::string(m_start, m_size);+ }++ public: // operators+ auto operator == ( StringRef const& other ) const noexcept -> bool;+ auto operator != (StringRef const& other) const noexcept -> bool {+ return !(*this == other);+ }++ auto operator[] ( size_type index ) const noexcept -> char {+ assert(index < m_size);+ return m_start[index];+ }++ public: // named queries+ constexpr auto empty() const noexcept -> bool {+ return m_size == 0;+ }+ constexpr auto size() const noexcept -> size_type {+ return m_size;+ }++ // Returns the current start pointer. If the StringRef is not+ // null-terminated, throws std::domain_exception+ auto c_str() const -> char const*;++ public: // substrings and searches+ // Returns a substring of [start, start + length).+ // If start + length > size(), then the substring is [start, size()).+ // If start > size(), then the substring is empty.+ auto substr( size_type start, size_type length ) const noexcept -> StringRef;++ // Returns the current start pointer. May not be null-terminated.+ auto data() const noexcept -> char const*;++ constexpr auto isNullTerminated() const noexcept -> bool {+ return m_start[m_size] == '\0';+ }++ public: // iterators+ constexpr const_iterator begin() const { return m_start; }+ constexpr const_iterator end() const { return m_start + m_size; }+ };++ auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;+ auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;++ constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {+ return StringRef( rawChars, size );+ }+} // namespace Catch++constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {+ return Catch::StringRef( rawChars, size );+}++// end catch_stringref.h+// start catch_preprocessor.hpp+++#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__+#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__)))+#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__)))+#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__)))+#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__)))+#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__)))++#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__+// MSVC needs more evaluations+#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__)))+#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__))+#else+#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__)+#endif++#define CATCH_REC_END(...)+#define CATCH_REC_OUT++#define CATCH_EMPTY()+#define CATCH_DEFER(id) id CATCH_EMPTY()++#define CATCH_REC_GET_END2() 0, CATCH_REC_END+#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2+#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1+#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT+#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0)+#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next)++#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )+#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ )+#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )++#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )+#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ )+#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )++// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results,+// and passes userdata as the first parameter to each invocation,+// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c)+#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0))++#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))++#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param)+#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__+#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__+#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF+#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))+#else+// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF+#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)+#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)+#endif++#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__+#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name)++#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))+#else+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()))+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))+#endif++#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\+ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__)++#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0)+#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1)+#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2)+#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)+#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)+#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)+#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6)+#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)+#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)+#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)+#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10)++#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N++#define INTERNAL_CATCH_TYPE_GEN\+ template<typename...> struct TypeList {};\+ template<typename...Ts>\+ constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\+ template<template<typename...> class...> struct TemplateTypeList{};\+ template<template<typename...> class...Cs>\+ constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\+ template<typename...>\+ struct append;\+ template<typename...>\+ struct rewrap;\+ template<template<typename...> class, typename...>\+ struct create;\+ template<template<typename...> class, typename>\+ struct convert;\+ \+ template<typename T> \+ struct append<T> { using type = T; };\+ template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\+ struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\+ template< template<typename...> class L1, typename...E1, typename...Rest>\+ struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\+ \+ template< template<typename...> class Container, template<typename...> class List, typename...elems>\+ struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\+ template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\+ struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\+ \+ template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\+ struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\+ template<template <typename...> class Final, template <typename...> class List, typename...Ts>\+ struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };++#define INTERNAL_CATCH_NTTP_1(signature, ...)\+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\+ constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\+ constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \+ \+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\+ template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\+ struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };++#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)+#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\+ static void TestName()+#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\+ static void TestName()++#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName)+#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\+ static void TestName()+#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\+ static void TestName()++#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\+ template<typename Type>\+ void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\+ {\+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\+ }++#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\+ void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\+ {\+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\+ }++#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\+ template<typename Type>\+ void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\+ {\+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\+ }++#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\+ void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\+ {\+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\+ }++#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName)+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\+ template<typename TestType> \+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \+ void test();\+ }++#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \+ void test();\+ }++#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName)+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\+ template<typename TestType> \+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test()+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test()++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+#define INTERNAL_CATCH_NTTP_0+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__),INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_0)+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)+#else+#define INTERNAL_CATCH_NTTP_0(signature)+#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1,INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_0)( __VA_ARGS__))+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__))+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__))+#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__))+#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__))+#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__))+#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__))+#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__))+#endif++// end catch_preprocessor.hpp+// start catch_meta.hpp+++#include <type_traits>++namespace Catch {+ template<typename T>+ struct always_false : std::false_type {};++ template <typename> struct true_given : std::true_type {};+ struct is_callable_tester {+ template <typename Fun, typename... Args>+ true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);+ template <typename...>+ std::false_type static test(...);+ };++ template <typename T>+ struct is_callable;++ template <typename Fun, typename... Args>+ struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};++#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703+ // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is+ // replaced with std::invoke_result here.+ template <typename Func, typename... U>+ using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;+#else+ // Keep ::type here because we still support C++11+ template <typename Func, typename... U>+ using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type;+#endif++} // namespace Catch++namespace mpl_{+ struct na;+}++// end catch_meta.hpp+namespace Catch {++template<typename C>+class TestInvokerAsMethod : public ITestInvoker {+ void (C::*m_testAsMethod)();+public:+ TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {}++ void invoke() const override {+ C obj;+ (obj.*m_testAsMethod)();+ }+};++auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*;++template<typename C>+auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* {+ return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod );+}++struct NameAndTags {+ NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept;+ StringRef name;+ StringRef tags;+};++struct AutoReg : NonCopyable {+ AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept;+ ~AutoReg();+};++} // end namespace Catch++#if defined(CATCH_CONFIG_DISABLE)+ #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \+ static void TestName()+ #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \+ namespace{ \+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \+ void test(); \+ }; \+ } \+ void TestName::test()+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature))+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \+ namespace{ \+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\+ } \+ } \+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))++ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ )+ #else+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )+ #endif++ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ )+ #else+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )+ #endif++ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )+ #else+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )+ #endif++ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )+ #else+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )+ #endif+#endif++ ///////////////////////////////////////////////////////////////////////////////+ #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \+ static void TestName(); \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \+ static void TestName()+ #define INTERNAL_CATCH_TESTCASE( ... ) \+ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )++ ///////////////////////////////////////////////////////////////////////////////+ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION++ ///////////////////////////////////////////////////////////////////////////////+ #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ namespace{ \+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \+ void test(); \+ }; \+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \+ } \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \+ void TestName::test()+ #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \+ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )++ ///////////////////////////////////////////////////////////////////////////////+ #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION++ ///////////////////////////////////////////////////////////////////////////////+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \+ INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\+ namespace {\+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\+ INTERNAL_CATCH_TYPE_GEN\+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\+ INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\+ template<typename...Types> \+ struct TestName{\+ TestName(){\+ int index = 0; \+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\+ using expander = int[];\+ (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \+ }\+ };\+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\+ TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\+ return 0;\+ }();\+ }\+ }\+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ )+#else+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )+#endif++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ )+#else+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )+#endif++ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \+ template<typename TestType> static void TestFuncName(); \+ namespace {\+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \+ INTERNAL_CATCH_TYPE_GEN \+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \+ template<typename... Types> \+ struct TestName { \+ void reg_tests() { \+ int index = 0; \+ using expander = int[]; \+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\+ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\+ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */\+ } \+ }; \+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \+ using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \+ TestInit t; \+ t.reg_tests(); \+ return 0; \+ }(); \+ } \+ } \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \+ template<typename TestType> \+ static void TestFuncName()++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T,__VA_ARGS__)+#else+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T, __VA_ARGS__ ) )+#endif++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__)+#else+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )+#endif++ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \+ template<typename TestType> static void TestFunc(); \+ namespace {\+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\+ INTERNAL_CATCH_TYPE_GEN\+ template<typename... Types> \+ struct TestName { \+ void reg_tests() { \+ int index = 0; \+ using expander = int[]; \+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\+ } \+ };\+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \+ using TestInit = typename convert<TestName, TmplList>::type; \+ TestInit t; \+ t.reg_tests(); \+ return 0; \+ }(); \+ }}\+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \+ template<typename TestType> \+ static void TestFunc()++ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, TmplList )++ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \+ namespace {\+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \+ INTERNAL_CATCH_TYPE_GEN\+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\+ INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\+ template<typename...Types> \+ struct TestNameClass{\+ TestNameClass(){\+ int index = 0; \+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\+ using expander = int[];\+ (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \+ }\+ };\+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\+ TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\+ return 0;\+ }();\+ }\+ }\+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )+#else+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )+#endif++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )+#else+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )+#endif++ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \+ template<typename TestType> \+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \+ void test();\+ };\+ namespace {\+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\+ INTERNAL_CATCH_TYPE_GEN \+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\+ template<typename...Types>\+ struct TestNameClass{\+ void reg_tests(){\+ int index = 0;\+ using expander = int[];\+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\+ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\+ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */ \+ }\+ };\+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\+ using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\+ TestInit t;\+ t.reg_tests();\+ return 0;\+ }(); \+ }\+ }\+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \+ template<typename TestType> \+ void TestName<TestType>::test()++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T, __VA_ARGS__ )+#else+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) )+#endif++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature, __VA_ARGS__ )+#else+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )+#endif++ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \+ template<typename TestType> \+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \+ void test();\+ };\+ namespace {\+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \+ INTERNAL_CATCH_TYPE_GEN\+ template<typename...Types>\+ struct TestNameClass{\+ void reg_tests(){\+ int index = 0;\+ using expander = int[];\+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \+ }\+ };\+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\+ using TestInit = typename convert<TestNameClass, TmplList>::type;\+ TestInit t;\+ t.reg_tests();\+ return 0;\+ }(); \+ }}\+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \+ template<typename TestType> \+ void TestName<TestType>::test()++#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, TmplList )++// end catch_test_registry.h+// start catch_capture.hpp++// start catch_assertionhandler.h++// start catch_assertioninfo.h++// start catch_result_type.h++namespace Catch {++ // ResultWas::OfType enum+ struct ResultWas { enum OfType {+ Unknown = -1,+ Ok = 0,+ Info = 1,+ Warning = 2,++ FailureBit = 0x10,++ ExpressionFailed = FailureBit | 1,+ ExplicitFailure = FailureBit | 2,++ Exception = 0x100 | FailureBit,++ ThrewException = Exception | 1,+ DidntThrowException = Exception | 2,++ FatalErrorCondition = 0x200 | FailureBit++ }; };++ bool isOk( ResultWas::OfType resultType );+ bool isJustInfo( int flags );++ // ResultDisposition::Flags enum+ struct ResultDisposition { enum Flags {+ Normal = 0x01,++ ContinueOnFailure = 0x02, // Failures fail test, but execution continues+ FalseTest = 0x04, // Prefix expression with !+ SuppressFail = 0x08 // Failures are reported but do not fail the test+ }; };++ ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs );++ bool shouldContinueOnFailure( int flags );+ inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }+ bool shouldSuppressFailure( int flags );++} // end namespace Catch++// end catch_result_type.h+namespace Catch {++ struct AssertionInfo+ {+ StringRef macroName;+ SourceLineInfo lineInfo;+ StringRef capturedExpression;+ ResultDisposition::Flags resultDisposition;++ // We want to delete this constructor but a compiler bug in 4.8 means+ // the struct is then treated as non-aggregate+ //AssertionInfo() = delete;+ };++} // end namespace Catch++// end catch_assertioninfo.h+// start catch_decomposer.h++// start catch_tostring.h++#include <vector>+#include <cstddef>+#include <type_traits>+#include <string>+// start catch_stream.h++#include <iosfwd>+#include <cstddef>+#include <ostream>++namespace Catch {++ std::ostream& cout();+ std::ostream& cerr();+ std::ostream& clog();++ class StringRef;++ struct IStream {+ virtual ~IStream();+ virtual std::ostream& stream() const = 0;+ };++ auto makeStream( StringRef const &filename ) -> IStream const*;++ class ReusableStringStream : NonCopyable {+ std::size_t m_index;+ std::ostream* m_oss;+ public:+ ReusableStringStream();+ ~ReusableStringStream();++ auto str() const -> std::string;++ template<typename T>+ auto operator << ( T const& value ) -> ReusableStringStream& {+ *m_oss << value;+ return *this;+ }+ auto get() -> std::ostream& { return *m_oss; }+ };+}++// end catch_stream.h+// start catch_interfaces_enum_values_registry.h++#include <vector>++namespace Catch {++ namespace Detail {+ struct EnumInfo {+ StringRef m_name;+ std::vector<std::pair<int, StringRef>> m_values;++ ~EnumInfo();++ StringRef lookup( int value ) const;+ };+ } // namespace Detail++ struct IMutableEnumValuesRegistry {+ virtual ~IMutableEnumValuesRegistry();++ virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;++ template<typename E>+ Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {+ static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");+ std::vector<int> intValues;+ intValues.reserve( values.size() );+ for( auto enumValue : values )+ intValues.push_back( static_cast<int>( enumValue ) );+ return registerEnum( enumName, allEnums, intValues );+ }+ };++} // Catch++// end catch_interfaces_enum_values_registry.h++#ifdef CATCH_CONFIG_CPP17_STRING_VIEW+#include <string_view>+#endif++#ifdef __OBJC__+// start catch_objc_arc.hpp++#import <Foundation/Foundation.h>++#ifdef __has_feature+#define CATCH_ARC_ENABLED __has_feature(objc_arc)+#else+#define CATCH_ARC_ENABLED 0+#endif++void arcSafeRelease( NSObject* obj );+id performOptionalSelector( id obj, SEL sel );++#if !CATCH_ARC_ENABLED+inline void arcSafeRelease( NSObject* obj ) {+ [obj release];+}+inline id performOptionalSelector( id obj, SEL sel ) {+ if( [obj respondsToSelector: sel] )+ return [obj performSelector: sel];+ return nil;+}+#define CATCH_UNSAFE_UNRETAINED+#define CATCH_ARC_STRONG+#else+inline void arcSafeRelease( NSObject* ){}+inline id performOptionalSelector( id obj, SEL sel ) {+#ifdef __clang__+#pragma clang diagnostic push+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"+#endif+ if( [obj respondsToSelector: sel] )+ return [obj performSelector: sel];+#ifdef __clang__+#pragma clang diagnostic pop+#endif+ return nil;+}+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained+#define CATCH_ARC_STRONG __strong+#endif++// end catch_objc_arc.hpp+#endif++#ifdef _MSC_VER+#pragma warning(push)+#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless+#endif++namespace Catch {+ namespace Detail {++ extern const std::string unprintableString;++ std::string rawMemoryToString( const void *object, std::size_t size );++ template<typename T>+ std::string rawMemoryToString( const T& object ) {+ return rawMemoryToString( &object, sizeof(object) );+ }++ template<typename T>+ class IsStreamInsertable {+ template<typename Stream, typename U>+ static auto test(int)+ -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());++ template<typename, typename>+ static auto test(...)->std::false_type;++ public:+ static const bool value = decltype(test<std::ostream, const T&>(0))::value;+ };++ template<typename E>+ std::string convertUnknownEnumToString( E e );++ template<typename T>+ typename std::enable_if<+ !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,+ std::string>::type convertUnstreamable( T const& ) {+ return Detail::unprintableString;+ }+ template<typename T>+ typename std::enable_if<+ !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,+ std::string>::type convertUnstreamable(T const& ex) {+ return ex.what();+ }++ template<typename T>+ typename std::enable_if<+ std::is_enum<T>::value+ , std::string>::type convertUnstreamable( T const& value ) {+ return convertUnknownEnumToString( value );+ }++#if defined(_MANAGED)+ //! Convert a CLR string to a utf8 std::string+ template<typename T>+ std::string clrReferenceToString( T^ ref ) {+ if (ref == nullptr)+ return std::string("null");+ auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());+ cli::pin_ptr<System::Byte> p = &bytes[0];+ return std::string(reinterpret_cast<char const *>(p), bytes->Length);+ }+#endif++ } // namespace Detail++ // If we decide for C++14, change these to enable_if_ts+ template <typename T, typename = void>+ struct StringMaker {+ template <typename Fake = T>+ static+ typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type+ convert(const Fake& value) {+ ReusableStringStream rss;+ // NB: call using the function-like syntax to avoid ambiguity with+ // user-defined templated operator<< under clang.+ rss.operator<<(value);+ return rss.str();+ }++ template <typename Fake = T>+ static+ typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type+ convert( const Fake& value ) {+#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)+ return Detail::convertUnstreamable(value);+#else+ return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);+#endif+ }+ };++ namespace Detail {++ // This function dispatches all stringification requests inside of Catch.+ // Should be preferably called fully qualified, like ::Catch::Detail::stringify+ template <typename T>+ std::string stringify(const T& e) {+ return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e);+ }++ template<typename E>+ std::string convertUnknownEnumToString( E e ) {+ return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e));+ }++#if defined(_MANAGED)+ template <typename T>+ std::string stringify( T^ e ) {+ return ::Catch::StringMaker<T^>::convert(e);+ }+#endif++ } // namespace Detail++ // Some predefined specializations++ template<>+ struct StringMaker<std::string> {+ static std::string convert(const std::string& str);+ };++#ifdef CATCH_CONFIG_CPP17_STRING_VIEW+ template<>+ struct StringMaker<std::string_view> {+ static std::string convert(std::string_view str);+ };+#endif++ template<>+ struct StringMaker<char const *> {+ static std::string convert(char const * str);+ };+ template<>+ struct StringMaker<char *> {+ static std::string convert(char * str);+ };++#ifdef CATCH_CONFIG_WCHAR+ template<>+ struct StringMaker<std::wstring> {+ static std::string convert(const std::wstring& wstr);+ };++# ifdef CATCH_CONFIG_CPP17_STRING_VIEW+ template<>+ struct StringMaker<std::wstring_view> {+ static std::string convert(std::wstring_view str);+ };+# endif++ template<>+ struct StringMaker<wchar_t const *> {+ static std::string convert(wchar_t const * str);+ };+ template<>+ struct StringMaker<wchar_t *> {+ static std::string convert(wchar_t * str);+ };+#endif++ // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer,+ // while keeping string semantics?+ template<int SZ>+ struct StringMaker<char[SZ]> {+ static std::string convert(char const* str) {+ return ::Catch::Detail::stringify(std::string{ str });+ }+ };+ template<int SZ>+ struct StringMaker<signed char[SZ]> {+ static std::string convert(signed char const* str) {+ return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });+ }+ };+ template<int SZ>+ struct StringMaker<unsigned char[SZ]> {+ static std::string convert(unsigned char const* str) {+ return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });+ }+ };++#if defined(CATCH_CONFIG_CPP17_BYTE)+ template<>+ struct StringMaker<std::byte> {+ static std::string convert(std::byte value);+ };+#endif // defined(CATCH_CONFIG_CPP17_BYTE)+ template<>+ struct StringMaker<int> {+ static std::string convert(int value);+ };+ template<>+ struct StringMaker<long> {+ static std::string convert(long value);+ };+ template<>+ struct StringMaker<long long> {+ static std::string convert(long long value);+ };+ template<>+ struct StringMaker<unsigned int> {+ static std::string convert(unsigned int value);+ };+ template<>+ struct StringMaker<unsigned long> {+ static std::string convert(unsigned long value);+ };+ template<>+ struct StringMaker<unsigned long long> {+ static std::string convert(unsigned long long value);+ };++ template<>+ struct StringMaker<bool> {+ static std::string convert(bool b);+ };++ template<>+ struct StringMaker<char> {+ static std::string convert(char c);+ };+ template<>+ struct StringMaker<signed char> {+ static std::string convert(signed char c);+ };+ template<>+ struct StringMaker<unsigned char> {+ static std::string convert(unsigned char c);+ };++ template<>+ struct StringMaker<std::nullptr_t> {+ static std::string convert(std::nullptr_t);+ };++ template<>+ struct StringMaker<float> {+ static std::string convert(float value);+ static int precision;+ };++ template<>+ struct StringMaker<double> {+ static std::string convert(double value);+ static int precision;+ };++ template <typename T>+ struct StringMaker<T*> {+ template <typename U>+ static std::string convert(U* p) {+ if (p) {+ return ::Catch::Detail::rawMemoryToString(p);+ } else {+ return "nullptr";+ }+ }+ };++ template <typename R, typename C>+ struct StringMaker<R C::*> {+ static std::string convert(R C::* p) {+ if (p) {+ return ::Catch::Detail::rawMemoryToString(p);+ } else {+ return "nullptr";+ }+ }+ };++#if defined(_MANAGED)+ template <typename T>+ struct StringMaker<T^> {+ static std::string convert( T^ ref ) {+ return ::Catch::Detail::clrReferenceToString(ref);+ }+ };+#endif++ namespace Detail {+ template<typename InputIterator, typename Sentinel = InputIterator>+ std::string rangeToString(InputIterator first, Sentinel last) {+ ReusableStringStream rss;+ rss << "{ ";+ if (first != last) {+ rss << ::Catch::Detail::stringify(*first);+ for (++first; first != last; ++first)+ rss << ", " << ::Catch::Detail::stringify(*first);+ }+ rss << " }";+ return rss.str();+ }+ }++#ifdef __OBJC__+ template<>+ struct StringMaker<NSString*> {+ static std::string convert(NSString * nsstring) {+ if (!nsstring)+ return "nil";+ return std::string("@") + [nsstring UTF8String];+ }+ };+ template<>+ struct StringMaker<NSObject*> {+ static std::string convert(NSObject* nsObject) {+ return ::Catch::Detail::stringify([nsObject description]);+ }++ };+ namespace Detail {+ inline std::string stringify( NSString* nsstring ) {+ return StringMaker<NSString*>::convert( nsstring );+ }++ } // namespace Detail+#endif // __OBJC__++} // namespace Catch++//////////////////////////////////////////////////////+// Separate std-lib types stringification, so it can be selectively enabled+// This means that we do not bring in++#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)+# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER+# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER+# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER+# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER+# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER+#endif++// Separate std::pair specialization+#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)+#include <utility>+namespace Catch {+ template<typename T1, typename T2>+ struct StringMaker<std::pair<T1, T2> > {+ static std::string convert(const std::pair<T1, T2>& pair) {+ ReusableStringStream rss;+ rss << "{ "+ << ::Catch::Detail::stringify(pair.first)+ << ", "+ << ::Catch::Detail::stringify(pair.second)+ << " }";+ return rss.str();+ }+ };+}+#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER++#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)+#include <optional>+namespace Catch {+ template<typename T>+ struct StringMaker<std::optional<T> > {+ static std::string convert(const std::optional<T>& optional) {+ ReusableStringStream rss;+ if (optional.has_value()) {+ rss << ::Catch::Detail::stringify(*optional);+ } else {+ rss << "{ }";+ }+ return rss.str();+ }+ };+}+#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER++// Separate std::tuple specialization+#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)+#include <tuple>+namespace Catch {+ namespace Detail {+ template<+ typename Tuple,+ std::size_t N = 0,+ bool = (N < std::tuple_size<Tuple>::value)+ >+ struct TupleElementPrinter {+ static void print(const Tuple& tuple, std::ostream& os) {+ os << (N ? ", " : " ")+ << ::Catch::Detail::stringify(std::get<N>(tuple));+ TupleElementPrinter<Tuple, N + 1>::print(tuple, os);+ }+ };++ template<+ typename Tuple,+ std::size_t N+ >+ struct TupleElementPrinter<Tuple, N, false> {+ static void print(const Tuple&, std::ostream&) {}+ };++ }++ template<typename ...Types>+ struct StringMaker<std::tuple<Types...>> {+ static std::string convert(const std::tuple<Types...>& tuple) {+ ReusableStringStream rss;+ rss << '{';+ Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());+ rss << " }";+ return rss.str();+ }+ };+}+#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER++#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)+#include <variant>+namespace Catch {+ template<>+ struct StringMaker<std::monostate> {+ static std::string convert(const std::monostate&) {+ return "{ }";+ }+ };++ template<typename... Elements>+ struct StringMaker<std::variant<Elements...>> {+ static std::string convert(const std::variant<Elements...>& variant) {+ if (variant.valueless_by_exception()) {+ return "{valueless variant}";+ } else {+ return std::visit(+ [](const auto& value) {+ return ::Catch::Detail::stringify(value);+ },+ variant+ );+ }+ }+ };+}+#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER++namespace Catch {+ // Import begin/ end from std here+ using std::begin;+ using std::end;++ namespace detail {+ template <typename...>+ struct void_type {+ using type = void;+ };++ template <typename T, typename = void>+ struct is_range_impl : std::false_type {+ };++ template <typename T>+ struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type {+ };+ } // namespace detail++ template <typename T>+ struct is_range : detail::is_range_impl<T> {+ };++#if defined(_MANAGED) // Managed types are never ranges+ template <typename T>+ struct is_range<T^> {+ static const bool value = false;+ };+#endif++ template<typename Range>+ std::string rangeToString( Range const& range ) {+ return ::Catch::Detail::rangeToString( begin( range ), end( range ) );+ }++ // Handle vector<bool> specially+ template<typename Allocator>+ std::string rangeToString( std::vector<bool, Allocator> const& v ) {+ ReusableStringStream rss;+ rss << "{ ";+ bool first = true;+ for( bool b : v ) {+ if( first )+ first = false;+ else+ rss << ", ";+ rss << ::Catch::Detail::stringify( b );+ }+ rss << " }";+ return rss.str();+ }++ template<typename R>+ struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> {+ static std::string convert( R const& range ) {+ return rangeToString( range );+ }+ };++ template <typename T, int SZ>+ struct StringMaker<T[SZ]> {+ static std::string convert(T const(&arr)[SZ]) {+ return rangeToString(arr);+ }+ };++} // namespace Catch++// Separate std::chrono::duration specialization+#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)+#include <ctime>+#include <ratio>+#include <chrono>++namespace Catch {++template <class Ratio>+struct ratio_string {+ static std::string symbol();+};++template <class Ratio>+std::string ratio_string<Ratio>::symbol() {+ Catch::ReusableStringStream rss;+ rss << '[' << Ratio::num << '/'+ << Ratio::den << ']';+ return rss.str();+}+template <>+struct ratio_string<std::atto> {+ static std::string symbol();+};+template <>+struct ratio_string<std::femto> {+ static std::string symbol();+};+template <>+struct ratio_string<std::pico> {+ static std::string symbol();+};+template <>+struct ratio_string<std::nano> {+ static std::string symbol();+};+template <>+struct ratio_string<std::micro> {+ static std::string symbol();+};+template <>+struct ratio_string<std::milli> {+ static std::string symbol();+};++ ////////////+ // std::chrono::duration specializations+ template<typename Value, typename Ratio>+ struct StringMaker<std::chrono::duration<Value, Ratio>> {+ static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {+ ReusableStringStream rss;+ rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';+ return rss.str();+ }+ };+ template<typename Value>+ struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {+ static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {+ ReusableStringStream rss;+ rss << duration.count() << " s";+ return rss.str();+ }+ };+ template<typename Value>+ struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {+ static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {+ ReusableStringStream rss;+ rss << duration.count() << " m";+ return rss.str();+ }+ };+ template<typename Value>+ struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {+ static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {+ ReusableStringStream rss;+ rss << duration.count() << " h";+ return rss.str();+ }+ };++ ////////////+ // std::chrono::time_point specialization+ // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>+ template<typename Clock, typename Duration>+ struct StringMaker<std::chrono::time_point<Clock, Duration>> {+ static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {+ return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";+ }+ };+ // std::chrono::time_point<system_clock> specialization+ template<typename Duration>+ struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {+ static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {+ auto converted = std::chrono::system_clock::to_time_t(time_point);++#ifdef _MSC_VER+ std::tm timeInfo = {};+ gmtime_s(&timeInfo, &converted);+#else+ std::tm* timeInfo = std::gmtime(&converted);+#endif++ auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");+ char timeStamp[timeStampSize];+ const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";++#ifdef _MSC_VER+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);+#else+ std::strftime(timeStamp, timeStampSize, fmt, timeInfo);+#endif+ return std::string(timeStamp);+ }+ };+}+#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER++#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \+namespace Catch { \+ template<> struct StringMaker<enumName> { \+ static std::string convert( enumName value ) { \+ static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \+ return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \+ } \+ }; \+}++#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )++#ifdef _MSC_VER+#pragma warning(pop)+#endif++// end catch_tostring.h+#include <iosfwd>++#ifdef _MSC_VER+#pragma warning(push)+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch+#pragma warning(disable:4018) // more "signed/unsigned mismatch"+#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)+#pragma warning(disable:4180) // qualifier applied to function type has no meaning+#pragma warning(disable:4800) // Forcing result to true or false+#endif++namespace Catch {++ struct ITransientExpression {+ auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }+ auto getResult() const -> bool { return m_result; }+ virtual void streamReconstructedExpression( std::ostream &os ) const = 0;++ ITransientExpression( bool isBinaryExpression, bool result )+ : m_isBinaryExpression( isBinaryExpression ),+ m_result( result )+ {}++ // We don't actually need a virtual destructor, but many static analysers+ // complain if it's not here :-(+ virtual ~ITransientExpression();++ bool m_isBinaryExpression;+ bool m_result;++ };++ void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );++ template<typename LhsT, typename RhsT>+ class BinaryExpr : public ITransientExpression {+ LhsT m_lhs;+ StringRef m_op;+ RhsT m_rhs;++ void streamReconstructedExpression( std::ostream &os ) const override {+ formatReconstructedExpression+ ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );+ }++ public:+ BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )+ : ITransientExpression{ true, comparisonResult },+ m_lhs( lhs ),+ m_op( op ),+ m_rhs( rhs )+ {}++ template<typename T>+ auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {+ static_assert(always_false<T>::value,+ "chained comparisons are not supported inside assertions, "+ "wrap the expression inside parentheses, or decompose it");+ }++ template<typename T>+ auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {+ static_assert(always_false<T>::value,+ "chained comparisons are not supported inside assertions, "+ "wrap the expression inside parentheses, or decompose it");+ }++ template<typename T>+ auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {+ static_assert(always_false<T>::value,+ "chained comparisons are not supported inside assertions, "+ "wrap the expression inside parentheses, or decompose it");+ }++ template<typename T>+ auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {+ static_assert(always_false<T>::value,+ "chained comparisons are not supported inside assertions, "+ "wrap the expression inside parentheses, or decompose it");+ }++ template<typename T>+ auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {+ static_assert(always_false<T>::value,+ "chained comparisons are not supported inside assertions, "+ "wrap the expression inside parentheses, or decompose it");+ }++ template<typename T>+ auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {+ static_assert(always_false<T>::value,+ "chained comparisons are not supported inside assertions, "+ "wrap the expression inside parentheses, or decompose it");+ }++ template<typename T>+ auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {+ static_assert(always_false<T>::value,+ "chained comparisons are not supported inside assertions, "+ "wrap the expression inside parentheses, or decompose it");+ }++ template<typename T>+ auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {+ static_assert(always_false<T>::value,+ "chained comparisons are not supported inside assertions, "+ "wrap the expression inside parentheses, or decompose it");+ }+ };++ template<typename LhsT>+ class UnaryExpr : public ITransientExpression {+ LhsT m_lhs;++ void streamReconstructedExpression( std::ostream &os ) const override {+ os << Catch::Detail::stringify( m_lhs );+ }++ public:+ explicit UnaryExpr( LhsT lhs )+ : ITransientExpression{ false, static_cast<bool>(lhs) },+ m_lhs( lhs )+ {}+ };++ // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)+ template<typename LhsT, typename RhsT>+ auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); }+ template<typename T>+ auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }+ template<typename T>+ auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }+ template<typename T>+ auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }+ template<typename T>+ auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }++ template<typename LhsT, typename RhsT>+ auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); }+ template<typename T>+ auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }+ template<typename T>+ auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }+ template<typename T>+ auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }+ template<typename T>+ auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }++ template<typename LhsT>+ class ExprLhs {+ LhsT m_lhs;+ public:+ explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}++ template<typename RhsT>+ auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {+ return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs };+ }+ auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const {+ return { m_lhs == rhs, m_lhs, "==", rhs };+ }++ template<typename RhsT>+ auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {+ return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs };+ }+ auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const {+ return { m_lhs != rhs, m_lhs, "!=", rhs };+ }++ template<typename RhsT>+ auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {+ return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs };+ }+ template<typename RhsT>+ auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {+ return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs };+ }+ template<typename RhsT>+ auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {+ return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs };+ }+ template<typename RhsT>+ auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {+ return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };+ }+ template <typename RhsT>+ auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {+ return { static_cast<bool>(m_lhs | rhs), m_lhs, "|", rhs };+ }+ template <typename RhsT>+ auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {+ return { static_cast<bool>(m_lhs & rhs), m_lhs, "&", rhs };+ }+ template <typename RhsT>+ auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {+ return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^", rhs };+ }++ template<typename RhsT>+ auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {+ static_assert(always_false<RhsT>::value,+ "operator&& is not supported inside assertions, "+ "wrap the expression inside parentheses, or decompose it");+ }++ template<typename RhsT>+ auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {+ static_assert(always_false<RhsT>::value,+ "operator|| is not supported inside assertions, "+ "wrap the expression inside parentheses, or decompose it");+ }++ auto makeUnaryExpr() const -> UnaryExpr<LhsT> {+ return UnaryExpr<LhsT>{ m_lhs };+ }+ };++ void handleExpression( ITransientExpression const& expr );++ template<typename T>+ void handleExpression( ExprLhs<T> const& expr ) {+ handleExpression( expr.makeUnaryExpr() );+ }++ struct Decomposer {+ template<typename T>+ auto operator <= ( T const& lhs ) -> ExprLhs<T const&> {+ return ExprLhs<T const&>{ lhs };+ }++ auto operator <=( bool value ) -> ExprLhs<bool> {+ return ExprLhs<bool>{ value };+ }+ };++} // end namespace Catch++#ifdef _MSC_VER+#pragma warning(pop)+#endif++// end catch_decomposer.h+// start catch_interfaces_capture.h++#include <string>+#include <chrono>++namespace Catch {++ class AssertionResult;+ struct AssertionInfo;+ struct SectionInfo;+ struct SectionEndInfo;+ struct MessageInfo;+ struct MessageBuilder;+ struct Counts;+ struct AssertionReaction;+ struct SourceLineInfo;++ struct ITransientExpression;+ struct IGeneratorTracker;++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+ struct BenchmarkInfo;+ template <typename Duration = std::chrono::duration<double, std::nano>>+ struct BenchmarkStats;+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++ struct IResultCapture {++ virtual ~IResultCapture();++ virtual bool sectionStarted( SectionInfo const& sectionInfo,+ Counts& assertions ) = 0;+ virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;+ virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;++ virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+ virtual void benchmarkPreparing( std::string const& name ) = 0;+ virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;+ virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;+ virtual void benchmarkFailed( std::string const& error ) = 0;+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++ virtual void pushScopedMessage( MessageInfo const& message ) = 0;+ virtual void popScopedMessage( MessageInfo const& message ) = 0;++ virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;++ virtual void handleFatalErrorCondition( StringRef message ) = 0;++ virtual void handleExpr+ ( AssertionInfo const& info,+ ITransientExpression const& expr,+ AssertionReaction& reaction ) = 0;+ virtual void handleMessage+ ( AssertionInfo const& info,+ ResultWas::OfType resultType,+ StringRef const& message,+ AssertionReaction& reaction ) = 0;+ virtual void handleUnexpectedExceptionNotThrown+ ( AssertionInfo const& info,+ AssertionReaction& reaction ) = 0;+ virtual void handleUnexpectedInflightException+ ( AssertionInfo const& info,+ std::string const& message,+ AssertionReaction& reaction ) = 0;+ virtual void handleIncomplete+ ( AssertionInfo const& info ) = 0;+ virtual void handleNonExpr+ ( AssertionInfo const &info,+ ResultWas::OfType resultType,+ AssertionReaction &reaction ) = 0;++ virtual bool lastAssertionPassed() = 0;+ virtual void assertionPassed() = 0;++ // Deprecated, do not use:+ virtual std::string getCurrentTestName() const = 0;+ virtual const AssertionResult* getLastResult() const = 0;+ virtual void exceptionEarlyReported() = 0;+ };++ IResultCapture& getResultCapture();+}++// end catch_interfaces_capture.h+namespace Catch {++ struct TestFailureException{};+ struct AssertionResultData;+ struct IResultCapture;+ class RunContext;++ class LazyExpression {+ friend class AssertionHandler;+ friend struct AssertionStats;+ friend class RunContext;++ ITransientExpression const* m_transientExpression = nullptr;+ bool m_isNegated;+ public:+ LazyExpression( bool isNegated );+ LazyExpression( LazyExpression const& other );+ LazyExpression& operator = ( LazyExpression const& ) = delete;++ explicit operator bool() const;++ friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;+ };++ struct AssertionReaction {+ bool shouldDebugBreak = false;+ bool shouldThrow = false;+ };++ class AssertionHandler {+ AssertionInfo m_assertionInfo;+ AssertionReaction m_reaction;+ bool m_completed = false;+ IResultCapture& m_resultCapture;++ public:+ AssertionHandler+ ( StringRef const& macroName,+ SourceLineInfo const& lineInfo,+ StringRef capturedExpression,+ ResultDisposition::Flags resultDisposition );+ ~AssertionHandler() {+ if ( !m_completed ) {+ m_resultCapture.handleIncomplete( m_assertionInfo );+ }+ }++ template<typename T>+ void handleExpr( ExprLhs<T> const& expr ) {+ handleExpr( expr.makeUnaryExpr() );+ }+ void handleExpr( ITransientExpression const& expr );++ void handleMessage(ResultWas::OfType resultType, StringRef const& message);++ void handleExceptionThrownAsExpected();+ void handleUnexpectedExceptionNotThrown();+ void handleExceptionNotThrownAsExpected();+ void handleThrowingCallSkipped();+ void handleUnexpectedInflightException();++ void complete();+ void setCompleted();++ // query+ auto allowThrows() const -> bool;+ };++ void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString );++} // namespace Catch++// end catch_assertionhandler.h+// start catch_message.h++#include <string>+#include <vector>++namespace Catch {++ struct MessageInfo {+ MessageInfo( StringRef const& _macroName,+ SourceLineInfo const& _lineInfo,+ ResultWas::OfType _type );++ StringRef macroName;+ std::string message;+ SourceLineInfo lineInfo;+ ResultWas::OfType type;+ unsigned int sequence;++ bool operator == ( MessageInfo const& other ) const;+ bool operator < ( MessageInfo const& other ) const;+ private:+ static unsigned int globalCount;+ };++ struct MessageStream {++ template<typename T>+ MessageStream& operator << ( T const& value ) {+ m_stream << value;+ return *this;+ }++ ReusableStringStream m_stream;+ };++ struct MessageBuilder : MessageStream {+ MessageBuilder( StringRef const& macroName,+ SourceLineInfo const& lineInfo,+ ResultWas::OfType type );++ template<typename T>+ MessageBuilder& operator << ( T const& value ) {+ m_stream << value;+ return *this;+ }++ MessageInfo m_info;+ };++ class ScopedMessage {+ public:+ explicit ScopedMessage( MessageBuilder const& builder );+ ScopedMessage( ScopedMessage& duplicate ) = delete;+ ScopedMessage( ScopedMessage&& old );+ ~ScopedMessage();++ MessageInfo m_info;+ bool m_moved;+ };++ class Capturer {+ std::vector<MessageInfo> m_messages;+ IResultCapture& m_resultCapture = getResultCapture();+ size_t m_captured = 0;+ public:+ Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );+ ~Capturer();++ void captureValue( size_t index, std::string const& value );++ template<typename T>+ void captureValues( size_t index, T const& value ) {+ captureValue( index, Catch::Detail::stringify( value ) );+ }++ template<typename T, typename... Ts>+ void captureValues( size_t index, T const& value, Ts const&... values ) {+ captureValue( index, Catch::Detail::stringify(value) );+ captureValues( index+1, values... );+ }+ };++} // end namespace Catch++// end catch_message.h+#if !defined(CATCH_CONFIG_DISABLE)++#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)+ #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__+#else+ #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"+#endif++#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)++///////////////////////////////////////////////////////////////////////////////+// Another way to speed-up compilation is to omit local try-catch for REQUIRE*+// macros.+#define INTERNAL_CATCH_TRY+#define INTERNAL_CATCH_CATCH( capturer )++#else // CATCH_CONFIG_FAST_COMPILE++#define INTERNAL_CATCH_TRY try+#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); }++#endif++#define INTERNAL_CATCH_REACT( handler ) handler.complete();++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \+ do { \+ CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \+ INTERNAL_CATCH_TRY { \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \+ catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \+ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \+ } while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) )++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \+ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \+ if( Catch::getResultCapture().lastAssertionPassed() )++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \+ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \+ if( !Catch::getResultCapture().lastAssertionPassed() )++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \+ do { \+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \+ try { \+ static_cast<void>(__VA_ARGS__); \+ catchAssertionHandler.handleExceptionNotThrownAsExpected(); \+ } \+ catch( ... ) { \+ catchAssertionHandler.handleUnexpectedInflightException(); \+ } \+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \+ } while( false )++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \+ do { \+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \+ if( catchAssertionHandler.allowThrows() ) \+ try { \+ static_cast<void>(__VA_ARGS__); \+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \+ } \+ catch( ... ) { \+ catchAssertionHandler.handleExceptionThrownAsExpected(); \+ } \+ else \+ catchAssertionHandler.handleThrowingCallSkipped(); \+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \+ } while( false )++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \+ do { \+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \+ if( catchAssertionHandler.allowThrows() ) \+ try { \+ static_cast<void>(expr); \+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \+ } \+ catch( exceptionType const& ) { \+ catchAssertionHandler.handleExceptionThrownAsExpected(); \+ } \+ catch( ... ) { \+ catchAssertionHandler.handleUnexpectedInflightException(); \+ } \+ else \+ catchAssertionHandler.handleThrowingCallSkipped(); \+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \+ } while( false )++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \+ do { \+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \+ catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \+ } while( false )++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \+ auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \+ varName.captureValues( 0, __VA_ARGS__ )++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_INFO( macroName, log ) \+ Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \+ Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )++///////////////////////////////////////////////////////////////////////////////+// Although this is matcher-based, it can be used with just a string+#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \+ do { \+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \+ if( catchAssertionHandler.allowThrows() ) \+ try { \+ static_cast<void>(__VA_ARGS__); \+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \+ } \+ catch( ... ) { \+ Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \+ } \+ else \+ catchAssertionHandler.handleThrowingCallSkipped(); \+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \+ } while( false )++#endif // CATCH_CONFIG_DISABLE++// end catch_capture.hpp+// start catch_section.h++// start catch_section_info.h++// start catch_totals.h++#include <cstddef>++namespace Catch {++ struct Counts {+ Counts operator - ( Counts const& other ) const;+ Counts& operator += ( Counts const& other );++ std::size_t total() const;+ bool allPassed() const;+ bool allOk() const;++ std::size_t passed = 0;+ std::size_t failed = 0;+ std::size_t failedButOk = 0;+ };++ struct Totals {++ Totals operator - ( Totals const& other ) const;+ Totals& operator += ( Totals const& other );++ Totals delta( Totals const& prevTotals ) const;++ int error = 0;+ Counts assertions;+ Counts testCases;+ };+}++// end catch_totals.h+#include <string>++namespace Catch {++ struct SectionInfo {+ SectionInfo+ ( SourceLineInfo const& _lineInfo,+ std::string const& _name );++ // Deprecated+ SectionInfo+ ( SourceLineInfo const& _lineInfo,+ std::string const& _name,+ std::string const& ) : SectionInfo( _lineInfo, _name ) {}++ std::string name;+ std::string description; // !Deprecated: this will always be empty+ SourceLineInfo lineInfo;+ };++ struct SectionEndInfo {+ SectionInfo sectionInfo;+ Counts prevAssertions;+ double durationInSeconds;+ };++} // end namespace Catch++// end catch_section_info.h+// start catch_timer.h++#include <cstdint>++namespace Catch {++ auto getCurrentNanosecondsSinceEpoch() -> uint64_t;+ auto getEstimatedClockResolution() -> uint64_t;++ class Timer {+ uint64_t m_nanoseconds = 0;+ public:+ void start();+ auto getElapsedNanoseconds() const -> uint64_t;+ auto getElapsedMicroseconds() const -> uint64_t;+ auto getElapsedMilliseconds() const -> unsigned int;+ auto getElapsedSeconds() const -> double;+ };++} // namespace Catch++// end catch_timer.h+#include <string>++namespace Catch {++ class Section : NonCopyable {+ public:+ Section( SectionInfo const& info );+ ~Section();++ // This indicates whether the section should be executed or not+ explicit operator bool() const;++ private:+ SectionInfo m_info;++ std::string m_name;+ Counts m_assertions;+ bool m_sectionIncluded;+ Timer m_timer;+ };++} // end namespace Catch++#define INTERNAL_CATCH_SECTION( ... ) \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \+ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION++#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \+ if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION++// end catch_section.h+// start catch_interfaces_exception.h++// start catch_interfaces_registry_hub.h++#include <string>+#include <memory>++namespace Catch {++ class TestCase;+ struct ITestCaseRegistry;+ struct IExceptionTranslatorRegistry;+ struct IExceptionTranslator;+ struct IReporterRegistry;+ struct IReporterFactory;+ struct ITagAliasRegistry;+ struct IMutableEnumValuesRegistry;++ class StartupExceptionRegistry;++ using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;++ struct IRegistryHub {+ virtual ~IRegistryHub();++ virtual IReporterRegistry const& getReporterRegistry() const = 0;+ virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;+ virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;+ virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;++ virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;+ };++ struct IMutableRegistryHub {+ virtual ~IMutableRegistryHub();+ virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0;+ virtual void registerListener( IReporterFactoryPtr const& factory ) = 0;+ virtual void registerTest( TestCase const& testInfo ) = 0;+ virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;+ virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;+ virtual void registerStartupException() noexcept = 0;+ virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;+ };++ IRegistryHub const& getRegistryHub();+ IMutableRegistryHub& getMutableRegistryHub();+ void cleanUp();+ std::string translateActiveException();++}++// end catch_interfaces_registry_hub.h+#if defined(CATCH_CONFIG_DISABLE)+ #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \+ static std::string translatorName( signature )+#endif++#include <exception>+#include <string>+#include <vector>++namespace Catch {+ using exceptionTranslateFunction = std::string(*)();++ struct IExceptionTranslator;+ using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>;++ struct IExceptionTranslator {+ virtual ~IExceptionTranslator();+ virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;+ };++ struct IExceptionTranslatorRegistry {+ virtual ~IExceptionTranslatorRegistry();++ virtual std::string translateActiveException() const = 0;+ };++ class ExceptionTranslatorRegistrar {+ template<typename T>+ class ExceptionTranslator : public IExceptionTranslator {+ public:++ ExceptionTranslator( std::string(*translateFunction)( T& ) )+ : m_translateFunction( translateFunction )+ {}++ std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+ return "";+#else+ try {+ if( it == itEnd )+ std::rethrow_exception(std::current_exception());+ else+ return (*it)->translate( it+1, itEnd );+ }+ catch( T& ex ) {+ return m_translateFunction( ex );+ }+#endif+ }++ protected:+ std::string(*m_translateFunction)( T& );+ };++ public:+ template<typename T>+ ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {+ getMutableRegistryHub().registerTranslator+ ( new ExceptionTranslator<T>( translateFunction ) );+ }+ };+}++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \+ static std::string translatorName( signature ); \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \+ static std::string translatorName( signature )++#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )++// end catch_interfaces_exception.h+// start catch_approx.h++#include <type_traits>++namespace Catch {+namespace Detail {++ class Approx {+ private:+ bool equalityComparisonImpl(double other) const;+ // Validates the new margin (margin >= 0)+ // out-of-line to avoid including stdexcept in the header+ void setMargin(double margin);+ // Validates the new epsilon (0 < epsilon < 1)+ // out-of-line to avoid including stdexcept in the header+ void setEpsilon(double epsilon);++ public:+ explicit Approx ( double value );++ static Approx custom();++ Approx operator-() const;++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ Approx operator()( T const& value ) {+ Approx approx( static_cast<double>(value) );+ approx.m_epsilon = m_epsilon;+ approx.m_margin = m_margin;+ approx.m_scale = m_scale;+ return approx;+ }++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ explicit Approx( T const& value ): Approx(static_cast<double>(value))+ {}++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ friend bool operator == ( const T& lhs, Approx const& rhs ) {+ auto lhs_v = static_cast<double>(lhs);+ return rhs.equalityComparisonImpl(lhs_v);+ }++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ friend bool operator == ( Approx const& lhs, const T& rhs ) {+ return operator==( rhs, lhs );+ }++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ friend bool operator != ( T const& lhs, Approx const& rhs ) {+ return !operator==( lhs, rhs );+ }++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ friend bool operator != ( Approx const& lhs, T const& rhs ) {+ return !operator==( rhs, lhs );+ }++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ friend bool operator <= ( T const& lhs, Approx const& rhs ) {+ return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;+ }++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ friend bool operator <= ( Approx const& lhs, T const& rhs ) {+ return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;+ }++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ friend bool operator >= ( T const& lhs, Approx const& rhs ) {+ return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;+ }++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ friend bool operator >= ( Approx const& lhs, T const& rhs ) {+ return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;+ }++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ Approx& epsilon( T const& newEpsilon ) {+ double epsilonAsDouble = static_cast<double>(newEpsilon);+ setEpsilon(epsilonAsDouble);+ return *this;+ }++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ Approx& margin( T const& newMargin ) {+ double marginAsDouble = static_cast<double>(newMargin);+ setMargin(marginAsDouble);+ return *this;+ }++ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ Approx& scale( T const& newScale ) {+ m_scale = static_cast<double>(newScale);+ return *this;+ }++ std::string toString() const;++ private:+ double m_epsilon;+ double m_margin;+ double m_scale;+ double m_value;+ };+} // end namespace Detail++namespace literals {+ Detail::Approx operator "" _a(long double val);+ Detail::Approx operator "" _a(unsigned long long val);+} // end namespace literals++template<>+struct StringMaker<Catch::Detail::Approx> {+ static std::string convert(Catch::Detail::Approx const& value);+};++} // end namespace Catch++// end catch_approx.h+// start catch_string_manip.h++#include <string>+#include <iosfwd>+#include <vector>++namespace Catch {++ bool startsWith( std::string const& s, std::string const& prefix );+ bool startsWith( std::string const& s, char prefix );+ bool endsWith( std::string const& s, std::string const& suffix );+ bool endsWith( std::string const& s, char suffix );+ bool contains( std::string const& s, std::string const& infix );+ void toLowerInPlace( std::string& s );+ std::string toLower( std::string const& s );+ //! Returns a new string without whitespace at the start/end+ std::string trim( std::string const& str );+ //! Returns a substring of the original ref without whitespace. Beware lifetimes!+ StringRef trim(StringRef ref);++ // !!! Be aware, returns refs into original string - make sure original string outlives them+ std::vector<StringRef> splitStringRef( StringRef str, char delimiter );+ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );++ struct pluralise {+ pluralise( std::size_t count, std::string const& label );++ friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );++ std::size_t m_count;+ std::string m_label;+ };+}++// end catch_string_manip.h+#ifndef CATCH_CONFIG_DISABLE_MATCHERS+// start catch_capture_matchers.h++// start catch_matchers.h++#include <string>+#include <vector>++namespace Catch {+namespace Matchers {+ namespace Impl {++ template<typename ArgT> struct MatchAllOf;+ template<typename ArgT> struct MatchAnyOf;+ template<typename ArgT> struct MatchNotOf;++ class MatcherUntypedBase {+ public:+ MatcherUntypedBase() = default;+ MatcherUntypedBase ( MatcherUntypedBase const& ) = default;+ MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete;+ std::string toString() const;++ protected:+ virtual ~MatcherUntypedBase();+ virtual std::string describe() const = 0;+ mutable std::string m_cachedToString;+ };++#ifdef __clang__+# pragma clang diagnostic push+# pragma clang diagnostic ignored "-Wnon-virtual-dtor"+#endif++ template<typename ObjectT>+ struct MatcherMethod {+ virtual bool match( ObjectT const& arg ) const = 0;+ };++#if defined(__OBJC__)+ // Hack to fix Catch GH issue #1661. Could use id for generic Object support.+ // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation+ template<>+ struct MatcherMethod<NSString*> {+ virtual bool match( NSString* arg ) const = 0;+ };+#endif++#ifdef __clang__+# pragma clang diagnostic pop+#endif++ template<typename T>+ struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {++ MatchAllOf<T> operator && ( MatcherBase const& other ) const;+ MatchAnyOf<T> operator || ( MatcherBase const& other ) const;+ MatchNotOf<T> operator ! () const;+ };++ template<typename ArgT>+ struct MatchAllOf : MatcherBase<ArgT> {+ bool match( ArgT const& arg ) const override {+ for( auto matcher : m_matchers ) {+ if (!matcher->match(arg))+ return false;+ }+ return true;+ }+ std::string describe() const override {+ std::string description;+ description.reserve( 4 + m_matchers.size()*32 );+ description += "( ";+ bool first = true;+ for( auto matcher : m_matchers ) {+ if( first )+ first = false;+ else+ description += " and ";+ description += matcher->toString();+ }+ description += " )";+ return description;+ }++ MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) {+ auto copy(*this);+ copy.m_matchers.push_back( &other );+ return copy;+ }++ std::vector<MatcherBase<ArgT> const*> m_matchers;+ };+ template<typename ArgT>+ struct MatchAnyOf : MatcherBase<ArgT> {++ bool match( ArgT const& arg ) const override {+ for( auto matcher : m_matchers ) {+ if (matcher->match(arg))+ return true;+ }+ return false;+ }+ std::string describe() const override {+ std::string description;+ description.reserve( 4 + m_matchers.size()*32 );+ description += "( ";+ bool first = true;+ for( auto matcher : m_matchers ) {+ if( first )+ first = false;+ else+ description += " or ";+ description += matcher->toString();+ }+ description += " )";+ return description;+ }++ MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) {+ auto copy(*this);+ copy.m_matchers.push_back( &other );+ return copy;+ }++ std::vector<MatcherBase<ArgT> const*> m_matchers;+ };++ template<typename ArgT>+ struct MatchNotOf : MatcherBase<ArgT> {++ MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}++ bool match( ArgT const& arg ) const override {+ return !m_underlyingMatcher.match( arg );+ }++ std::string describe() const override {+ return "not " + m_underlyingMatcher.toString();+ }+ MatcherBase<ArgT> const& m_underlyingMatcher;+ };++ template<typename T>+ MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const {+ return MatchAllOf<T>() && *this && other;+ }+ template<typename T>+ MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const {+ return MatchAnyOf<T>() || *this || other;+ }+ template<typename T>+ MatchNotOf<T> MatcherBase<T>::operator ! () const {+ return MatchNotOf<T>( *this );+ }++ } // namespace Impl++} // namespace Matchers++using namespace Matchers;+using Matchers::Impl::MatcherBase;++} // namespace Catch++// end catch_matchers.h+// start catch_matchers_exception.hpp++namespace Catch {+namespace Matchers {+namespace Exception {++class ExceptionMessageMatcher : public MatcherBase<std::exception> {+ std::string m_message;+public:++ ExceptionMessageMatcher(std::string const& message):+ m_message(message)+ {}++ bool match(std::exception const& ex) const override;++ std::string describe() const override;+};++} // namespace Exception++Exception::ExceptionMessageMatcher Message(std::string const& message);++} // namespace Matchers+} // namespace Catch++// end catch_matchers_exception.hpp+// start catch_matchers_floating.h++namespace Catch {+namespace Matchers {++ namespace Floating {++ enum class FloatingPointKind : uint8_t;++ struct WithinAbsMatcher : MatcherBase<double> {+ WithinAbsMatcher(double target, double margin);+ bool match(double const& matchee) const override;+ std::string describe() const override;+ private:+ double m_target;+ double m_margin;+ };++ struct WithinUlpsMatcher : MatcherBase<double> {+ WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType);+ bool match(double const& matchee) const override;+ std::string describe() const override;+ private:+ double m_target;+ uint64_t m_ulps;+ FloatingPointKind m_type;+ };++ // Given IEEE-754 format for floats and doubles, we can assume+ // that float -> double promotion is lossless. Given this, we can+ // assume that if we do the standard relative comparison of+ // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get+ // the same result if we do this for floats, as if we do this for+ // doubles that were promoted from floats.+ struct WithinRelMatcher : MatcherBase<double> {+ WithinRelMatcher(double target, double epsilon);+ bool match(double const& matchee) const override;+ std::string describe() const override;+ private:+ double m_target;+ double m_epsilon;+ };++ } // namespace Floating++ // The following functions create the actual matcher objects.+ // This allows the types to be inferred+ Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);+ Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);+ Floating::WithinAbsMatcher WithinAbs(double target, double margin);+ Floating::WithinRelMatcher WithinRel(double target, double eps);+ // defaults epsilon to 100*numeric_limits<double>::epsilon()+ Floating::WithinRelMatcher WithinRel(double target);+ Floating::WithinRelMatcher WithinRel(float target, float eps);+ // defaults epsilon to 100*numeric_limits<float>::epsilon()+ Floating::WithinRelMatcher WithinRel(float target);++} // namespace Matchers+} // namespace Catch++// end catch_matchers_floating.h+// start catch_matchers_generic.hpp++#include <functional>+#include <string>++namespace Catch {+namespace Matchers {+namespace Generic {++namespace Detail {+ std::string finalizeDescription(const std::string& desc);+}++template <typename T>+class PredicateMatcher : public MatcherBase<T> {+ std::function<bool(T const&)> m_predicate;+ std::string m_description;+public:++ PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr)+ :m_predicate(std::move(elem)),+ m_description(Detail::finalizeDescription(descr))+ {}++ bool match( T const& item ) const override {+ return m_predicate(item);+ }++ std::string describe() const override {+ return m_description;+ }+};++} // namespace Generic++ // The following functions create the actual matcher objects.+ // The user has to explicitly specify type to the function, because+ // inferring std::function<bool(T const&)> is hard (but possible) and+ // requires a lot of TMP.+ template<typename T>+ Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") {+ return Generic::PredicateMatcher<T>(predicate, description);+ }++} // namespace Matchers+} // namespace Catch++// end catch_matchers_generic.hpp+// start catch_matchers_string.h++#include <string>++namespace Catch {+namespace Matchers {++ namespace StdString {++ struct CasedString+ {+ CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity );+ std::string adjustString( std::string const& str ) const;+ std::string caseSensitivitySuffix() const;++ CaseSensitive::Choice m_caseSensitivity;+ std::string m_str;+ };++ struct StringMatcherBase : MatcherBase<std::string> {+ StringMatcherBase( std::string const& operation, CasedString const& comparator );+ std::string describe() const override;++ CasedString m_comparator;+ std::string m_operation;+ };++ struct EqualsMatcher : StringMatcherBase {+ EqualsMatcher( CasedString const& comparator );+ bool match( std::string const& source ) const override;+ };+ struct ContainsMatcher : StringMatcherBase {+ ContainsMatcher( CasedString const& comparator );+ bool match( std::string const& source ) const override;+ };+ struct StartsWithMatcher : StringMatcherBase {+ StartsWithMatcher( CasedString const& comparator );+ bool match( std::string const& source ) const override;+ };+ struct EndsWithMatcher : StringMatcherBase {+ EndsWithMatcher( CasedString const& comparator );+ bool match( std::string const& source ) const override;+ };++ struct RegexMatcher : MatcherBase<std::string> {+ RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity );+ bool match( std::string const& matchee ) const override;+ std::string describe() const override;++ private:+ std::string m_regex;+ CaseSensitive::Choice m_caseSensitivity;+ };++ } // namespace StdString++ // The following functions create the actual matcher objects.+ // This allows the types to be inferred++ StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );+ StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );+ StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );+ StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );+ StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );++} // namespace Matchers+} // namespace Catch++// end catch_matchers_string.h+// start catch_matchers_vector.h++#include <algorithm>++namespace Catch {+namespace Matchers {++ namespace Vector {+ template<typename T, typename Alloc>+ struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> {++ ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}++ bool match(std::vector<T, Alloc> const &v) const override {+ for (auto const& el : v) {+ if (el == m_comparator) {+ return true;+ }+ }+ return false;+ }++ std::string describe() const override {+ return "Contains: " + ::Catch::Detail::stringify( m_comparator );+ }++ T const& m_comparator;+ };++ template<typename T, typename AllocComp, typename AllocMatch>+ struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> {++ ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}++ bool match(std::vector<T, AllocMatch> const &v) const override {+ // !TBD: see note in EqualsMatcher+ if (m_comparator.size() > v.size())+ return false;+ for (auto const& comparator : m_comparator) {+ auto present = false;+ for (const auto& el : v) {+ if (el == comparator) {+ present = true;+ break;+ }+ }+ if (!present) {+ return false;+ }+ }+ return true;+ }+ std::string describe() const override {+ return "Contains: " + ::Catch::Detail::stringify( m_comparator );+ }++ std::vector<T, AllocComp> const& m_comparator;+ };++ template<typename T, typename AllocComp, typename AllocMatch>+ struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {++ EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}++ bool match(std::vector<T, AllocMatch> const &v) const override {+ // !TBD: This currently works if all elements can be compared using !=+ // - a more general approach would be via a compare template that defaults+ // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc+ // - then just call that directly+ if (m_comparator.size() != v.size())+ return false;+ for (std::size_t i = 0; i < v.size(); ++i)+ if (m_comparator[i] != v[i])+ return false;+ return true;+ }+ std::string describe() const override {+ return "Equals: " + ::Catch::Detail::stringify( m_comparator );+ }+ std::vector<T, AllocComp> const& m_comparator;+ };++ template<typename T, typename AllocComp, typename AllocMatch>+ struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> {++ ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {}++ bool match(std::vector<T, AllocMatch> const &v) const override {+ if (m_comparator.size() != v.size())+ return false;+ for (std::size_t i = 0; i < v.size(); ++i)+ if (m_comparator[i] != approx(v[i]))+ return false;+ return true;+ }+ std::string describe() const override {+ return "is approx: " + ::Catch::Detail::stringify( m_comparator );+ }+ template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ ApproxMatcher& epsilon( T const& newEpsilon ) {+ approx.epsilon(newEpsilon);+ return *this;+ }+ template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ ApproxMatcher& margin( T const& newMargin ) {+ approx.margin(newMargin);+ return *this;+ }+ template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>+ ApproxMatcher& scale( T const& newScale ) {+ approx.scale(newScale);+ return *this;+ }++ std::vector<T, AllocComp> const& m_comparator;+ mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom();+ };++ template<typename T, typename AllocComp, typename AllocMatch>+ struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {+ UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {}+ bool match(std::vector<T, AllocMatch> const& vec) const override {+ if (m_target.size() != vec.size()) {+ return false;+ }+ return std::is_permutation(m_target.begin(), m_target.end(), vec.begin());+ }++ std::string describe() const override {+ return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);+ }+ private:+ std::vector<T, AllocComp> const& m_target;+ };++ } // namespace Vector++ // The following functions create the actual matcher objects.+ // This allows the types to be inferred++ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>+ Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {+ return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator );+ }++ template<typename T, typename Alloc = std::allocator<T>>+ Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {+ return Vector::ContainsElementMatcher<T, Alloc>( comparator );+ }++ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>+ Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {+ return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator );+ }++ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>+ Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {+ return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator );+ }++ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>+ Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {+ return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target );+ }++} // namespace Matchers+} // namespace Catch++// end catch_matchers_vector.h+namespace Catch {++ template<typename ArgT, typename MatcherT>+ class MatchExpr : public ITransientExpression {+ ArgT const& m_arg;+ MatcherT m_matcher;+ StringRef m_matcherString;+ public:+ MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )+ : ITransientExpression{ true, matcher.match( arg ) },+ m_arg( arg ),+ m_matcher( matcher ),+ m_matcherString( matcherString )+ {}++ void streamReconstructedExpression( std::ostream &os ) const override {+ auto matcherAsString = m_matcher.toString();+ os << Catch::Detail::stringify( m_arg ) << ' ';+ if( matcherAsString == Detail::unprintableString )+ os << m_matcherString;+ else+ os << matcherAsString;+ }+ };++ using StringMatcher = Matchers::Impl::MatcherBase<std::string>;++ void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString );++ template<typename ArgT, typename MatcherT>+ auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> {+ return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );+ }++} // namespace Catch++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \+ do { \+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \+ INTERNAL_CATCH_TRY { \+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \+ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \+ } while( false )++///////////////////////////////////////////////////////////////////////////////+#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \+ do { \+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \+ if( catchAssertionHandler.allowThrows() ) \+ try { \+ static_cast<void>(__VA_ARGS__ ); \+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \+ } \+ catch( exceptionType const& ex ) { \+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \+ } \+ catch( ... ) { \+ catchAssertionHandler.handleUnexpectedInflightException(); \+ } \+ else \+ catchAssertionHandler.handleThrowingCallSkipped(); \+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \+ } while( false )++// end catch_capture_matchers.h+#endif+// start catch_generators.hpp++// start catch_interfaces_generatortracker.h+++#include <memory>++namespace Catch {++ namespace Generators {+ class GeneratorUntypedBase {+ public:+ GeneratorUntypedBase() = default;+ virtual ~GeneratorUntypedBase();+ // Attempts to move the generator to the next element+ //+ // Returns true iff the move succeeded (and a valid element+ // can be retrieved).+ virtual bool next() = 0;+ };+ using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>;++ } // namespace Generators++ struct IGeneratorTracker {+ virtual ~IGeneratorTracker();+ virtual auto hasGenerator() const -> bool = 0;+ virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;+ virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;+ };++} // namespace Catch++// end catch_interfaces_generatortracker.h+// start catch_enforce.h++#include <exception>++namespace Catch {+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+ template <typename Ex>+ [[noreturn]]+ void throw_exception(Ex const& e) {+ throw e;+ }+#else // ^^ Exceptions are enabled // Exceptions are disabled vv+ [[noreturn]]+ void throw_exception(std::exception const& e);+#endif++ [[noreturn]]+ void throw_logic_error(std::string const& msg);+ [[noreturn]]+ void throw_domain_error(std::string const& msg);+ [[noreturn]]+ void throw_runtime_error(std::string const& msg);++} // namespace Catch;++#define CATCH_MAKE_MSG(...) \+ (Catch::ReusableStringStream() << __VA_ARGS__).str()++#define CATCH_INTERNAL_ERROR(...) \+ Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__))++#define CATCH_ERROR(...) \+ Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))++#define CATCH_RUNTIME_ERROR(...) \+ Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))++#define CATCH_ENFORCE( condition, ... ) \+ do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)++// end catch_enforce.h+#include <memory>+#include <vector>+#include <cassert>++#include <utility>+#include <exception>++namespace Catch {++class GeneratorException : public std::exception {+ const char* const m_msg = "";++public:+ GeneratorException(const char* msg):+ m_msg(msg)+ {}++ const char* what() const noexcept override final;+};++namespace Generators {++ // !TBD move this into its own location?+ namespace pf{+ template<typename T, typename... Args>+ std::unique_ptr<T> make_unique( Args&&... args ) {+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));+ }+ }++ template<typename T>+ struct IGenerator : GeneratorUntypedBase {+ virtual ~IGenerator() = default;++ // Returns the current element of the generator+ //+ // \Precondition The generator is either freshly constructed,+ // or the last call to `next()` returned true+ virtual T const& get() const = 0;+ using type = T;+ };++ template<typename T>+ class SingleValueGenerator final : public IGenerator<T> {+ T m_value;+ public:+ SingleValueGenerator(T&& value) : m_value(std::move(value)) {}++ T const& get() const override {+ return m_value;+ }+ bool next() override {+ return false;+ }+ };++ template<typename T>+ class FixedValuesGenerator final : public IGenerator<T> {+ static_assert(!std::is_same<T, bool>::value,+ "FixedValuesGenerator does not support bools because of std::vector<bool>"+ "specialization, use SingleValue Generator instead.");+ std::vector<T> m_values;+ size_t m_idx = 0;+ public:+ FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}++ T const& get() const override {+ return m_values[m_idx];+ }+ bool next() override {+ ++m_idx;+ return m_idx < m_values.size();+ }+ };++ template <typename T>+ class GeneratorWrapper final {+ std::unique_ptr<IGenerator<T>> m_generator;+ public:+ GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator):+ m_generator(std::move(generator))+ {}+ T const& get() const {+ return m_generator->get();+ }+ bool next() {+ return m_generator->next();+ }+ };++ template <typename T>+ GeneratorWrapper<T> value(T&& value) {+ return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));+ }+ template <typename T>+ GeneratorWrapper<T> values(std::initializer_list<T> values) {+ return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));+ }++ template<typename T>+ class Generators : public IGenerator<T> {+ std::vector<GeneratorWrapper<T>> m_generators;+ size_t m_current = 0;++ void populate(GeneratorWrapper<T>&& generator) {+ m_generators.emplace_back(std::move(generator));+ }+ void populate(T&& val) {+ m_generators.emplace_back(value(std::forward<T>(val)));+ }+ template<typename U>+ void populate(U&& val) {+ populate(T(std::forward<U>(val)));+ }+ template<typename U, typename... Gs>+ void populate(U&& valueOrGenerator, Gs &&... moreGenerators) {+ populate(std::forward<U>(valueOrGenerator));+ populate(std::forward<Gs>(moreGenerators)...);+ }++ public:+ template <typename... Gs>+ Generators(Gs &&... moreGenerators) {+ m_generators.reserve(sizeof...(Gs));+ populate(std::forward<Gs>(moreGenerators)...);+ }++ T const& get() const override {+ return m_generators[m_current].get();+ }++ bool next() override {+ if (m_current >= m_generators.size()) {+ return false;+ }+ const bool current_status = m_generators[m_current].next();+ if (!current_status) {+ ++m_current;+ }+ return m_current < m_generators.size();+ }+ };++ template<typename... Ts>+ GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) {+ return values<std::tuple<Ts...>>( tuples );+ }++ // Tag type to signal that a generator sequence should convert arguments to a specific type+ template <typename T>+ struct as {};++ template<typename T, typename... Gs>+ auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {+ return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);+ }+ template<typename T>+ auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {+ return Generators<T>(std::move(generator));+ }+ template<typename T, typename... Gs>+ auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> {+ return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );+ }+ template<typename T, typename U, typename... Gs>+ auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {+ return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );+ }++ auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;++ template<typename L>+ // Note: The type after -> is weird, because VS2015 cannot parse+ // the expression used in the typedef inside, when it is in+ // return type. Yeah.+ auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {+ using UnderlyingType = typename decltype(generatorExpression())::type;++ IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo );+ if (!tracker.hasGenerator()) {+ tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));+ }++ auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );+ return generator.get();+ }++} // namespace Generators+} // namespace Catch++#define GENERATE( ... ) \+ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \+ CATCH_INTERNAL_LINEINFO, \+ [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)+#define GENERATE_COPY( ... ) \+ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \+ CATCH_INTERNAL_LINEINFO, \+ [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)+#define GENERATE_REF( ... ) \+ Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \+ CATCH_INTERNAL_LINEINFO, \+ [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)++// end catch_generators.hpp+// start catch_generators_generic.hpp++namespace Catch {+namespace Generators {++ template <typename T>+ class TakeGenerator : public IGenerator<T> {+ GeneratorWrapper<T> m_generator;+ size_t m_returned = 0;+ size_t m_target;+ public:+ TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):+ m_generator(std::move(generator)),+ m_target(target)+ {+ assert(target != 0 && "Empty generators are not allowed");+ }+ T const& get() const override {+ return m_generator.get();+ }+ bool next() override {+ ++m_returned;+ if (m_returned >= m_target) {+ return false;+ }++ const auto success = m_generator.next();+ // If the underlying generator does not contain enough values+ // then we cut short as well+ if (!success) {+ m_returned = m_target;+ }+ return success;+ }+ };++ template <typename T>+ GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {+ return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));+ }++ template <typename T, typename Predicate>+ class FilterGenerator : public IGenerator<T> {+ GeneratorWrapper<T> m_generator;+ Predicate m_predicate;+ public:+ template <typename P = Predicate>+ FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):+ m_generator(std::move(generator)),+ m_predicate(std::forward<P>(pred))+ {+ if (!m_predicate(m_generator.get())) {+ // It might happen that there are no values that pass the+ // filter. In that case we throw an exception.+ auto has_initial_value = next();+ if (!has_initial_value) {+ Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));+ }+ }+ }++ T const& get() const override {+ return m_generator.get();+ }++ bool next() override {+ bool success = m_generator.next();+ if (!success) {+ return false;+ }+ while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);+ return success;+ }+ };++ template <typename T, typename Predicate>+ GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {+ return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));+ }++ template <typename T>+ class RepeatGenerator : public IGenerator<T> {+ static_assert(!std::is_same<T, bool>::value,+ "RepeatGenerator currently does not support bools"+ "because of std::vector<bool> specialization");+ GeneratorWrapper<T> m_generator;+ mutable std::vector<T> m_returned;+ size_t m_target_repeats;+ size_t m_current_repeat = 0;+ size_t m_repeat_index = 0;+ public:+ RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):+ m_generator(std::move(generator)),+ m_target_repeats(repeats)+ {+ assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");+ }++ T const& get() const override {+ if (m_current_repeat == 0) {+ m_returned.push_back(m_generator.get());+ return m_returned.back();+ }+ return m_returned[m_repeat_index];+ }++ bool next() override {+ // There are 2 basic cases:+ // 1) We are still reading the generator+ // 2) We are reading our own cache++ // In the first case, we need to poke the underlying generator.+ // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache+ if (m_current_repeat == 0) {+ const auto success = m_generator.next();+ if (!success) {+ ++m_current_repeat;+ }+ return m_current_repeat < m_target_repeats;+ }++ // In the second case, we need to move indices forward and check that we haven't run up against the end+ ++m_repeat_index;+ if (m_repeat_index == m_returned.size()) {+ m_repeat_index = 0;+ ++m_current_repeat;+ }+ return m_current_repeat < m_target_repeats;+ }+ };++ template <typename T>+ GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {+ return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));+ }++ template <typename T, typename U, typename Func>+ class MapGenerator : public IGenerator<T> {+ // TBD: provide static assert for mapping function, for friendly error message+ GeneratorWrapper<U> m_generator;+ Func m_function;+ // To avoid returning dangling reference, we have to save the values+ T m_cache;+ public:+ template <typename F2 = Func>+ MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :+ m_generator(std::move(generator)),+ m_function(std::forward<F2>(function)),+ m_cache(m_function(m_generator.get()))+ {}++ T const& get() const override {+ return m_cache;+ }+ bool next() override {+ const auto success = m_generator.next();+ if (success) {+ m_cache = m_function(m_generator.get());+ }+ return success;+ }+ };++ template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>+ GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {+ return GeneratorWrapper<T>(+ pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))+ );+ }++ template <typename T, typename U, typename Func>+ GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {+ return GeneratorWrapper<T>(+ pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))+ );+ }++ template <typename T>+ class ChunkGenerator final : public IGenerator<std::vector<T>> {+ std::vector<T> m_chunk;+ size_t m_chunk_size;+ GeneratorWrapper<T> m_generator;+ bool m_used_up = false;+ public:+ ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :+ m_chunk_size(size), m_generator(std::move(generator))+ {+ m_chunk.reserve(m_chunk_size);+ if (m_chunk_size != 0) {+ m_chunk.push_back(m_generator.get());+ for (size_t i = 1; i < m_chunk_size; ++i) {+ if (!m_generator.next()) {+ Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));+ }+ m_chunk.push_back(m_generator.get());+ }+ }+ }+ std::vector<T> const& get() const override {+ return m_chunk;+ }+ bool next() override {+ m_chunk.clear();+ for (size_t idx = 0; idx < m_chunk_size; ++idx) {+ if (!m_generator.next()) {+ return false;+ }+ m_chunk.push_back(m_generator.get());+ }+ return true;+ }+ };++ template <typename T>+ GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {+ return GeneratorWrapper<std::vector<T>>(+ pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))+ );+ }++} // namespace Generators+} // namespace Catch++// end catch_generators_generic.hpp+// start catch_generators_specific.hpp++// start catch_context.h++#include <memory>++namespace Catch {++ struct IResultCapture;+ struct IRunner;+ struct IConfig;+ struct IMutableContext;++ using IConfigPtr = std::shared_ptr<IConfig const>;++ struct IContext+ {+ virtual ~IContext();++ virtual IResultCapture* getResultCapture() = 0;+ virtual IRunner* getRunner() = 0;+ virtual IConfigPtr const& getConfig() const = 0;+ };++ struct IMutableContext : IContext+ {+ virtual ~IMutableContext();+ virtual void setResultCapture( IResultCapture* resultCapture ) = 0;+ virtual void setRunner( IRunner* runner ) = 0;+ virtual void setConfig( IConfigPtr const& config ) = 0;++ private:+ static IMutableContext *currentContext;+ friend IMutableContext& getCurrentMutableContext();+ friend void cleanUpContext();+ static void createContext();+ };++ inline IMutableContext& getCurrentMutableContext()+ {+ if( !IMutableContext::currentContext )+ IMutableContext::createContext();+ // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)+ return *IMutableContext::currentContext;+ }++ inline IContext& getCurrentContext()+ {+ return getCurrentMutableContext();+ }++ void cleanUpContext();++ class SimplePcg32;+ SimplePcg32& rng();+}++// end catch_context.h+// start catch_interfaces_config.h++// start catch_option.hpp++namespace Catch {++ // An optional type+ template<typename T>+ class Option {+ public:+ Option() : nullableValue( nullptr ) {}+ Option( T const& _value )+ : nullableValue( new( storage ) T( _value ) )+ {}+ Option( Option const& _other )+ : nullableValue( _other ? new( storage ) T( *_other ) : nullptr )+ {}++ ~Option() {+ reset();+ }++ Option& operator= ( Option const& _other ) {+ if( &_other != this ) {+ reset();+ if( _other )+ nullableValue = new( storage ) T( *_other );+ }+ return *this;+ }+ Option& operator = ( T const& _value ) {+ reset();+ nullableValue = new( storage ) T( _value );+ return *this;+ }++ void reset() {+ if( nullableValue )+ nullableValue->~T();+ nullableValue = nullptr;+ }++ T& operator*() { return *nullableValue; }+ T const& operator*() const { return *nullableValue; }+ T* operator->() { return nullableValue; }+ const T* operator->() const { return nullableValue; }++ T valueOr( T const& defaultValue ) const {+ return nullableValue ? *nullableValue : defaultValue;+ }++ bool some() const { return nullableValue != nullptr; }+ bool none() const { return nullableValue == nullptr; }++ bool operator !() const { return nullableValue == nullptr; }+ explicit operator bool() const {+ return some();+ }++ private:+ T *nullableValue;+ alignas(alignof(T)) char storage[sizeof(T)];+ };++} // end namespace Catch++// end catch_option.hpp+#include <chrono>+#include <iosfwd>+#include <string>+#include <vector>+#include <memory>++namespace Catch {++ enum class Verbosity {+ Quiet = 0,+ Normal,+ High+ };++ struct WarnAbout { enum What {+ Nothing = 0x00,+ NoAssertions = 0x01,+ NoTests = 0x02+ }; };++ struct ShowDurations { enum OrNot {+ DefaultForReporter,+ Always,+ Never+ }; };+ struct RunTests { enum InWhatOrder {+ InDeclarationOrder,+ InLexicographicalOrder,+ InRandomOrder+ }; };+ struct UseColour { enum YesOrNo {+ Auto,+ Yes,+ No+ }; };+ struct WaitForKeypress { enum When {+ Never,+ BeforeStart = 1,+ BeforeExit = 2,+ BeforeStartAndExit = BeforeStart | BeforeExit+ }; };++ class TestSpec;++ struct IConfig : NonCopyable {++ virtual ~IConfig();++ virtual bool allowThrows() const = 0;+ virtual std::ostream& stream() const = 0;+ virtual std::string name() const = 0;+ virtual bool includeSuccessfulResults() const = 0;+ virtual bool shouldDebugBreak() const = 0;+ virtual bool warnAboutMissingAssertions() const = 0;+ virtual bool warnAboutNoTests() const = 0;+ virtual int abortAfter() const = 0;+ virtual bool showInvisibles() const = 0;+ virtual ShowDurations::OrNot showDurations() const = 0;+ virtual double minDuration() const = 0;+ virtual TestSpec const& testSpec() const = 0;+ virtual bool hasTestFilters() const = 0;+ virtual std::vector<std::string> const& getTestsOrTags() const = 0;+ virtual RunTests::InWhatOrder runOrder() const = 0;+ virtual unsigned int rngSeed() const = 0;+ virtual UseColour::YesOrNo useColour() const = 0;+ virtual std::vector<std::string> const& getSectionsToRun() const = 0;+ virtual Verbosity verbosity() const = 0;++ virtual bool benchmarkNoAnalysis() const = 0;+ virtual int benchmarkSamples() const = 0;+ virtual double benchmarkConfidenceInterval() const = 0;+ virtual unsigned int benchmarkResamples() const = 0;+ virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;+ };++ using IConfigPtr = std::shared_ptr<IConfig const>;+}++// end catch_interfaces_config.h+// start catch_random_number_generator.h++#include <cstdint>++namespace Catch {++ // This is a simple implementation of C++11 Uniform Random Number+ // Generator. It does not provide all operators, because Catch2+ // does not use it, but it should behave as expected inside stdlib's+ // distributions.+ // The implementation is based on the PCG family (http://pcg-random.org)+ class SimplePcg32 {+ using state_type = std::uint64_t;+ public:+ using result_type = std::uint32_t;+ static constexpr result_type (min)() {+ return 0;+ }+ static constexpr result_type (max)() {+ return static_cast<result_type>(-1);+ }++ // Provide some default initial state for the default constructor+ SimplePcg32():SimplePcg32(0xed743cc4U) {}++ explicit SimplePcg32(result_type seed_);++ void seed(result_type seed_);+ void discard(uint64_t skip);++ result_type operator()();++ private:+ friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs);+ friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs);++ // In theory we also need operator<< and operator>>+ // In practice we do not use them, so we will skip them for now++ std::uint64_t m_state;+ // This part of the state determines which "stream" of the numbers+ // is chosen -- we take it as a constant for Catch2, so we only+ // need to deal with seeding the main state.+ // Picked by reading 8 bytes from `/dev/random` :-)+ static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL;+ };++} // end namespace Catch++// end catch_random_number_generator.h+#include <random>++namespace Catch {+namespace Generators {++template <typename Float>+class RandomFloatingGenerator final : public IGenerator<Float> {+ Catch::SimplePcg32& m_rng;+ std::uniform_real_distribution<Float> m_dist;+ Float m_current_number;+public:++ RandomFloatingGenerator(Float a, Float b):+ m_rng(rng()),+ m_dist(a, b) {+ static_cast<void>(next());+ }++ Float const& get() const override {+ return m_current_number;+ }+ bool next() override {+ m_current_number = m_dist(m_rng);+ return true;+ }+};++template <typename Integer>+class RandomIntegerGenerator final : public IGenerator<Integer> {+ Catch::SimplePcg32& m_rng;+ std::uniform_int_distribution<Integer> m_dist;+ Integer m_current_number;+public:++ RandomIntegerGenerator(Integer a, Integer b):+ m_rng(rng()),+ m_dist(a, b) {+ static_cast<void>(next());+ }++ Integer const& get() const override {+ return m_current_number;+ }+ bool next() override {+ m_current_number = m_dist(m_rng);+ return true;+ }+};++// TODO: Ideally this would be also constrained against the various char types,+// but I don't expect users to run into that in practice.+template <typename T>+typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,+GeneratorWrapper<T>>::type+random(T a, T b) {+ return GeneratorWrapper<T>(+ pf::make_unique<RandomIntegerGenerator<T>>(a, b)+ );+}++template <typename T>+typename std::enable_if<std::is_floating_point<T>::value,+GeneratorWrapper<T>>::type+random(T a, T b) {+ return GeneratorWrapper<T>(+ pf::make_unique<RandomFloatingGenerator<T>>(a, b)+ );+}++template <typename T>+class RangeGenerator final : public IGenerator<T> {+ T m_current;+ T m_end;+ T m_step;+ bool m_positive;++public:+ RangeGenerator(T const& start, T const& end, T const& step):+ m_current(start),+ m_end(end),+ m_step(step),+ m_positive(m_step > T(0))+ {+ assert(m_current != m_end && "Range start and end cannot be equal");+ assert(m_step != T(0) && "Step size cannot be zero");+ assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");+ }++ RangeGenerator(T const& start, T const& end):+ RangeGenerator(start, end, (start < end) ? T(1) : T(-1))+ {}++ T const& get() const override {+ return m_current;+ }++ bool next() override {+ m_current += m_step;+ return (m_positive) ? (m_current < m_end) : (m_current > m_end);+ }+};++template <typename T>+GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {+ static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");+ return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));+}++template <typename T>+GeneratorWrapper<T> range(T const& start, T const& end) {+ static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");+ return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));+}++template <typename T>+class IteratorGenerator final : public IGenerator<T> {+ static_assert(!std::is_same<T, bool>::value,+ "IteratorGenerator currently does not support bools"+ "because of std::vector<bool> specialization");++ std::vector<T> m_elems;+ size_t m_current = 0;+public:+ template <typename InputIterator, typename InputSentinel>+ IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {+ if (m_elems.empty()) {+ Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values"));+ }+ }++ T const& get() const override {+ return m_elems[m_current];+ }++ bool next() override {+ ++m_current;+ return m_current != m_elems.size();+ }+};++template <typename InputIterator,+ typename InputSentinel,+ typename ResultType = typename std::iterator_traits<InputIterator>::value_type>+GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {+ return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to));+}++template <typename Container,+ typename ResultType = typename Container::value_type>+GeneratorWrapper<ResultType> from_range(Container const& cnt) {+ return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end()));+}++} // namespace Generators+} // namespace Catch++// end catch_generators_specific.hpp++// These files are included here so the single_include script doesn't put them+// in the conditionally compiled sections+// start catch_test_case_info.h++#include <string>+#include <vector>+#include <memory>++#ifdef __clang__+#pragma clang diagnostic push+#pragma clang diagnostic ignored "-Wpadded"+#endif++namespace Catch {++ struct ITestInvoker;++ struct TestCaseInfo {+ enum SpecialProperties{+ None = 0,+ IsHidden = 1 << 1,+ ShouldFail = 1 << 2,+ MayFail = 1 << 3,+ Throws = 1 << 4,+ NonPortable = 1 << 5,+ Benchmark = 1 << 6+ };++ TestCaseInfo( std::string const& _name,+ std::string const& _className,+ std::string const& _description,+ std::vector<std::string> const& _tags,+ SourceLineInfo const& _lineInfo );++ friend void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags );++ bool isHidden() const;+ bool throws() const;+ bool okToFail() const;+ bool expectedToFail() const;++ std::string tagsAsString() const;++ std::string name;+ std::string className;+ std::string description;+ std::vector<std::string> tags;+ std::vector<std::string> lcaseTags;+ SourceLineInfo lineInfo;+ SpecialProperties properties;+ };++ class TestCase : public TestCaseInfo {+ public:++ TestCase( ITestInvoker* testCase, TestCaseInfo&& info );++ TestCase withName( std::string const& _newName ) const;++ void invoke() const;++ TestCaseInfo const& getTestCaseInfo() const;++ bool operator == ( TestCase const& other ) const;+ bool operator < ( TestCase const& other ) const;++ private:+ std::shared_ptr<ITestInvoker> test;+ };++ TestCase makeTestCase( ITestInvoker* testCase,+ std::string const& className,+ NameAndTags const& nameAndTags,+ SourceLineInfo const& lineInfo );+}++#ifdef __clang__+#pragma clang diagnostic pop+#endif++// end catch_test_case_info.h+// start catch_interfaces_runner.h++namespace Catch {++ struct IRunner {+ virtual ~IRunner();+ virtual bool aborting() const = 0;+ };+}++// end catch_interfaces_runner.h++#ifdef __OBJC__+// start catch_objc.hpp++#import <objc/runtime.h>++#include <string>++// NB. Any general catch headers included here must be included+// in catch.hpp first to make sure they are included by the single+// header for non obj-usage++///////////////////////////////////////////////////////////////////////////////+// This protocol is really only here for (self) documenting purposes, since+// all its methods are optional.+@protocol OcFixture++@optional++-(void) setUp;+-(void) tearDown;++@end++namespace Catch {++ class OcMethod : public ITestInvoker {++ public:+ OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}++ virtual void invoke() const {+ id obj = [[m_cls alloc] init];++ performOptionalSelector( obj, @selector(setUp) );+ performOptionalSelector( obj, m_sel );+ performOptionalSelector( obj, @selector(tearDown) );++ arcSafeRelease( obj );+ }+ private:+ virtual ~OcMethod() {}++ Class m_cls;+ SEL m_sel;+ };++ namespace Detail{++ inline std::string getAnnotation( Class cls,+ std::string const& annotationName,+ std::string const& testCaseName ) {+ NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];+ SEL sel = NSSelectorFromString( selStr );+ arcSafeRelease( selStr );+ id value = performOptionalSelector( cls, sel );+ if( value )+ return [(NSString*)value UTF8String];+ return "";+ }+ }++ inline std::size_t registerTestMethods() {+ std::size_t noTestMethods = 0;+ int noClasses = objc_getClassList( nullptr, 0 );++ Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);+ objc_getClassList( classes, noClasses );++ for( int c = 0; c < noClasses; c++ ) {+ Class cls = classes[c];+ {+ u_int count;+ Method* methods = class_copyMethodList( cls, &count );+ for( u_int m = 0; m < count ; m++ ) {+ SEL selector = method_getName(methods[m]);+ std::string methodName = sel_getName(selector);+ if( startsWith( methodName, "Catch_TestCase_" ) ) {+ std::string testCaseName = methodName.substr( 15 );+ std::string name = Detail::getAnnotation( cls, "Name", testCaseName );+ std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );+ const char* className = class_getName( cls );++ getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) );+ noTestMethods++;+ }+ }+ free(methods);+ }+ }+ return noTestMethods;+ }++#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)++ namespace Matchers {+ namespace Impl {+ namespace NSStringMatchers {++ struct StringHolder : MatcherBase<NSString*>{+ StringHolder( NSString* substr ) : m_substr( [substr copy] ){}+ StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}+ StringHolder() {+ arcSafeRelease( m_substr );+ }++ bool match( NSString* str ) const override {+ return false;+ }++ NSString* CATCH_ARC_STRONG m_substr;+ };++ struct Equals : StringHolder {+ Equals( NSString* substr ) : StringHolder( substr ){}++ bool match( NSString* str ) const override {+ return (str != nil || m_substr == nil ) &&+ [str isEqualToString:m_substr];+ }++ std::string describe() const override {+ return "equals string: " + Catch::Detail::stringify( m_substr );+ }+ };++ struct Contains : StringHolder {+ Contains( NSString* substr ) : StringHolder( substr ){}++ bool match( NSString* str ) const override {+ return (str != nil || m_substr == nil ) &&+ [str rangeOfString:m_substr].location != NSNotFound;+ }++ std::string describe() const override {+ return "contains string: " + Catch::Detail::stringify( m_substr );+ }+ };++ struct StartsWith : StringHolder {+ StartsWith( NSString* substr ) : StringHolder( substr ){}++ bool match( NSString* str ) const override {+ return (str != nil || m_substr == nil ) &&+ [str rangeOfString:m_substr].location == 0;+ }++ std::string describe() const override {+ return "starts with: " + Catch::Detail::stringify( m_substr );+ }+ };+ struct EndsWith : StringHolder {+ EndsWith( NSString* substr ) : StringHolder( substr ){}++ bool match( NSString* str ) const override {+ return (str != nil || m_substr == nil ) &&+ [str rangeOfString:m_substr].location == [str length] - [m_substr length];+ }++ std::string describe() const override {+ return "ends with: " + Catch::Detail::stringify( m_substr );+ }+ };++ } // namespace NSStringMatchers+ } // namespace Impl++ inline Impl::NSStringMatchers::Equals+ Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }++ inline Impl::NSStringMatchers::Contains+ Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }++ inline Impl::NSStringMatchers::StartsWith+ StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }++ inline Impl::NSStringMatchers::EndsWith+ EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }++ } // namespace Matchers++ using namespace Matchers;++#endif // CATCH_CONFIG_DISABLE_MATCHERS++} // namespace Catch++///////////////////////////////////////////////////////////////////////////////+#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix+#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \+{ \+return @ name; \+} \++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \+{ \+return @ desc; \+} \+-(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix )++#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ )++// end catch_objc.hpp+#endif++// Benchmarking needs the externally-facing parts of reporters to work+#if defined(CATCH_CONFIG_EXTERNAL_INTERFACES) || defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+// start catch_external_interfaces.h++// start catch_reporter_bases.hpp++// start catch_interfaces_reporter.h++// start catch_config.hpp++// start catch_test_spec_parser.h++#ifdef __clang__+#pragma clang diagnostic push+#pragma clang diagnostic ignored "-Wpadded"+#endif++// start catch_test_spec.h++#ifdef __clang__+#pragma clang diagnostic push+#pragma clang diagnostic ignored "-Wpadded"+#endif++// start catch_wildcard_pattern.h++namespace Catch+{+ class WildcardPattern {+ enum WildcardPosition {+ NoWildcard = 0,+ WildcardAtStart = 1,+ WildcardAtEnd = 2,+ WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd+ };++ public:++ WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity );+ virtual ~WildcardPattern() = default;+ virtual bool matches( std::string const& str ) const;++ private:+ std::string normaliseString( std::string const& str ) const;+ CaseSensitive::Choice m_caseSensitivity;+ WildcardPosition m_wildcard = NoWildcard;+ std::string m_pattern;+ };+}++// end catch_wildcard_pattern.h+#include <string>+#include <vector>+#include <memory>++namespace Catch {++ struct IConfig;++ class TestSpec {+ class Pattern {+ public:+ explicit Pattern( std::string const& name );+ virtual ~Pattern();+ virtual bool matches( TestCaseInfo const& testCase ) const = 0;+ std::string const& name() const;+ private:+ std::string const m_name;+ };+ using PatternPtr = std::shared_ptr<Pattern>;++ class NamePattern : public Pattern {+ public:+ explicit NamePattern( std::string const& name, std::string const& filterString );+ bool matches( TestCaseInfo const& testCase ) const override;+ private:+ WildcardPattern m_wildcardPattern;+ };++ class TagPattern : public Pattern {+ public:+ explicit TagPattern( std::string const& tag, std::string const& filterString );+ bool matches( TestCaseInfo const& testCase ) const override;+ private:+ std::string m_tag;+ };++ class ExcludedPattern : public Pattern {+ public:+ explicit ExcludedPattern( PatternPtr const& underlyingPattern );+ bool matches( TestCaseInfo const& testCase ) const override;+ private:+ PatternPtr m_underlyingPattern;+ };++ struct Filter {+ std::vector<PatternPtr> m_patterns;++ bool matches( TestCaseInfo const& testCase ) const;+ std::string name() const;+ };++ public:+ struct FilterMatch {+ std::string name;+ std::vector<TestCase const*> tests;+ };+ using Matches = std::vector<FilterMatch>;+ using vectorStrings = std::vector<std::string>;++ bool hasFilters() const;+ bool matches( TestCaseInfo const& testCase ) const;+ Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const;+ const vectorStrings & getInvalidArgs() const;++ private:+ std::vector<Filter> m_filters;+ std::vector<std::string> m_invalidArgs;+ friend class TestSpecParser;+ };+}++#ifdef __clang__+#pragma clang diagnostic pop+#endif++// end catch_test_spec.h+// start catch_interfaces_tag_alias_registry.h++#include <string>++namespace Catch {++ struct TagAlias;++ struct ITagAliasRegistry {+ virtual ~ITagAliasRegistry();+ // Nullptr if not present+ virtual TagAlias const* find( std::string const& alias ) const = 0;+ virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;++ static ITagAliasRegistry const& get();+ };++} // end namespace Catch++// end catch_interfaces_tag_alias_registry.h+namespace Catch {++ class TestSpecParser {+ enum Mode{ None, Name, QuotedName, Tag, EscapedName };+ Mode m_mode = None;+ Mode lastMode = None;+ bool m_exclusion = false;+ std::size_t m_pos = 0;+ std::size_t m_realPatternPos = 0;+ std::string m_arg;+ std::string m_substring;+ std::string m_patternName;+ std::vector<std::size_t> m_escapeChars;+ TestSpec::Filter m_currentFilter;+ TestSpec m_testSpec;+ ITagAliasRegistry const* m_tagAliases = nullptr;++ public:+ TestSpecParser( ITagAliasRegistry const& tagAliases );++ TestSpecParser& parse( std::string const& arg );+ TestSpec testSpec();++ private:+ bool visitChar( char c );+ void startNewMode( Mode mode );+ bool processNoneChar( char c );+ void processNameChar( char c );+ bool processOtherChar( char c );+ void endMode();+ void escape();+ bool isControlChar( char c ) const;+ void saveLastMode();+ void revertBackToLastMode();+ void addFilter();+ bool separate();++ // Handles common preprocessing of the pattern for name/tag patterns+ std::string preprocessPattern();+ // Adds the current pattern as a test name+ void addNamePattern();+ // Adds the current pattern as a tag+ void addTagPattern();++ inline void addCharToPattern(char c) {+ m_substring += c;+ m_patternName += c;+ m_realPatternPos++;+ }++ };+ TestSpec parseTestSpec( std::string const& arg );++} // namespace Catch++#ifdef __clang__+#pragma clang diagnostic pop+#endif++// end catch_test_spec_parser.h+// Libstdc++ doesn't like incomplete classes for unique_ptr++#include <memory>+#include <vector>+#include <string>++#ifndef CATCH_CONFIG_CONSOLE_WIDTH+#define CATCH_CONFIG_CONSOLE_WIDTH 80+#endif++namespace Catch {++ struct IStream;++ struct ConfigData {+ bool listTests = false;+ bool listTags = false;+ bool listReporters = false;+ bool listTestNamesOnly = false;++ bool showSuccessfulTests = false;+ bool shouldDebugBreak = false;+ bool noThrow = false;+ bool showHelp = false;+ bool showInvisibles = false;+ bool filenamesAsTags = false;+ bool libIdentify = false;++ int abortAfter = -1;+ unsigned int rngSeed = 0;++ bool benchmarkNoAnalysis = false;+ unsigned int benchmarkSamples = 100;+ double benchmarkConfidenceInterval = 0.95;+ unsigned int benchmarkResamples = 100000;+ std::chrono::milliseconds::rep benchmarkWarmupTime = 100;++ Verbosity verbosity = Verbosity::Normal;+ WarnAbout::What warnings = WarnAbout::Nothing;+ ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;+ double minDuration = -1;+ RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;+ UseColour::YesOrNo useColour = UseColour::Auto;+ WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;++ std::string outputFilename;+ std::string name;+ std::string processName;+#ifndef CATCH_CONFIG_DEFAULT_REPORTER+#define CATCH_CONFIG_DEFAULT_REPORTER "console"+#endif+ std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER;+#undef CATCH_CONFIG_DEFAULT_REPORTER++ std::vector<std::string> testsOrTags;+ std::vector<std::string> sectionsToRun;+ };++ class Config : public IConfig {+ public:++ Config() = default;+ Config( ConfigData const& data );+ virtual ~Config() = default;++ std::string const& getFilename() const;++ bool listTests() const;+ bool listTestNamesOnly() const;+ bool listTags() const;+ bool listReporters() const;++ std::string getProcessName() const;+ std::string const& getReporterName() const;++ std::vector<std::string> const& getTestsOrTags() const override;+ std::vector<std::string> const& getSectionsToRun() const override;++ TestSpec const& testSpec() const override;+ bool hasTestFilters() const override;++ bool showHelp() const;++ // IConfig interface+ bool allowThrows() const override;+ std::ostream& stream() const override;+ std::string name() const override;+ bool includeSuccessfulResults() const override;+ bool warnAboutMissingAssertions() const override;+ bool warnAboutNoTests() const override;+ ShowDurations::OrNot showDurations() const override;+ double minDuration() const override;+ RunTests::InWhatOrder runOrder() const override;+ unsigned int rngSeed() const override;+ UseColour::YesOrNo useColour() const override;+ bool shouldDebugBreak() const override;+ int abortAfter() const override;+ bool showInvisibles() const override;+ Verbosity verbosity() const override;+ bool benchmarkNoAnalysis() const override;+ int benchmarkSamples() const override;+ double benchmarkConfidenceInterval() const override;+ unsigned int benchmarkResamples() const override;+ std::chrono::milliseconds benchmarkWarmupTime() const override;++ private:++ IStream const* openStream();+ ConfigData m_data;++ std::unique_ptr<IStream const> m_stream;+ TestSpec m_testSpec;+ bool m_hasTestFilters = false;+ };++} // end namespace Catch++// end catch_config.hpp+// start catch_assertionresult.h++#include <string>++namespace Catch {++ struct AssertionResultData+ {+ AssertionResultData() = delete;++ AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );++ std::string message;+ mutable std::string reconstructedExpression;+ LazyExpression lazyExpression;+ ResultWas::OfType resultType;++ std::string reconstructExpression() const;+ };++ class AssertionResult {+ public:+ AssertionResult() = delete;+ AssertionResult( AssertionInfo const& info, AssertionResultData const& data );++ bool isOk() const;+ bool succeeded() const;+ ResultWas::OfType getResultType() const;+ bool hasExpression() const;+ bool hasMessage() const;+ std::string getExpression() const;+ std::string getExpressionInMacro() const;+ bool hasExpandedExpression() const;+ std::string getExpandedExpression() const;+ std::string getMessage() const;+ SourceLineInfo getSourceInfo() const;+ StringRef getTestMacroName() const;++ //protected:+ AssertionInfo m_info;+ AssertionResultData m_resultData;+ };++} // end namespace Catch++// end catch_assertionresult.h+#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+// start catch_estimate.hpp++ // Statistics estimates+++namespace Catch {+ namespace Benchmark {+ template <typename Duration>+ struct Estimate {+ Duration point;+ Duration lower_bound;+ Duration upper_bound;+ double confidence_interval;++ template <typename Duration2>+ operator Estimate<Duration2>() const {+ return { point, lower_bound, upper_bound, confidence_interval };+ }+ };+ } // namespace Benchmark+} // namespace Catch++// end catch_estimate.hpp+// start catch_outlier_classification.hpp++// Outlier information++namespace Catch {+ namespace Benchmark {+ struct OutlierClassification {+ int samples_seen = 0;+ int low_severe = 0; // more than 3 times IQR below Q1+ int low_mild = 0; // 1.5 to 3 times IQR below Q1+ int high_mild = 0; // 1.5 to 3 times IQR above Q3+ int high_severe = 0; // more than 3 times IQR above Q3++ int total() const {+ return low_severe + low_mild + high_mild + high_severe;+ }+ };+ } // namespace Benchmark+} // namespace Catch++// end catch_outlier_classification.hpp++#include <iterator>+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++#include <string>+#include <iosfwd>+#include <map>+#include <set>+#include <memory>+#include <algorithm>++namespace Catch {++ struct ReporterConfig {+ explicit ReporterConfig( IConfigPtr const& _fullConfig );++ ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream );++ std::ostream& stream() const;+ IConfigPtr fullConfig() const;++ private:+ std::ostream* m_stream;+ IConfigPtr m_fullConfig;+ };++ struct ReporterPreferences {+ bool shouldRedirectStdOut = false;+ bool shouldReportAllAssertions = false;+ };++ template<typename T>+ struct LazyStat : Option<T> {+ LazyStat& operator=( T const& _value ) {+ Option<T>::operator=( _value );+ used = false;+ return *this;+ }+ void reset() {+ Option<T>::reset();+ used = false;+ }+ bool used = false;+ };++ struct TestRunInfo {+ TestRunInfo( std::string const& _name );+ std::string name;+ };+ struct GroupInfo {+ GroupInfo( std::string const& _name,+ std::size_t _groupIndex,+ std::size_t _groupsCount );++ std::string name;+ std::size_t groupIndex;+ std::size_t groupsCounts;+ };++ struct AssertionStats {+ AssertionStats( AssertionResult const& _assertionResult,+ std::vector<MessageInfo> const& _infoMessages,+ Totals const& _totals );++ AssertionStats( AssertionStats const& ) = default;+ AssertionStats( AssertionStats && ) = default;+ AssertionStats& operator = ( AssertionStats const& ) = delete;+ AssertionStats& operator = ( AssertionStats && ) = delete;+ virtual ~AssertionStats();++ AssertionResult assertionResult;+ std::vector<MessageInfo> infoMessages;+ Totals totals;+ };++ struct SectionStats {+ SectionStats( SectionInfo const& _sectionInfo,+ Counts const& _assertions,+ double _durationInSeconds,+ bool _missingAssertions );+ SectionStats( SectionStats const& ) = default;+ SectionStats( SectionStats && ) = default;+ SectionStats& operator = ( SectionStats const& ) = default;+ SectionStats& operator = ( SectionStats && ) = default;+ virtual ~SectionStats();++ SectionInfo sectionInfo;+ Counts assertions;+ double durationInSeconds;+ bool missingAssertions;+ };++ struct TestCaseStats {+ TestCaseStats( TestCaseInfo const& _testInfo,+ Totals const& _totals,+ std::string const& _stdOut,+ std::string const& _stdErr,+ bool _aborting );++ TestCaseStats( TestCaseStats const& ) = default;+ TestCaseStats( TestCaseStats && ) = default;+ TestCaseStats& operator = ( TestCaseStats const& ) = default;+ TestCaseStats& operator = ( TestCaseStats && ) = default;+ virtual ~TestCaseStats();++ TestCaseInfo testInfo;+ Totals totals;+ std::string stdOut;+ std::string stdErr;+ bool aborting;+ };++ struct TestGroupStats {+ TestGroupStats( GroupInfo const& _groupInfo,+ Totals const& _totals,+ bool _aborting );+ TestGroupStats( GroupInfo const& _groupInfo );++ TestGroupStats( TestGroupStats const& ) = default;+ TestGroupStats( TestGroupStats && ) = default;+ TestGroupStats& operator = ( TestGroupStats const& ) = default;+ TestGroupStats& operator = ( TestGroupStats && ) = default;+ virtual ~TestGroupStats();++ GroupInfo groupInfo;+ Totals totals;+ bool aborting;+ };++ struct TestRunStats {+ TestRunStats( TestRunInfo const& _runInfo,+ Totals const& _totals,+ bool _aborting );++ TestRunStats( TestRunStats const& ) = default;+ TestRunStats( TestRunStats && ) = default;+ TestRunStats& operator = ( TestRunStats const& ) = default;+ TestRunStats& operator = ( TestRunStats && ) = default;+ virtual ~TestRunStats();++ TestRunInfo runInfo;+ Totals totals;+ bool aborting;+ };++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+ struct BenchmarkInfo {+ std::string name;+ double estimatedDuration;+ int iterations;+ int samples;+ unsigned int resamples;+ double clockResolution;+ double clockCost;+ };++ template <class Duration>+ struct BenchmarkStats {+ BenchmarkInfo info;++ std::vector<Duration> samples;+ Benchmark::Estimate<Duration> mean;+ Benchmark::Estimate<Duration> standardDeviation;+ Benchmark::OutlierClassification outliers;+ double outlierVariance;++ template <typename Duration2>+ operator BenchmarkStats<Duration2>() const {+ std::vector<Duration2> samples2;+ samples2.reserve(samples.size());+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });+ return {+ info,+ std::move(samples2),+ mean,+ standardDeviation,+ outliers,+ outlierVariance,+ };+ }+ };+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++ struct IStreamingReporter {+ virtual ~IStreamingReporter() = default;++ // Implementing class must also provide the following static methods:+ // static std::string getDescription();+ // static std::set<Verbosity> getSupportedVerbosities()++ virtual ReporterPreferences getPreferences() const = 0;++ virtual void noMatchingTestCases( std::string const& spec ) = 0;++ virtual void reportInvalidArguments(std::string const&) {}++ virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;+ virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;++ virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;+ virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+ virtual void benchmarkPreparing( std::string const& ) {}+ virtual void benchmarkStarting( BenchmarkInfo const& ) {}+ virtual void benchmarkEnded( BenchmarkStats<> const& ) {}+ virtual void benchmarkFailed( std::string const& ) {}+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++ virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;++ // The return value indicates if the messages buffer should be cleared:+ virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;++ virtual void sectionEnded( SectionStats const& sectionStats ) = 0;+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;+ virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;+ virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;++ virtual void skipTest( TestCaseInfo const& testInfo ) = 0;++ // Default empty implementation provided+ virtual void fatalErrorEncountered( StringRef name );++ virtual bool isMulti() const;+ };+ using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>;++ struct IReporterFactory {+ virtual ~IReporterFactory();+ virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0;+ virtual std::string getDescription() const = 0;+ };+ using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;++ struct IReporterRegistry {+ using FactoryMap = std::map<std::string, IReporterFactoryPtr>;+ using Listeners = std::vector<IReporterFactoryPtr>;++ virtual ~IReporterRegistry();+ virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0;+ virtual FactoryMap const& getFactories() const = 0;+ virtual Listeners const& getListeners() const = 0;+ };++} // end namespace Catch++// end catch_interfaces_reporter.h+#include <algorithm>+#include <cstring>+#include <cfloat>+#include <cstdio>+#include <cassert>+#include <memory>+#include <ostream>++namespace Catch {+ void prepareExpandedExpression(AssertionResult& result);++ // Returns double formatted as %.3f (format expected on output)+ std::string getFormattedDuration( double duration );++ //! Should the reporter show+ bool shouldShowDuration( IConfig const& config, double duration );++ std::string serializeFilters( std::vector<std::string> const& container );++ template<typename DerivedT>+ struct StreamingReporterBase : IStreamingReporter {++ StreamingReporterBase( ReporterConfig const& _config )+ : m_config( _config.fullConfig() ),+ stream( _config.stream() )+ {+ m_reporterPrefs.shouldRedirectStdOut = false;+ if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )+ CATCH_ERROR( "Verbosity level not supported by this reporter" );+ }++ ReporterPreferences getPreferences() const override {+ return m_reporterPrefs;+ }++ static std::set<Verbosity> getSupportedVerbosities() {+ return { Verbosity::Normal };+ }++ ~StreamingReporterBase() override = default;++ void noMatchingTestCases(std::string const&) override {}++ void reportInvalidArguments(std::string const&) override {}++ void testRunStarting(TestRunInfo const& _testRunInfo) override {+ currentTestRunInfo = _testRunInfo;+ }++ void testGroupStarting(GroupInfo const& _groupInfo) override {+ currentGroupInfo = _groupInfo;+ }++ void testCaseStarting(TestCaseInfo const& _testInfo) override {+ currentTestCaseInfo = _testInfo;+ }+ void sectionStarting(SectionInfo const& _sectionInfo) override {+ m_sectionStack.push_back(_sectionInfo);+ }++ void sectionEnded(SectionStats const& /* _sectionStats */) override {+ m_sectionStack.pop_back();+ }+ void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {+ currentTestCaseInfo.reset();+ }+ void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override {+ currentGroupInfo.reset();+ }+ void testRunEnded(TestRunStats const& /* _testRunStats */) override {+ currentTestCaseInfo.reset();+ currentGroupInfo.reset();+ currentTestRunInfo.reset();+ }++ void skipTest(TestCaseInfo const&) override {+ // Don't do anything with this by default.+ // It can optionally be overridden in the derived class.+ }++ IConfigPtr m_config;+ std::ostream& stream;++ LazyStat<TestRunInfo> currentTestRunInfo;+ LazyStat<GroupInfo> currentGroupInfo;+ LazyStat<TestCaseInfo> currentTestCaseInfo;++ std::vector<SectionInfo> m_sectionStack;+ ReporterPreferences m_reporterPrefs;+ };++ template<typename DerivedT>+ struct CumulativeReporterBase : IStreamingReporter {+ template<typename T, typename ChildNodeT>+ struct Node {+ explicit Node( T const& _value ) : value( _value ) {}+ virtual ~Node() {}++ using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>;+ T value;+ ChildNodes children;+ };+ struct SectionNode {+ explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}+ virtual ~SectionNode() = default;++ bool operator == (SectionNode const& other) const {+ return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;+ }+ bool operator == (std::shared_ptr<SectionNode> const& other) const {+ return operator==(*other);+ }++ SectionStats stats;+ using ChildSections = std::vector<std::shared_ptr<SectionNode>>;+ using Assertions = std::vector<AssertionStats>;+ ChildSections childSections;+ Assertions assertions;+ std::string stdOut;+ std::string stdErr;+ };++ struct BySectionInfo {+ BySectionInfo( SectionInfo const& other ) : m_other( other ) {}+ BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}+ bool operator() (std::shared_ptr<SectionNode> const& node) const {+ return ((node->stats.sectionInfo.name == m_other.name) &&+ (node->stats.sectionInfo.lineInfo == m_other.lineInfo));+ }+ void operator=(BySectionInfo const&) = delete;++ private:+ SectionInfo const& m_other;+ };++ using TestCaseNode = Node<TestCaseStats, SectionNode>;+ using TestGroupNode = Node<TestGroupStats, TestCaseNode>;+ using TestRunNode = Node<TestRunStats, TestGroupNode>;++ CumulativeReporterBase( ReporterConfig const& _config )+ : m_config( _config.fullConfig() ),+ stream( _config.stream() )+ {+ m_reporterPrefs.shouldRedirectStdOut = false;+ if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )+ CATCH_ERROR( "Verbosity level not supported by this reporter" );+ }+ ~CumulativeReporterBase() override = default;++ ReporterPreferences getPreferences() const override {+ return m_reporterPrefs;+ }++ static std::set<Verbosity> getSupportedVerbosities() {+ return { Verbosity::Normal };+ }++ void testRunStarting( TestRunInfo const& ) override {}+ void testGroupStarting( GroupInfo const& ) override {}++ void testCaseStarting( TestCaseInfo const& ) override {}++ void sectionStarting( SectionInfo const& sectionInfo ) override {+ SectionStats incompleteStats( sectionInfo, Counts(), 0, false );+ std::shared_ptr<SectionNode> node;+ if( m_sectionStack.empty() ) {+ if( !m_rootSection )+ m_rootSection = std::make_shared<SectionNode>( incompleteStats );+ node = m_rootSection;+ }+ else {+ SectionNode& parentNode = *m_sectionStack.back();+ auto it =+ std::find_if( parentNode.childSections.begin(),+ parentNode.childSections.end(),+ BySectionInfo( sectionInfo ) );+ if( it == parentNode.childSections.end() ) {+ node = std::make_shared<SectionNode>( incompleteStats );+ parentNode.childSections.push_back( node );+ }+ else+ node = *it;+ }+ m_sectionStack.push_back( node );+ m_deepestSection = std::move(node);+ }++ void assertionStarting(AssertionInfo const&) override {}++ bool assertionEnded(AssertionStats const& assertionStats) override {+ assert(!m_sectionStack.empty());+ // AssertionResult holds a pointer to a temporary DecomposedExpression,+ // which getExpandedExpression() calls to build the expression string.+ // Our section stack copy of the assertionResult will likely outlive the+ // temporary, so it must be expanded or discarded now to avoid calling+ // a destroyed object later.+ prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) );+ SectionNode& sectionNode = *m_sectionStack.back();+ sectionNode.assertions.push_back(assertionStats);+ return true;+ }+ void sectionEnded(SectionStats const& sectionStats) override {+ assert(!m_sectionStack.empty());+ SectionNode& node = *m_sectionStack.back();+ node.stats = sectionStats;+ m_sectionStack.pop_back();+ }+ void testCaseEnded(TestCaseStats const& testCaseStats) override {+ auto node = std::make_shared<TestCaseNode>(testCaseStats);+ assert(m_sectionStack.size() == 0);+ node->children.push_back(m_rootSection);+ m_testCases.push_back(node);+ m_rootSection.reset();++ assert(m_deepestSection);+ m_deepestSection->stdOut = testCaseStats.stdOut;+ m_deepestSection->stdErr = testCaseStats.stdErr;+ }+ void testGroupEnded(TestGroupStats const& testGroupStats) override {+ auto node = std::make_shared<TestGroupNode>(testGroupStats);+ node->children.swap(m_testCases);+ m_testGroups.push_back(node);+ }+ void testRunEnded(TestRunStats const& testRunStats) override {+ auto node = std::make_shared<TestRunNode>(testRunStats);+ node->children.swap(m_testGroups);+ m_testRuns.push_back(node);+ testRunEndedCumulative();+ }+ virtual void testRunEndedCumulative() = 0;++ void skipTest(TestCaseInfo const&) override {}++ IConfigPtr m_config;+ std::ostream& stream;+ std::vector<AssertionStats> m_assertions;+ std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections;+ std::vector<std::shared_ptr<TestCaseNode>> m_testCases;+ std::vector<std::shared_ptr<TestGroupNode>> m_testGroups;++ std::vector<std::shared_ptr<TestRunNode>> m_testRuns;++ std::shared_ptr<SectionNode> m_rootSection;+ std::shared_ptr<SectionNode> m_deepestSection;+ std::vector<std::shared_ptr<SectionNode>> m_sectionStack;+ ReporterPreferences m_reporterPrefs;+ };++ template<char C>+ char const* getLineOfChars() {+ static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};+ if( !*line ) {+ std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );+ line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;+ }+ return line;+ }++ struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> {+ TestEventListenerBase( ReporterConfig const& _config );++ static std::set<Verbosity> getSupportedVerbosities();++ void assertionStarting(AssertionInfo const&) override;+ bool assertionEnded(AssertionStats const&) override;+ };++} // end namespace Catch++// end catch_reporter_bases.hpp+// start catch_console_colour.h++namespace Catch {++ struct Colour {+ enum Code {+ None = 0,++ White,+ Red,+ Green,+ Blue,+ Cyan,+ Yellow,+ Grey,++ Bright = 0x10,++ BrightRed = Bright | Red,+ BrightGreen = Bright | Green,+ LightGrey = Bright | Grey,+ BrightWhite = Bright | White,+ BrightYellow = Bright | Yellow,++ // By intention+ FileName = LightGrey,+ Warning = BrightYellow,+ ResultError = BrightRed,+ ResultSuccess = BrightGreen,+ ResultExpectedFailure = Warning,++ Error = BrightRed,+ Success = Green,++ OriginalExpression = Cyan,+ ReconstructedExpression = BrightYellow,++ SecondaryText = LightGrey,+ Headers = White+ };++ // Use constructed object for RAII guard+ Colour( Code _colourCode );+ Colour( Colour&& other ) noexcept;+ Colour& operator=( Colour&& other ) noexcept;+ ~Colour();++ // Use static method for one-shot changes+ static void use( Code _colourCode );++ private:+ bool m_moved = false;+ };++ std::ostream& operator << ( std::ostream& os, Colour const& );++} // end namespace Catch++// end catch_console_colour.h+// start catch_reporter_registrars.hpp+++namespace Catch {++ template<typename T>+ class ReporterRegistrar {++ class ReporterFactory : public IReporterFactory {++ IStreamingReporterPtr create( ReporterConfig const& config ) const override {+ return std::unique_ptr<T>( new T( config ) );+ }++ std::string getDescription() const override {+ return T::getDescription();+ }+ };++ public:++ explicit ReporterRegistrar( std::string const& name ) {+ getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() );+ }+ };++ template<typename T>+ class ListenerRegistrar {++ class ListenerFactory : public IReporterFactory {++ IStreamingReporterPtr create( ReporterConfig const& config ) const override {+ return std::unique_ptr<T>( new T( config ) );+ }+ std::string getDescription() const override {+ return std::string();+ }+ };++ public:++ ListenerRegistrar() {+ getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() );+ }+ };+}++#if !defined(CATCH_CONFIG_DISABLE)++#define CATCH_REGISTER_REPORTER( name, reporterType ) \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION++#define CATCH_REGISTER_LISTENER( listenerType ) \+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \+ namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION+#else // CATCH_CONFIG_DISABLE++#define CATCH_REGISTER_REPORTER(name, reporterType)+#define CATCH_REGISTER_LISTENER(listenerType)++#endif // CATCH_CONFIG_DISABLE++// end catch_reporter_registrars.hpp+// Allow users to base their work off existing reporters+// start catch_reporter_compact.h++namespace Catch {++ struct CompactReporter : StreamingReporterBase<CompactReporter> {++ using StreamingReporterBase::StreamingReporterBase;++ ~CompactReporter() override;++ static std::string getDescription();++ void noMatchingTestCases(std::string const& spec) override;++ void assertionStarting(AssertionInfo const&) override;++ bool assertionEnded(AssertionStats const& _assertionStats) override;++ void sectionEnded(SectionStats const& _sectionStats) override;++ void testRunEnded(TestRunStats const& _testRunStats) override;++ };++} // end namespace Catch++// end catch_reporter_compact.h+// start catch_reporter_console.h++#if defined(_MSC_VER)+#pragma warning(push)+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch+ // Note that 4062 (not all labels are handled+ // and default is missing) is enabled+#endif++namespace Catch {+ // Fwd decls+ struct SummaryColumn;+ class TablePrinter;++ struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> {+ std::unique_ptr<TablePrinter> m_tablePrinter;++ ConsoleReporter(ReporterConfig const& config);+ ~ConsoleReporter() override;+ static std::string getDescription();++ void noMatchingTestCases(std::string const& spec) override;++ void reportInvalidArguments(std::string const&arg) override;++ void assertionStarting(AssertionInfo const&) override;++ bool assertionEnded(AssertionStats const& _assertionStats) override;++ void sectionStarting(SectionInfo const& _sectionInfo) override;+ void sectionEnded(SectionStats const& _sectionStats) override;++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+ void benchmarkPreparing(std::string const& name) override;+ void benchmarkStarting(BenchmarkInfo const& info) override;+ void benchmarkEnded(BenchmarkStats<> const& stats) override;+ void benchmarkFailed(std::string const& error) override;+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++ void testCaseEnded(TestCaseStats const& _testCaseStats) override;+ void testGroupEnded(TestGroupStats const& _testGroupStats) override;+ void testRunEnded(TestRunStats const& _testRunStats) override;+ void testRunStarting(TestRunInfo const& _testRunInfo) override;+ private:++ void lazyPrint();++ void lazyPrintWithoutClosingBenchmarkTable();+ void lazyPrintRunInfo();+ void lazyPrintGroupInfo();+ void printTestCaseAndSectionHeader();++ void printClosedHeader(std::string const& _name);+ void printOpenHeader(std::string const& _name);++ // if string has a : in first line will set indent to follow it on+ // subsequent lines+ void printHeaderString(std::string const& _string, std::size_t indent = 0);++ void printTotals(Totals const& totals);+ void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row);++ void printTotalsDivider(Totals const& totals);+ void printSummaryDivider();+ void printTestFilters();++ private:+ bool m_headerPrinted = false;+ };++} // end namespace Catch++#if defined(_MSC_VER)+#pragma warning(pop)+#endif++// end catch_reporter_console.h+// start catch_reporter_junit.h++// start catch_xmlwriter.h++#include <vector>++namespace Catch {+ enum class XmlFormatting {+ None = 0x00,+ Indent = 0x01,+ Newline = 0x02,+ };++ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);+ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);++ class XmlEncode {+ public:+ enum ForWhat { ForTextNodes, ForAttributes };++ XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );++ void encodeTo( std::ostream& os ) const;++ friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );++ private:+ std::string m_str;+ ForWhat m_forWhat;+ };++ class XmlWriter {+ public:++ class ScopedElement {+ public:+ ScopedElement( XmlWriter* writer, XmlFormatting fmt );++ ScopedElement( ScopedElement&& other ) noexcept;+ ScopedElement& operator=( ScopedElement&& other ) noexcept;++ ~ScopedElement();++ ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent );++ template<typename T>+ ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {+ m_writer->writeAttribute( name, attribute );+ return *this;+ }++ private:+ mutable XmlWriter* m_writer = nullptr;+ XmlFormatting m_fmt;+ };++ XmlWriter( std::ostream& os = Catch::cout() );+ ~XmlWriter();++ XmlWriter( XmlWriter const& ) = delete;+ XmlWriter& operator=( XmlWriter const& ) = delete;++ XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);++ ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);++ XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);++ XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );++ XmlWriter& writeAttribute( std::string const& name, bool attribute );++ template<typename T>+ XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {+ ReusableStringStream rss;+ rss << attribute;+ return writeAttribute( name, rss.str() );+ }++ XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);++ XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);++ void writeStylesheetRef( std::string const& url );++ XmlWriter& writeBlankLine();++ void ensureTagClosed();++ private:++ void applyFormatting(XmlFormatting fmt);++ void writeDeclaration();++ void newlineIfNecessary();++ bool m_tagIsOpen = false;+ bool m_needsNewline = false;+ std::vector<std::string> m_tags;+ std::string m_indent;+ std::ostream& m_os;+ };++}++// end catch_xmlwriter.h+namespace Catch {++ class JunitReporter : public CumulativeReporterBase<JunitReporter> {+ public:+ JunitReporter(ReporterConfig const& _config);++ ~JunitReporter() override;++ static std::string getDescription();++ void noMatchingTestCases(std::string const& /*spec*/) override;++ void testRunStarting(TestRunInfo const& runInfo) override;++ void testGroupStarting(GroupInfo const& groupInfo) override;++ void testCaseStarting(TestCaseInfo const& testCaseInfo) override;+ bool assertionEnded(AssertionStats const& assertionStats) override;++ void testCaseEnded(TestCaseStats const& testCaseStats) override;++ void testGroupEnded(TestGroupStats const& testGroupStats) override;++ void testRunEndedCumulative() override;++ void writeGroup(TestGroupNode const& groupNode, double suiteTime);++ void writeTestCase(TestCaseNode const& testCaseNode);++ void writeSection( std::string const& className,+ std::string const& rootName,+ SectionNode const& sectionNode,+ bool testOkToFail );++ void writeAssertions(SectionNode const& sectionNode);+ void writeAssertion(AssertionStats const& stats);++ XmlWriter xml;+ Timer suiteTimer;+ std::string stdOutForSuite;+ std::string stdErrForSuite;+ unsigned int unexpectedExceptions = 0;+ bool m_okToFail = false;+ };++} // end namespace Catch++// end catch_reporter_junit.h+// start catch_reporter_xml.h++namespace Catch {+ class XmlReporter : public StreamingReporterBase<XmlReporter> {+ public:+ XmlReporter(ReporterConfig const& _config);++ ~XmlReporter() override;++ static std::string getDescription();++ virtual std::string getStylesheetRef() const;++ void writeSourceInfo(SourceLineInfo const& sourceInfo);++ public: // StreamingReporterBase++ void noMatchingTestCases(std::string const& s) override;++ void testRunStarting(TestRunInfo const& testInfo) override;++ void testGroupStarting(GroupInfo const& groupInfo) override;++ void testCaseStarting(TestCaseInfo const& testInfo) override;++ void sectionStarting(SectionInfo const& sectionInfo) override;++ void assertionStarting(AssertionInfo const&) override;++ bool assertionEnded(AssertionStats const& assertionStats) override;++ void sectionEnded(SectionStats const& sectionStats) override;++ void testCaseEnded(TestCaseStats const& testCaseStats) override;++ void testGroupEnded(TestGroupStats const& testGroupStats) override;++ void testRunEnded(TestRunStats const& testRunStats) override;++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+ void benchmarkPreparing(std::string const& name) override;+ void benchmarkStarting(BenchmarkInfo const&) override;+ void benchmarkEnded(BenchmarkStats<> const&) override;+ void benchmarkFailed(std::string const&) override;+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++ private:+ Timer m_testCaseTimer;+ XmlWriter m_xml;+ int m_sectionDepth = 0;+ };++} // end namespace Catch++// end catch_reporter_xml.h++// end catch_external_interfaces.h+#endif++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+// start catch_benchmarking_all.hpp++// A proxy header that includes all of the benchmarking headers to allow+// concise include of the benchmarking features. You should prefer the+// individual includes in standard use.++// start catch_benchmark.hpp++ // Benchmark++// start catch_chronometer.hpp++// User-facing chronometer+++// start catch_clock.hpp++// Clocks+++#include <chrono>+#include <ratio>++namespace Catch {+ namespace Benchmark {+ template <typename Clock>+ using ClockDuration = typename Clock::duration;+ template <typename Clock>+ using FloatDuration = std::chrono::duration<double, typename Clock::period>;++ template <typename Clock>+ using TimePoint = typename Clock::time_point;++ using default_clock = std::chrono::steady_clock;++ template <typename Clock>+ struct now {+ TimePoint<Clock> operator()() const {+ return Clock::now();+ }+ };++ using fp_seconds = std::chrono::duration<double, std::ratio<1>>;+ } // namespace Benchmark+} // namespace Catch++// end catch_clock.hpp+// start catch_optimizer.hpp++ // Hinting the optimizer+++#if defined(_MSC_VER)+# include <atomic> // atomic_thread_fence+#endif++namespace Catch {+ namespace Benchmark {+#if defined(__GNUC__) || defined(__clang__)+ template <typename T>+ inline void keep_memory(T* p) {+ asm volatile("" : : "g"(p) : "memory");+ }+ inline void keep_memory() {+ asm volatile("" : : : "memory");+ }++ namespace Detail {+ inline void optimizer_barrier() { keep_memory(); }+ } // namespace Detail+#elif defined(_MSC_VER)++#pragma optimize("", off)+ template <typename T>+ inline void keep_memory(T* p) {+ // thanks @milleniumbug+ *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);+ }+ // TODO equivalent keep_memory()+#pragma optimize("", on)++ namespace Detail {+ inline void optimizer_barrier() {+ std::atomic_thread_fence(std::memory_order_seq_cst);+ }+ } // namespace Detail++#endif++ template <typename T>+ inline void deoptimize_value(T&& x) {+ keep_memory(&x);+ }++ template <typename Fn, typename... Args>+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type {+ deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...)));+ }++ template <typename Fn, typename... Args>+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type {+ std::forward<Fn>(fn) (std::forward<Args...>(args...));+ }+ } // namespace Benchmark+} // namespace Catch++// end catch_optimizer.hpp+// start catch_complete_invoke.hpp++// Invoke with a special case for void+++#include <type_traits>+#include <utility>++namespace Catch {+ namespace Benchmark {+ namespace Detail {+ template <typename T>+ struct CompleteType { using type = T; };+ template <>+ struct CompleteType<void> { struct type {}; };++ template <typename T>+ using CompleteType_t = typename CompleteType<T>::type;++ template <typename Result>+ struct CompleteInvoker {+ template <typename Fun, typename... Args>+ static Result invoke(Fun&& fun, Args&&... args) {+ return std::forward<Fun>(fun)(std::forward<Args>(args)...);+ }+ };+ template <>+ struct CompleteInvoker<void> {+ template <typename Fun, typename... Args>+ static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {+ std::forward<Fun>(fun)(std::forward<Args>(args)...);+ return {};+ }+ };++ // invoke and not return void :(+ template <typename Fun, typename... Args>+ CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {+ return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);+ }++ const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";+ } // namespace Detail++ template <typename Fun>+ Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {+ CATCH_TRY{+ return Detail::complete_invoke(std::forward<Fun>(fun));+ } CATCH_CATCH_ALL{+ getResultCapture().benchmarkFailed(translateActiveException());+ CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg);+ }+ }+ } // namespace Benchmark+} // namespace Catch++// end catch_complete_invoke.hpp+namespace Catch {+ namespace Benchmark {+ namespace Detail {+ struct ChronometerConcept {+ virtual void start() = 0;+ virtual void finish() = 0;+ virtual ~ChronometerConcept() = default;+ };+ template <typename Clock>+ struct ChronometerModel final : public ChronometerConcept {+ void start() override { started = Clock::now(); }+ void finish() override { finished = Clock::now(); }++ ClockDuration<Clock> elapsed() const { return finished - started; }++ TimePoint<Clock> started;+ TimePoint<Clock> finished;+ };+ } // namespace Detail++ struct Chronometer {+ public:+ template <typename Fun>+ void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); }++ int runs() const { return k; }++ Chronometer(Detail::ChronometerConcept& meter, int k)+ : impl(&meter)+ , k(k) {}++ private:+ template <typename Fun>+ void measure(Fun&& fun, std::false_type) {+ measure([&fun](int) { return fun(); }, std::true_type());+ }++ template <typename Fun>+ void measure(Fun&& fun, std::true_type) {+ Detail::optimizer_barrier();+ impl->start();+ for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i);+ impl->finish();+ Detail::optimizer_barrier();+ }++ Detail::ChronometerConcept* impl;+ int k;+ };+ } // namespace Benchmark+} // namespace Catch++// end catch_chronometer.hpp+// start catch_environment.hpp++// Environment information+++namespace Catch {+ namespace Benchmark {+ template <typename Duration>+ struct EnvironmentEstimate {+ Duration mean;+ OutlierClassification outliers;++ template <typename Duration2>+ operator EnvironmentEstimate<Duration2>() const {+ return { mean, outliers };+ }+ };+ template <typename Clock>+ struct Environment {+ using clock_type = Clock;+ EnvironmentEstimate<FloatDuration<Clock>> clock_resolution;+ EnvironmentEstimate<FloatDuration<Clock>> clock_cost;+ };+ } // namespace Benchmark+} // namespace Catch++// end catch_environment.hpp+// start catch_execution_plan.hpp++ // Execution plan+++// start catch_benchmark_function.hpp++ // Dumb std::function implementation for consistent call overhead+++#include <cassert>+#include <type_traits>+#include <utility>+#include <memory>++namespace Catch {+ namespace Benchmark {+ namespace Detail {+ template <typename T>+ using Decay = typename std::decay<T>::type;+ template <typename T, typename U>+ struct is_related+ : std::is_same<Decay<T>, Decay<U>> {};++ /// We need to reinvent std::function because every piece of code that might add overhead+ /// in a measurement context needs to have consistent performance characteristics so that we+ /// can account for it in the measurement.+ /// Implementations of std::function with optimizations that aren't always applicable, like+ /// small buffer optimizations, are not uncommon.+ /// This is effectively an implementation of std::function without any such optimizations;+ /// it may be slow, but it is consistently slow.+ struct BenchmarkFunction {+ private:+ struct callable {+ virtual void call(Chronometer meter) const = 0;+ virtual callable* clone() const = 0;+ virtual ~callable() = default;+ };+ template <typename Fun>+ struct model : public callable {+ model(Fun&& fun) : fun(std::move(fun)) {}+ model(Fun const& fun) : fun(fun) {}++ model<Fun>* clone() const override { return new model<Fun>(*this); }++ void call(Chronometer meter) const override {+ call(meter, is_callable<Fun(Chronometer)>());+ }+ void call(Chronometer meter, std::true_type) const {+ fun(meter);+ }+ void call(Chronometer meter, std::false_type) const {+ meter.measure(fun);+ }++ Fun fun;+ };++ struct do_nothing { void operator()() const {} };++ template <typename T>+ BenchmarkFunction(model<T>* c) : f(c) {}++ public:+ BenchmarkFunction()+ : f(new model<do_nothing>{ {} }) {}++ template <typename Fun,+ typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0>+ BenchmarkFunction(Fun&& fun)+ : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {}++ BenchmarkFunction(BenchmarkFunction&& that)+ : f(std::move(that.f)) {}++ BenchmarkFunction(BenchmarkFunction const& that)+ : f(that.f->clone()) {}++ BenchmarkFunction& operator=(BenchmarkFunction&& that) {+ f = std::move(that.f);+ return *this;+ }++ BenchmarkFunction& operator=(BenchmarkFunction const& that) {+ f.reset(that.f->clone());+ return *this;+ }++ void operator()(Chronometer meter) const { f->call(meter); }++ private:+ std::unique_ptr<callable> f;+ };+ } // namespace Detail+ } // namespace Benchmark+} // namespace Catch++// end catch_benchmark_function.hpp+// start catch_repeat.hpp++// repeat algorithm+++#include <type_traits>+#include <utility>++namespace Catch {+ namespace Benchmark {+ namespace Detail {+ template <typename Fun>+ struct repeater {+ void operator()(int k) const {+ for (int i = 0; i < k; ++i) {+ fun();+ }+ }+ Fun fun;+ };+ template <typename Fun>+ repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) {+ return { std::forward<Fun>(fun) };+ }+ } // namespace Detail+ } // namespace Benchmark+} // namespace Catch++// end catch_repeat.hpp+// start catch_run_for_at_least.hpp++// Run a function for a minimum amount of time+++// start catch_measure.hpp++// Measure+++// start catch_timing.hpp++// Timing+++#include <tuple>+#include <type_traits>++namespace Catch {+ namespace Benchmark {+ template <typename Duration, typename Result>+ struct Timing {+ Duration elapsed;+ Result result;+ int iterations;+ };+ template <typename Clock, typename Func, typename... Args>+ using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;+ } // namespace Benchmark+} // namespace Catch++// end catch_timing.hpp+#include <utility>++namespace Catch {+ namespace Benchmark {+ namespace Detail {+ template <typename Clock, typename Fun, typename... Args>+ TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) {+ auto start = Clock::now();+ auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);+ auto end = Clock::now();+ auto delta = end - start;+ return { delta, std::forward<decltype(r)>(r), 1 };+ }+ } // namespace Detail+ } // namespace Benchmark+} // namespace Catch++// end catch_measure.hpp+#include <utility>+#include <type_traits>++namespace Catch {+ namespace Benchmark {+ namespace Detail {+ template <typename Clock, typename Fun>+ TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {+ return Detail::measure<Clock>(fun, iters);+ }+ template <typename Clock, typename Fun>+ TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {+ Detail::ChronometerModel<Clock> meter;+ auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));++ return { meter.elapsed(), std::move(result), iters };+ }++ template <typename Clock, typename Fun>+ using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type;++ struct optimized_away_error : std::exception {+ const char* what() const noexcept override {+ return "could not measure benchmark, maybe it was optimized away";+ }+ };++ template <typename Clock, typename Fun>+ TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {+ auto iters = seed;+ while (iters < (1 << 30)) {+ auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());++ if (Timing.elapsed >= how_long) {+ return { Timing.elapsed, std::move(Timing.result), iters };+ }+ iters *= 2;+ }+ Catch::throw_exception(optimized_away_error{});+ }+ } // namespace Detail+ } // namespace Benchmark+} // namespace Catch++// end catch_run_for_at_least.hpp+#include <algorithm>+#include <iterator>++namespace Catch {+ namespace Benchmark {+ template <typename Duration>+ struct ExecutionPlan {+ int iterations_per_sample;+ Duration estimated_duration;+ Detail::BenchmarkFunction benchmark;+ Duration warmup_time;+ int warmup_iterations;++ template <typename Duration2>+ operator ExecutionPlan<Duration2>() const {+ return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations };+ }++ template <typename Clock>+ std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {+ // warmup a bit+ Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));++ std::vector<FloatDuration<Clock>> times;+ times.reserve(cfg.benchmarkSamples());+ std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] {+ Detail::ChronometerModel<Clock> model;+ this->benchmark(Chronometer(model, iterations_per_sample));+ auto sample_time = model.elapsed() - env.clock_cost.mean;+ if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero();+ return sample_time / iterations_per_sample;+ });+ return times;+ }+ };+ } // namespace Benchmark+} // namespace Catch++// end catch_execution_plan.hpp+// start catch_estimate_clock.hpp++ // Environment measurement+++// start catch_stats.hpp++// Statistical analysis tools+++#include <algorithm>+#include <functional>+#include <vector>+#include <iterator>+#include <numeric>+#include <tuple>+#include <cmath>+#include <utility>+#include <cstddef>+#include <random>++namespace Catch {+ namespace Benchmark {+ namespace Detail {+ using sample = std::vector<double>;++ double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);++ template <typename Iterator>+ OutlierClassification classify_outliers(Iterator first, Iterator last) {+ std::vector<double> copy(first, last);++ auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end());+ auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end());+ auto iqr = q3 - q1;+ auto los = q1 - (iqr * 3.);+ auto lom = q1 - (iqr * 1.5);+ auto him = q3 + (iqr * 1.5);+ auto his = q3 + (iqr * 3.);++ OutlierClassification o;+ for (; first != last; ++first) {+ auto&& t = *first;+ if (t < los) ++o.low_severe;+ else if (t < lom) ++o.low_mild;+ else if (t > his) ++o.high_severe;+ else if (t > him) ++o.high_mild;+ ++o.samples_seen;+ }+ return o;+ }++ template <typename Iterator>+ double mean(Iterator first, Iterator last) {+ auto count = last - first;+ double sum = std::accumulate(first, last, 0.);+ return sum / count;+ }++ template <typename URng, typename Iterator, typename Estimator>+ sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) {+ auto n = last - first;+ std::uniform_int_distribution<decltype(n)> dist(0, n - 1);++ sample out;+ out.reserve(resamples);+ std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] {+ std::vector<double> resampled;+ resampled.reserve(n);+ std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; });+ return estimator(resampled.begin(), resampled.end());+ });+ std::sort(out.begin(), out.end());+ return out;+ }++ template <typename Estimator, typename Iterator>+ sample jackknife(Estimator&& estimator, Iterator first, Iterator last) {+ auto n = last - first;+ auto second = std::next(first);+ sample results;+ results.reserve(n);++ for (auto it = first; it != last; ++it) {+ std::iter_swap(it, first);+ results.push_back(estimator(second, last));+ }++ return results;+ }++ inline double normal_cdf(double x) {+ return std::erfc(-x / std::sqrt(2.0)) / 2.0;+ }++ double erfc_inv(double x);++ double normal_quantile(double p);++ template <typename Iterator, typename Estimator>+ Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) {+ auto n_samples = last - first;++ double point = estimator(first, last);+ // Degenerate case with a single sample+ if (n_samples == 1) return { point, point, point, confidence_level };++ sample jack = jackknife(estimator, first, last);+ double jack_mean = mean(jack.begin(), jack.end());+ double sum_squares, sum_cubes;+ std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> {+ auto d = jack_mean - x;+ auto d2 = d * d;+ auto d3 = d2 * d;+ return { sqcb.first + d2, sqcb.second + d3 };+ });++ double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));+ int n = static_cast<int>(resample.size());+ double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n;+ // degenerate case with uniform samples+ if (prob_n == 0) return { point, point, point, confidence_level };++ double bias = normal_quantile(prob_n);+ double z1 = normal_quantile((1. - confidence_level) / 2.);++ auto cumn = [n](double x) -> int {+ return std::lround(normal_cdf(x) * n); };+ auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };+ double b1 = bias + z1;+ double b2 = bias - z1;+ double a1 = a(b1);+ double a2 = a(b2);+ auto lo = (std::max)(cumn(a1), 0);+ auto hi = (std::min)(cumn(a2), n - 1);++ return { point, resample[lo], resample[hi], confidence_level };+ }++ double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n);++ struct bootstrap_analysis {+ Estimate<double> mean;+ Estimate<double> standard_deviation;+ double outlier_variance;+ };++ bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last);+ } // namespace Detail+ } // namespace Benchmark+} // namespace Catch++// end catch_stats.hpp+#include <algorithm>+#include <iterator>+#include <tuple>+#include <vector>+#include <cmath>++namespace Catch {+ namespace Benchmark {+ namespace Detail {+ template <typename Clock>+ std::vector<double> resolution(int k) {+ std::vector<TimePoint<Clock>> times;+ times.reserve(k + 1);+ std::generate_n(std::back_inserter(times), k + 1, now<Clock>{});++ std::vector<double> deltas;+ deltas.reserve(k);+ std::transform(std::next(times.begin()), times.end(), times.begin(),+ std::back_inserter(deltas),+ [](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); });++ return deltas;+ }++ const auto warmup_iterations = 10000;+ const auto warmup_time = std::chrono::milliseconds(100);+ const auto minimum_ticks = 1000;+ const auto warmup_seed = 10000;+ const auto clock_resolution_estimation_time = std::chrono::milliseconds(500);+ const auto clock_cost_estimation_time_limit = std::chrono::seconds(1);+ const auto clock_cost_estimation_tick_limit = 100000;+ const auto clock_cost_estimation_time = std::chrono::milliseconds(10);+ const auto clock_cost_estimation_iterations = 10000;++ template <typename Clock>+ int warmup() {+ return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)+ .iterations;+ }+ template <typename Clock>+ EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {+ auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)+ .result;+ return {+ FloatDuration<Clock>(mean(r.begin(), r.end())),+ classify_outliers(r.begin(), r.end()),+ };+ }+ template <typename Clock>+ EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {+ auto time_limit = (std::min)(+ resolution * clock_cost_estimation_tick_limit,+ FloatDuration<Clock>(clock_cost_estimation_time_limit));+ auto time_clock = [](int k) {+ return Detail::measure<Clock>([k] {+ for (int i = 0; i < k; ++i) {+ volatile auto ignored = Clock::now();+ (void)ignored;+ }+ }).elapsed;+ };+ time_clock(1);+ int iters = clock_cost_estimation_iterations;+ auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);+ std::vector<double> times;+ int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));+ times.reserve(nsamples);+ std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] {+ return static_cast<double>((time_clock(r.iterations) / r.iterations).count());+ });+ return {+ FloatDuration<Clock>(mean(times.begin(), times.end())),+ classify_outliers(times.begin(), times.end()),+ };+ }++ template <typename Clock>+ Environment<FloatDuration<Clock>> measure_environment() {+ static Environment<FloatDuration<Clock>>* env = nullptr;+ if (env) {+ return *env;+ }++ auto iters = Detail::warmup<Clock>();+ auto resolution = Detail::estimate_clock_resolution<Clock>(iters);+ auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);++ env = new Environment<FloatDuration<Clock>>{ resolution, cost };+ return *env;+ }+ } // namespace Detail+ } // namespace Benchmark+} // namespace Catch++// end catch_estimate_clock.hpp+// start catch_analyse.hpp++ // Run and analyse one benchmark+++// start catch_sample_analysis.hpp++// Benchmark results+++#include <algorithm>+#include <vector>+#include <string>+#include <iterator>++namespace Catch {+ namespace Benchmark {+ template <typename Duration>+ struct SampleAnalysis {+ std::vector<Duration> samples;+ Estimate<Duration> mean;+ Estimate<Duration> standard_deviation;+ OutlierClassification outliers;+ double outlier_variance;++ template <typename Duration2>+ operator SampleAnalysis<Duration2>() const {+ std::vector<Duration2> samples2;+ samples2.reserve(samples.size());+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });+ return {+ std::move(samples2),+ mean,+ standard_deviation,+ outliers,+ outlier_variance,+ };+ }+ };+ } // namespace Benchmark+} // namespace Catch++// end catch_sample_analysis.hpp+#include <algorithm>+#include <iterator>+#include <vector>++namespace Catch {+ namespace Benchmark {+ namespace Detail {+ template <typename Duration, typename Iterator>+ SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) {+ if (!cfg.benchmarkNoAnalysis()) {+ std::vector<double> samples;+ samples.reserve(last - first);+ std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); });++ auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());+ auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());++ auto wrap_estimate = [](Estimate<double> e) {+ return Estimate<Duration> {+ Duration(e.point),+ Duration(e.lower_bound),+ Duration(e.upper_bound),+ e.confidence_interval,+ };+ };+ std::vector<Duration> samples2;+ samples2.reserve(samples.size());+ std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); });+ return {+ std::move(samples2),+ wrap_estimate(analysis.mean),+ wrap_estimate(analysis.standard_deviation),+ outliers,+ analysis.outlier_variance,+ };+ } else {+ std::vector<Duration> samples;+ samples.reserve(last - first);++ Duration mean = Duration(0);+ int i = 0;+ for (auto it = first; it < last; ++it, ++i) {+ samples.push_back(Duration(*it));+ mean += Duration(*it);+ }+ mean /= i;++ return {+ std::move(samples),+ Estimate<Duration>{mean, mean, mean, 0.0},+ Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0},+ OutlierClassification{},+ 0.0+ };+ }+ }+ } // namespace Detail+ } // namespace Benchmark+} // namespace Catch++// end catch_analyse.hpp+#include <algorithm>+#include <functional>+#include <string>+#include <vector>+#include <cmath>++namespace Catch {+ namespace Benchmark {+ struct Benchmark {+ Benchmark(std::string &&name)+ : name(std::move(name)) {}++ template <class FUN>+ Benchmark(std::string &&name, FUN &&func)+ : fun(std::move(func)), name(std::move(name)) {}++ template <typename Clock>+ ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {+ auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;+ auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));+ auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);+ int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));+ return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };+ }++ template <typename Clock = default_clock>+ void run() {+ IConfigPtr cfg = getCurrentContext().getConfig();++ auto env = Detail::measure_environment<Clock>();++ getResultCapture().benchmarkPreparing(name);+ CATCH_TRY{+ auto plan = user_code([&] {+ return prepare<Clock>(*cfg, env);+ });++ BenchmarkInfo info {+ name,+ plan.estimated_duration.count(),+ plan.iterations_per_sample,+ cfg->benchmarkSamples(),+ cfg->benchmarkResamples(),+ env.clock_resolution.mean.count(),+ env.clock_cost.mean.count()+ };++ getResultCapture().benchmarkStarting(info);++ auto samples = user_code([&] {+ return plan.template run<Clock>(*cfg, env);+ });++ auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());+ BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };+ getResultCapture().benchmarkEnded(stats);++ } CATCH_CATCH_ALL{+ if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow.+ std::rethrow_exception(std::current_exception());+ }+ }++ // sets lambda to be used in fun *and* executes benchmark!+ template <typename Fun,+ typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0>+ Benchmark & operator=(Fun func) {+ fun = Detail::BenchmarkFunction(func);+ run();+ return *this;+ }++ explicit operator bool() {+ return true;+ }++ private:+ Detail::BenchmarkFunction fun;+ std::string name;+ };+ }+} // namespace Catch++#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1+#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2++#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \+ BenchmarkName = [&](int benchmarkIndex)++#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \+ BenchmarkName = [&]++// end catch_benchmark.hpp+// start catch_constructor.hpp++// Constructor and destructor helpers+++#include <type_traits>++namespace Catch {+ namespace Benchmark {+ namespace Detail {+ template <typename T, bool Destruct>+ struct ObjectStorage+ {+ using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;++ ObjectStorage() : data() {}++ ObjectStorage(const ObjectStorage& other)+ {+ new(&data) T(other.stored_object());+ }++ ObjectStorage(ObjectStorage&& other)+ {+ new(&data) T(std::move(other.stored_object()));+ }++ ~ObjectStorage() { destruct_on_exit<T>(); }++ template <typename... Args>+ void construct(Args&&... args)+ {+ new (&data) T(std::forward<Args>(args)...);+ }++ template <bool AllowManualDestruction = !Destruct>+ typename std::enable_if<AllowManualDestruction>::type destruct()+ {+ stored_object().~T();+ }++ private:+ // If this is a constructor benchmark, destruct the underlying object+ template <typename U>+ void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }+ // Otherwise, don't+ template <typename U>+ void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }++ T& stored_object() {+ return *static_cast<T*>(static_cast<void*>(&data));+ }++ T const& stored_object() const {+ return *static_cast<T*>(static_cast<void*>(&data));+ }++ TStorage data;+ };+ }++ template <typename T>+ using storage_for = Detail::ObjectStorage<T, true>;++ template <typename T>+ using destructable_object = Detail::ObjectStorage<T, false>;+ }+}++// end catch_constructor.hpp+// end catch_benchmarking_all.hpp+#endif++#endif // ! CATCH_CONFIG_IMPL_ONLY++#ifdef CATCH_IMPL+// start catch_impl.hpp++#ifdef __clang__+#pragma clang diagnostic push+#pragma clang diagnostic ignored "-Wweak-vtables"+#endif++// Keep these here for external reporters+// start catch_test_case_tracker.h++#include <string>+#include <vector>+#include <memory>++namespace Catch {+namespace TestCaseTracking {++ struct NameAndLocation {+ std::string name;+ SourceLineInfo location;++ NameAndLocation( std::string const& _name, SourceLineInfo const& _location );+ friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {+ return lhs.name == rhs.name+ && lhs.location == rhs.location;+ }+ };++ class ITracker;++ using ITrackerPtr = std::shared_ptr<ITracker>;++ class ITracker {+ NameAndLocation m_nameAndLocation;++ public:+ ITracker(NameAndLocation const& nameAndLoc) :+ m_nameAndLocation(nameAndLoc)+ {}++ // static queries+ NameAndLocation const& nameAndLocation() const {+ return m_nameAndLocation;+ }++ virtual ~ITracker();++ // dynamic queries+ virtual bool isComplete() const = 0; // Successfully completed or failed+ virtual bool isSuccessfullyCompleted() const = 0;+ virtual bool isOpen() const = 0; // Started but not complete+ virtual bool hasChildren() const = 0;+ virtual bool hasStarted() const = 0;++ virtual ITracker& parent() = 0;++ // actions+ virtual void close() = 0; // Successfully complete+ virtual void fail() = 0;+ virtual void markAsNeedingAnotherRun() = 0;++ virtual void addChild( ITrackerPtr const& child ) = 0;+ virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0;+ virtual void openChild() = 0;++ // Debug/ checking+ virtual bool isSectionTracker() const = 0;+ virtual bool isGeneratorTracker() const = 0;+ };++ class TrackerContext {++ enum RunState {+ NotStarted,+ Executing,+ CompletedCycle+ };++ ITrackerPtr m_rootTracker;+ ITracker* m_currentTracker = nullptr;+ RunState m_runState = NotStarted;++ public:++ ITracker& startRun();+ void endRun();++ void startCycle();+ void completeCycle();++ bool completedCycle() const;+ ITracker& currentTracker();+ void setCurrentTracker( ITracker* tracker );+ };++ class TrackerBase : public ITracker {+ protected:+ enum CycleState {+ NotStarted,+ Executing,+ ExecutingChildren,+ NeedsAnotherRun,+ CompletedSuccessfully,+ Failed+ };++ using Children = std::vector<ITrackerPtr>;+ TrackerContext& m_ctx;+ ITracker* m_parent;+ Children m_children;+ CycleState m_runState = NotStarted;++ public:+ TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );++ bool isComplete() const override;+ bool isSuccessfullyCompleted() const override;+ bool isOpen() const override;+ bool hasChildren() const override;+ bool hasStarted() const override {+ return m_runState != NotStarted;+ }++ void addChild( ITrackerPtr const& child ) override;++ ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override;+ ITracker& parent() override;++ void openChild() override;++ bool isSectionTracker() const override;+ bool isGeneratorTracker() const override;++ void open();++ void close() override;+ void fail() override;+ void markAsNeedingAnotherRun() override;++ private:+ void moveToParent();+ void moveToThis();+ };++ class SectionTracker : public TrackerBase {+ std::vector<std::string> m_filters;+ std::string m_trimmed_name;+ public:+ SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );++ bool isSectionTracker() const override;++ bool isComplete() const override;++ static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );++ void tryOpen();++ void addInitialFilters( std::vector<std::string> const& filters );+ void addNextFilters( std::vector<std::string> const& filters );+ //! Returns filters active in this tracker+ std::vector<std::string> const& getFilters() const;+ //! Returns whitespace-trimmed name of the tracked section+ std::string const& trimmedName() const;+ };++} // namespace TestCaseTracking++using TestCaseTracking::ITracker;+using TestCaseTracking::TrackerContext;+using TestCaseTracking::SectionTracker;++} // namespace Catch++// end catch_test_case_tracker.h++// start catch_leak_detector.h++namespace Catch {++ struct LeakDetector {+ LeakDetector();+ ~LeakDetector();+ };++}+// end catch_leak_detector.h+// Cpp files will be included in the single-header file here+// start catch_stats.cpp++// Statistical analysis tools++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)++#include <cassert>+#include <random>++#if defined(CATCH_CONFIG_USE_ASYNC)+#include <future>+#endif++namespace {+ double erf_inv(double x) {+ // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2+ double w, p;++ w = -log((1.0 - x) * (1.0 + x));++ if (w < 6.250000) {+ w = w - 3.125000;+ p = -3.6444120640178196996e-21;+ p = -1.685059138182016589e-19 + p * w;+ p = 1.2858480715256400167e-18 + p * w;+ p = 1.115787767802518096e-17 + p * w;+ p = -1.333171662854620906e-16 + p * w;+ p = 2.0972767875968561637e-17 + p * w;+ p = 6.6376381343583238325e-15 + p * w;+ p = -4.0545662729752068639e-14 + p * w;+ p = -8.1519341976054721522e-14 + p * w;+ p = 2.6335093153082322977e-12 + p * w;+ p = -1.2975133253453532498e-11 + p * w;+ p = -5.4154120542946279317e-11 + p * w;+ p = 1.051212273321532285e-09 + p * w;+ p = -4.1126339803469836976e-09 + p * w;+ p = -2.9070369957882005086e-08 + p * w;+ p = 4.2347877827932403518e-07 + p * w;+ p = -1.3654692000834678645e-06 + p * w;+ p = -1.3882523362786468719e-05 + p * w;+ p = 0.0001867342080340571352 + p * w;+ p = -0.00074070253416626697512 + p * w;+ p = -0.0060336708714301490533 + p * w;+ p = 0.24015818242558961693 + p * w;+ p = 1.6536545626831027356 + p * w;+ } else if (w < 16.000000) {+ w = sqrt(w) - 3.250000;+ p = 2.2137376921775787049e-09;+ p = 9.0756561938885390979e-08 + p * w;+ p = -2.7517406297064545428e-07 + p * w;+ p = 1.8239629214389227755e-08 + p * w;+ p = 1.5027403968909827627e-06 + p * w;+ p = -4.013867526981545969e-06 + p * w;+ p = 2.9234449089955446044e-06 + p * w;+ p = 1.2475304481671778723e-05 + p * w;+ p = -4.7318229009055733981e-05 + p * w;+ p = 6.8284851459573175448e-05 + p * w;+ p = 2.4031110387097893999e-05 + p * w;+ p = -0.0003550375203628474796 + p * w;+ p = 0.00095328937973738049703 + p * w;+ p = -0.0016882755560235047313 + p * w;+ p = 0.0024914420961078508066 + p * w;+ p = -0.0037512085075692412107 + p * w;+ p = 0.005370914553590063617 + p * w;+ p = 1.0052589676941592334 + p * w;+ p = 3.0838856104922207635 + p * w;+ } else {+ w = sqrt(w) - 5.000000;+ p = -2.7109920616438573243e-11;+ p = -2.5556418169965252055e-10 + p * w;+ p = 1.5076572693500548083e-09 + p * w;+ p = -3.7894654401267369937e-09 + p * w;+ p = 7.6157012080783393804e-09 + p * w;+ p = -1.4960026627149240478e-08 + p * w;+ p = 2.9147953450901080826e-08 + p * w;+ p = -6.7711997758452339498e-08 + p * w;+ p = 2.2900482228026654717e-07 + p * w;+ p = -9.9298272942317002539e-07 + p * w;+ p = 4.5260625972231537039e-06 + p * w;+ p = -1.9681778105531670567e-05 + p * w;+ p = 7.5995277030017761139e-05 + p * w;+ p = -0.00021503011930044477347 + p * w;+ p = -0.00013871931833623122026 + p * w;+ p = 1.0103004648645343977 + p * w;+ p = 4.8499064014085844221 + p * w;+ }+ return p * x;+ }++ double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) {+ auto m = Catch::Benchmark::Detail::mean(first, last);+ double variance = std::accumulate(first, last, 0., [m](double a, double b) {+ double diff = b - m;+ return a + diff * diff;+ }) / (last - first);+ return std::sqrt(variance);+ }++}++namespace Catch {+ namespace Benchmark {+ namespace Detail {++ double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) {+ auto count = last - first;+ double idx = (count - 1) * k / static_cast<double>(q);+ int j = static_cast<int>(idx);+ double g = idx - j;+ std::nth_element(first, first + j, last);+ auto xj = first[j];+ if (g == 0) return xj;++ auto xj1 = *std::min_element(first + (j + 1), last);+ return xj + g * (xj1 - xj);+ }++ double erfc_inv(double x) {+ return erf_inv(1.0 - x);+ }++ double normal_quantile(double p) {+ static const double ROOT_TWO = std::sqrt(2.0);++ double result = 0.0;+ assert(p >= 0 && p <= 1);+ if (p < 0 || p > 1) {+ return result;+ }++ result = -erfc_inv(2.0 * p);+ // result *= normal distribution standard deviation (1.0) * sqrt(2)+ result *= /*sd * */ ROOT_TWO;+ // result += normal disttribution mean (0)+ return result;+ }++ double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) {+ double sb = stddev.point;+ double mn = mean.point / n;+ double mg_min = mn / 2.;+ double sg = (std::min)(mg_min / 4., sb / std::sqrt(n));+ double sg2 = sg * sg;+ double sb2 = sb * sb;++ auto c_max = [n, mn, sb2, sg2](double x) -> double {+ double k = mn - x;+ double d = k * k;+ double nd = n * d;+ double k0 = -n * nd;+ double k1 = sb2 - n * sg2 + nd;+ double det = k1 * k1 - 4 * sg2 * k0;+ return (int)(-2. * k0 / (k1 + std::sqrt(det)));+ };++ auto var_out = [n, sb2, sg2](double c) {+ double nc = n - c;+ return (nc / n) * (sb2 - nc * sg2);+ };++ return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2;+ }++ bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS+ static std::random_device entropy;+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION++ auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++++ auto mean = &Detail::mean<std::vector<double>::iterator>;+ auto stddev = &standard_deviation;++#if defined(CATCH_CONFIG_USE_ASYNC)+ auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {+ auto seed = entropy();+ return std::async(std::launch::async, [=] {+ std::mt19937 rng(seed);+ auto resampled = resample(rng, n_resamples, first, last, f);+ return bootstrap(confidence_level, first, last, resampled, f);+ });+ };++ auto mean_future = Estimate(mean);+ auto stddev_future = Estimate(stddev);++ auto mean_estimate = mean_future.get();+ auto stddev_estimate = stddev_future.get();+#else+ auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {+ auto seed = entropy();+ std::mt19937 rng(seed);+ auto resampled = resample(rng, n_resamples, first, last, f);+ return bootstrap(confidence_level, first, last, resampled, f);+ };++ auto mean_estimate = Estimate(mean);+ auto stddev_estimate = Estimate(stddev);+#endif // CATCH_USE_ASYNC++ double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);++ return { mean_estimate, stddev_estimate, outlier_variance };+ }+ } // namespace Detail+ } // namespace Benchmark+} // namespace Catch++#endif // CATCH_CONFIG_ENABLE_BENCHMARKING+// end catch_stats.cpp+// start catch_approx.cpp++#include <cmath>+#include <limits>++namespace {++// Performs equivalent check of std::fabs(lhs - rhs) <= margin+// But without the subtraction to allow for INFINITY in comparison+bool marginComparison(double lhs, double rhs, double margin) {+ return (lhs + margin >= rhs) && (rhs + margin >= lhs);+}++}++namespace Catch {+namespace Detail {++ Approx::Approx ( double value )+ : m_epsilon( std::numeric_limits<float>::epsilon()*100 ),+ m_margin( 0.0 ),+ m_scale( 0.0 ),+ m_value( value )+ {}++ Approx Approx::custom() {+ return Approx( 0 );+ }++ Approx Approx::operator-() const {+ auto temp(*this);+ temp.m_value = -temp.m_value;+ return temp;+ }++ std::string Approx::toString() const {+ ReusableStringStream rss;+ rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";+ return rss.str();+ }++ bool Approx::equalityComparisonImpl(const double other) const {+ // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value+ // Thanks to Richard Harris for his help refining the scaled margin value+ return marginComparison(m_value, other, m_margin)+ || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));+ }++ void Approx::setMargin(double newMargin) {+ CATCH_ENFORCE(newMargin >= 0,+ "Invalid Approx::margin: " << newMargin << '.'+ << " Approx::Margin has to be non-negative.");+ m_margin = newMargin;+ }++ void Approx::setEpsilon(double newEpsilon) {+ CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,+ "Invalid Approx::epsilon: " << newEpsilon << '.'+ << " Approx::epsilon has to be in [0, 1]");+ m_epsilon = newEpsilon;+ }++} // end namespace Detail++namespace literals {+ Detail::Approx operator "" _a(long double val) {+ return Detail::Approx(val);+ }+ Detail::Approx operator "" _a(unsigned long long val) {+ return Detail::Approx(val);+ }+} // end namespace literals++std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {+ return value.toString();+}++} // end namespace Catch+// end catch_approx.cpp+// start catch_assertionhandler.cpp++// start catch_debugger.h++namespace Catch {+ bool isDebuggerActive();+}++#ifdef CATCH_PLATFORM_MAC++ #if defined(__i386__) || defined(__x86_64__)+ #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */+ #elif defined(__aarch64__)+ #define CATCH_TRAP() __asm__(".inst 0xd4200000")+ #endif++#elif defined(CATCH_PLATFORM_IPHONE)++ // use inline assembler+ #if defined(__i386__) || defined(__x86_64__)+ #define CATCH_TRAP() __asm__("int $3")+ #elif defined(__aarch64__)+ #define CATCH_TRAP() __asm__(".inst 0xd4200000")+ #elif defined(__arm__) && !defined(__thumb__)+ #define CATCH_TRAP() __asm__(".inst 0xe7f001f0")+ #elif defined(__arm__) && defined(__thumb__)+ #define CATCH_TRAP() __asm__(".inst 0xde01")+ #endif++#elif defined(CATCH_PLATFORM_LINUX)+ // If we can use inline assembler, do it because this allows us to break+ // directly at the location of the failing check instead of breaking inside+ // raise() called from it, i.e. one stack frame below.+ #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))+ #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */+ #else // Fall back to the generic way.+ #include <signal.h>++ #define CATCH_TRAP() raise(SIGTRAP)+ #endif+#elif defined(_MSC_VER)+ #define CATCH_TRAP() __debugbreak()+#elif defined(__MINGW32__)+ extern "C" __declspec(dllimport) void __stdcall DebugBreak();+ #define CATCH_TRAP() DebugBreak()+#endif++#ifndef CATCH_BREAK_INTO_DEBUGGER+ #ifdef CATCH_TRAP+ #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()+ #else+ #define CATCH_BREAK_INTO_DEBUGGER() []{}()+ #endif+#endif++// end catch_debugger.h+// start catch_run_context.h++// start catch_fatal_condition.h++#include <cassert>++namespace Catch {++ // Wrapper for platform-specific fatal error (signals/SEH) handlers+ //+ // Tries to be cooperative with other handlers, and not step over+ // other handlers. This means that unknown structured exceptions+ // are passed on, previous signal handlers are called, and so on.+ //+ // Can only be instantiated once, and assumes that once a signal+ // is caught, the binary will end up terminating. Thus, there+ class FatalConditionHandler {+ bool m_started = false;++ // Install/disengage implementation for specific platform.+ // Should be if-defed to work on current platform, can assume+ // engage-disengage 1:1 pairing.+ void engage_platform();+ void disengage_platform();+ public:+ // Should also have platform-specific implementations as needed+ FatalConditionHandler();+ ~FatalConditionHandler();++ void engage() {+ assert(!m_started && "Handler cannot be installed twice.");+ m_started = true;+ engage_platform();+ }++ void disengage() {+ assert(m_started && "Handler cannot be uninstalled without being installed first");+ m_started = false;+ disengage_platform();+ }+ };++ //! Simple RAII guard for (dis)engaging the FatalConditionHandler+ class FatalConditionHandlerGuard {+ FatalConditionHandler* m_handler;+ public:+ FatalConditionHandlerGuard(FatalConditionHandler* handler):+ m_handler(handler) {+ m_handler->engage();+ }+ ~FatalConditionHandlerGuard() {+ m_handler->disengage();+ }+ };++} // end namespace Catch++// end catch_fatal_condition.h+#include <string>++namespace Catch {++ struct IMutableContext;++ ///////////////////////////////////////////////////////////////////////////++ class RunContext : public IResultCapture, public IRunner {++ public:+ RunContext( RunContext const& ) = delete;+ RunContext& operator =( RunContext const& ) = delete;++ explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter );++ ~RunContext() override;++ void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount );+ void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount );++ Totals runTest(TestCase const& testCase);++ IConfigPtr config() const;+ IStreamingReporter& reporter() const;++ public: // IResultCapture++ // Assertion handlers+ void handleExpr+ ( AssertionInfo const& info,+ ITransientExpression const& expr,+ AssertionReaction& reaction ) override;+ void handleMessage+ ( AssertionInfo const& info,+ ResultWas::OfType resultType,+ StringRef const& message,+ AssertionReaction& reaction ) override;+ void handleUnexpectedExceptionNotThrown+ ( AssertionInfo const& info,+ AssertionReaction& reaction ) override;+ void handleUnexpectedInflightException+ ( AssertionInfo const& info,+ std::string const& message,+ AssertionReaction& reaction ) override;+ void handleIncomplete+ ( AssertionInfo const& info ) override;+ void handleNonExpr+ ( AssertionInfo const &info,+ ResultWas::OfType resultType,+ AssertionReaction &reaction ) override;++ bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;++ void sectionEnded( SectionEndInfo const& endInfo ) override;+ void sectionEndedEarly( SectionEndInfo const& endInfo ) override;++ auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+ void benchmarkPreparing( std::string const& name ) override;+ void benchmarkStarting( BenchmarkInfo const& info ) override;+ void benchmarkEnded( BenchmarkStats<> const& stats ) override;+ void benchmarkFailed( std::string const& error ) override;+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++ void pushScopedMessage( MessageInfo const& message ) override;+ void popScopedMessage( MessageInfo const& message ) override;++ void emplaceUnscopedMessage( MessageBuilder const& builder ) override;++ std::string getCurrentTestName() const override;++ const AssertionResult* getLastResult() const override;++ void exceptionEarlyReported() override;++ void handleFatalErrorCondition( StringRef message ) override;++ bool lastAssertionPassed() override;++ void assertionPassed() override;++ public:+ // !TBD We need to do this another way!+ bool aborting() const final;++ private:++ void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr );+ void invokeActiveTestCase();++ void resetAssertionInfo();+ bool testForMissingAssertions( Counts& assertions );++ void assertionEnded( AssertionResult const& result );+ void reportExpr+ ( AssertionInfo const &info,+ ResultWas::OfType resultType,+ ITransientExpression const *expr,+ bool negated );++ void populateReaction( AssertionReaction& reaction );++ private:++ void handleUnfinishedSections();++ TestRunInfo m_runInfo;+ IMutableContext& m_context;+ TestCase const* m_activeTestCase = nullptr;+ ITracker* m_testCaseTracker = nullptr;+ Option<AssertionResult> m_lastResult;++ IConfigPtr m_config;+ Totals m_totals;+ IStreamingReporterPtr m_reporter;+ std::vector<MessageInfo> m_messages;+ std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */+ AssertionInfo m_lastAssertionInfo;+ std::vector<SectionEndInfo> m_unfinishedSections;+ std::vector<ITracker*> m_activeSections;+ TrackerContext m_trackerContext;+ FatalConditionHandler m_fatalConditionhandler;+ bool m_lastAssertionPassed = false;+ bool m_shouldReportUnexpected = true;+ bool m_includeSuccessfulResults;+ };++ void seedRng(IConfig const& config);+ unsigned int rngSeed();+} // end namespace Catch++// end catch_run_context.h+namespace Catch {++ namespace {+ auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {+ expr.streamReconstructedExpression( os );+ return os;+ }+ }++ LazyExpression::LazyExpression( bool isNegated )+ : m_isNegated( isNegated )+ {}++ LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {}++ LazyExpression::operator bool() const {+ return m_transientExpression != nullptr;+ }++ auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& {+ if( lazyExpr.m_isNegated )+ os << "!";++ if( lazyExpr ) {+ if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() )+ os << "(" << *lazyExpr.m_transientExpression << ")";+ else+ os << *lazyExpr.m_transientExpression;+ }+ else {+ os << "{** error - unchecked empty expression requested **}";+ }+ return os;+ }++ AssertionHandler::AssertionHandler+ ( StringRef const& macroName,+ SourceLineInfo const& lineInfo,+ StringRef capturedExpression,+ ResultDisposition::Flags resultDisposition )+ : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },+ m_resultCapture( getResultCapture() )+ {}++ void AssertionHandler::handleExpr( ITransientExpression const& expr ) {+ m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );+ }+ void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) {+ m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );+ }++ auto AssertionHandler::allowThrows() const -> bool {+ return getCurrentContext().getConfig()->allowThrows();+ }++ void AssertionHandler::complete() {+ setCompleted();+ if( m_reaction.shouldDebugBreak ) {++ // If you find your debugger stopping you here then go one level up on the+ // call-stack for the code that caused it (typically a failed assertion)++ // (To go back to the test and change execution, jump over the throw, next)+ CATCH_BREAK_INTO_DEBUGGER();+ }+ if (m_reaction.shouldThrow) {+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+ throw Catch::TestFailureException();+#else+ CATCH_ERROR( "Test failure requires aborting test!" );+#endif+ }+ }+ void AssertionHandler::setCompleted() {+ m_completed = true;+ }++ void AssertionHandler::handleUnexpectedInflightException() {+ m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );+ }++ void AssertionHandler::handleExceptionThrownAsExpected() {+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);+ }+ void AssertionHandler::handleExceptionNotThrownAsExpected() {+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);+ }++ void AssertionHandler::handleUnexpectedExceptionNotThrown() {+ m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );+ }++ void AssertionHandler::handleThrowingCallSkipped() {+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);+ }++ // This is the overload that takes a string and infers the Equals matcher from it+ // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp+ void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) {+ handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );+ }++} // namespace Catch+// end catch_assertionhandler.cpp+// start catch_assertionresult.cpp++namespace Catch {+ AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression):+ lazyExpression(_lazyExpression),+ resultType(_resultType) {}++ std::string AssertionResultData::reconstructExpression() const {++ if( reconstructedExpression.empty() ) {+ if( lazyExpression ) {+ ReusableStringStream rss;+ rss << lazyExpression;+ reconstructedExpression = rss.str();+ }+ }+ return reconstructedExpression;+ }++ AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )+ : m_info( info ),+ m_resultData( data )+ {}++ // Result was a success+ bool AssertionResult::succeeded() const {+ return Catch::isOk( m_resultData.resultType );+ }++ // Result was a success, or failure is suppressed+ bool AssertionResult::isOk() const {+ return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );+ }++ ResultWas::OfType AssertionResult::getResultType() const {+ return m_resultData.resultType;+ }++ bool AssertionResult::hasExpression() const {+ return !m_info.capturedExpression.empty();+ }++ bool AssertionResult::hasMessage() const {+ return !m_resultData.message.empty();+ }++ std::string AssertionResult::getExpression() const {+ // Possibly overallocating by 3 characters should be basically free+ std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);+ if (isFalseTest(m_info.resultDisposition)) {+ expr += "!(";+ }+ expr += m_info.capturedExpression;+ if (isFalseTest(m_info.resultDisposition)) {+ expr += ')';+ }+ return expr;+ }++ std::string AssertionResult::getExpressionInMacro() const {+ std::string expr;+ if( m_info.macroName.empty() )+ expr = static_cast<std::string>(m_info.capturedExpression);+ else {+ expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );+ expr += m_info.macroName;+ expr += "( ";+ expr += m_info.capturedExpression;+ expr += " )";+ }+ return expr;+ }++ bool AssertionResult::hasExpandedExpression() const {+ return hasExpression() && getExpandedExpression() != getExpression();+ }++ std::string AssertionResult::getExpandedExpression() const {+ std::string expr = m_resultData.reconstructExpression();+ return expr.empty()+ ? getExpression()+ : expr;+ }++ std::string AssertionResult::getMessage() const {+ return m_resultData.message;+ }+ SourceLineInfo AssertionResult::getSourceInfo() const {+ return m_info.lineInfo;+ }++ StringRef AssertionResult::getTestMacroName() const {+ return m_info.macroName;+ }++} // end namespace Catch+// end catch_assertionresult.cpp+// start catch_capture_matchers.cpp++namespace Catch {++ using StringMatcher = Matchers::Impl::MatcherBase<std::string>;++ // This is the general overload that takes a any string matcher+ // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers+ // the Equals matcher (so the header does not mention matchers)+ void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) {+ std::string exceptionMessage = Catch::translateActiveException();+ MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );+ handler.handleExpr( expr );+ }++} // namespace Catch+// end catch_capture_matchers.cpp+// start catch_commandline.cpp++// start catch_commandline.h++// start catch_clara.h++// Use Catch's value for console width (store Clara's off to the side, if present)+#ifdef CLARA_CONFIG_CONSOLE_WIDTH+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH+#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH+#endif+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1++#ifdef __clang__+#pragma clang diagnostic push+#pragma clang diagnostic ignored "-Wweak-vtables"+#pragma clang diagnostic ignored "-Wexit-time-destructors"+#pragma clang diagnostic ignored "-Wshadow"+#endif++// start clara.hpp+// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.+//+// 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)+//+// See https://github.com/philsquared/Clara for more details++// Clara v1.1.5+++#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH+#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80+#endif++#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH+#endif++#ifndef CLARA_CONFIG_OPTIONAL_TYPE+#ifdef __has_include+#if __has_include(<optional>) && __cplusplus >= 201703L+#include <optional>+#define CLARA_CONFIG_OPTIONAL_TYPE std::optional+#endif+#endif+#endif++// ----------- #included from clara_textflow.hpp -----------++// TextFlowCpp+//+// A single-header library for wrapping and laying out basic text, by Phil Nash+//+// Distributed under the Boost Software License, Version 1.0. (See accompanying+// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)+//+// This project is hosted at https://github.com/philsquared/textflowcpp+++#include <cassert>+#include <ostream>+#include <sstream>+#include <vector>++#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80+#endif++namespace Catch {+namespace clara {+namespace TextFlow {++inline auto isWhitespace(char c) -> bool {+ static std::string chars = " \t\n\r";+ return chars.find(c) != std::string::npos;+}+inline auto isBreakableBefore(char c) -> bool {+ static std::string chars = "[({<|";+ return chars.find(c) != std::string::npos;+}+inline auto isBreakableAfter(char c) -> bool {+ static std::string chars = "])}>.,:;*+-=&/\\";+ return chars.find(c) != std::string::npos;+}++class Columns;++class Column {+ std::vector<std::string> m_strings;+ size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;+ size_t m_indent = 0;+ size_t m_initialIndent = std::string::npos;++public:+ class iterator {+ friend Column;++ Column const& m_column;+ size_t m_stringIndex = 0;+ size_t m_pos = 0;++ size_t m_len = 0;+ size_t m_end = 0;+ bool m_suffix = false;++ iterator(Column const& column, size_t stringIndex)+ : m_column(column),+ m_stringIndex(stringIndex) {}++ auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }++ auto isBoundary(size_t at) const -> bool {+ assert(at > 0);+ assert(at <= line().size());++ return at == line().size() ||+ (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) ||+ isBreakableBefore(line()[at]) ||+ isBreakableAfter(line()[at - 1]);+ }++ void calcLength() {+ assert(m_stringIndex < m_column.m_strings.size());++ m_suffix = false;+ auto width = m_column.m_width - indent();+ m_end = m_pos;+ if (line()[m_pos] == '\n') {+ ++m_end;+ }+ while (m_end < line().size() && line()[m_end] != '\n')+ ++m_end;++ if (m_end < m_pos + width) {+ m_len = m_end - m_pos;+ } else {+ size_t len = width;+ while (len > 0 && !isBoundary(m_pos + len))+ --len;+ while (len > 0 && isWhitespace(line()[m_pos + len - 1]))+ --len;++ if (len > 0) {+ m_len = len;+ } else {+ m_suffix = true;+ m_len = width - 1;+ }+ }+ }++ auto indent() const -> size_t {+ auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;+ return initial == std::string::npos ? m_column.m_indent : initial;+ }++ auto addIndentAndSuffix(std::string const &plain) const -> std::string {+ return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain);+ }++ public:+ using difference_type = std::ptrdiff_t;+ using value_type = std::string;+ using pointer = value_type * ;+ using reference = value_type & ;+ using iterator_category = std::forward_iterator_tag;++ explicit iterator(Column const& column) : m_column(column) {+ assert(m_column.m_width > m_column.m_indent);+ assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent);+ calcLength();+ if (m_len == 0)+ m_stringIndex++; // Empty string+ }++ auto operator *() const -> std::string {+ assert(m_stringIndex < m_column.m_strings.size());+ assert(m_pos <= m_end);+ return addIndentAndSuffix(line().substr(m_pos, m_len));+ }++ auto operator ++() -> iterator& {+ m_pos += m_len;+ if (m_pos < line().size() && line()[m_pos] == '\n')+ m_pos += 1;+ else+ while (m_pos < line().size() && isWhitespace(line()[m_pos]))+ ++m_pos;++ if (m_pos == line().size()) {+ m_pos = 0;+ ++m_stringIndex;+ }+ if (m_stringIndex < m_column.m_strings.size())+ calcLength();+ return *this;+ }+ auto operator ++(int) -> iterator {+ iterator prev(*this);+ operator++();+ return prev;+ }++ auto operator ==(iterator const& other) const -> bool {+ return+ m_pos == other.m_pos &&+ m_stringIndex == other.m_stringIndex &&+ &m_column == &other.m_column;+ }+ auto operator !=(iterator const& other) const -> bool {+ return !operator==(other);+ }+ };+ using const_iterator = iterator;++ explicit Column(std::string const& text) { m_strings.push_back(text); }++ auto width(size_t newWidth) -> Column& {+ assert(newWidth > 0);+ m_width = newWidth;+ return *this;+ }+ auto indent(size_t newIndent) -> Column& {+ m_indent = newIndent;+ return *this;+ }+ auto initialIndent(size_t newIndent) -> Column& {+ m_initialIndent = newIndent;+ return *this;+ }++ auto width() const -> size_t { return m_width; }+ auto begin() const -> iterator { return iterator(*this); }+ auto end() const -> iterator { return { *this, m_strings.size() }; }++ inline friend std::ostream& operator << (std::ostream& os, Column const& col) {+ bool first = true;+ for (auto line : col) {+ if (first)+ first = false;+ else+ os << "\n";+ os << line;+ }+ return os;+ }++ auto operator + (Column const& other)->Columns;++ auto toString() const -> std::string {+ std::ostringstream oss;+ oss << *this;+ return oss.str();+ }+};++class Spacer : public Column {++public:+ explicit Spacer(size_t spaceWidth) : Column("") {+ width(spaceWidth);+ }+};++class Columns {+ std::vector<Column> m_columns;++public:++ class iterator {+ friend Columns;+ struct EndTag {};++ std::vector<Column> const& m_columns;+ std::vector<Column::iterator> m_iterators;+ size_t m_activeIterators;++ iterator(Columns const& columns, EndTag)+ : m_columns(columns.m_columns),+ m_activeIterators(0) {+ m_iterators.reserve(m_columns.size());++ for (auto const& col : m_columns)+ m_iterators.push_back(col.end());+ }++ public:+ using difference_type = std::ptrdiff_t;+ using value_type = std::string;+ using pointer = value_type * ;+ using reference = value_type & ;+ using iterator_category = std::forward_iterator_tag;++ explicit iterator(Columns const& columns)+ : m_columns(columns.m_columns),+ m_activeIterators(m_columns.size()) {+ m_iterators.reserve(m_columns.size());++ for (auto const& col : m_columns)+ m_iterators.push_back(col.begin());+ }++ auto operator ==(iterator const& other) const -> bool {+ return m_iterators == other.m_iterators;+ }+ auto operator !=(iterator const& other) const -> bool {+ return m_iterators != other.m_iterators;+ }+ auto operator *() const -> std::string {+ std::string row, padding;++ for (size_t i = 0; i < m_columns.size(); ++i) {+ auto width = m_columns[i].width();+ if (m_iterators[i] != m_columns[i].end()) {+ std::string col = *m_iterators[i];+ row += padding + col;+ if (col.size() < width)+ padding = std::string(width - col.size(), ' ');+ else+ padding = "";+ } else {+ padding += std::string(width, ' ');+ }+ }+ return row;+ }+ auto operator ++() -> iterator& {+ for (size_t i = 0; i < m_columns.size(); ++i) {+ if (m_iterators[i] != m_columns[i].end())+ ++m_iterators[i];+ }+ return *this;+ }+ auto operator ++(int) -> iterator {+ iterator prev(*this);+ operator++();+ return prev;+ }+ };+ using const_iterator = iterator;++ auto begin() const -> iterator { return iterator(*this); }+ auto end() const -> iterator { return { *this, iterator::EndTag() }; }++ auto operator += (Column const& col) -> Columns& {+ m_columns.push_back(col);+ return *this;+ }+ auto operator + (Column const& col) -> Columns {+ Columns combined = *this;+ combined += col;+ return combined;+ }++ inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) {++ bool first = true;+ for (auto line : cols) {+ if (first)+ first = false;+ else+ os << "\n";+ os << line;+ }+ return os;+ }++ auto toString() const -> std::string {+ std::ostringstream oss;+ oss << *this;+ return oss.str();+ }+};++inline auto Column::operator + (Column const& other) -> Columns {+ Columns cols;+ cols += *this;+ cols += other;+ return cols;+}+}++}+}++// ----------- end of #include from clara_textflow.hpp -----------+// ........... back in clara.hpp++#include <cctype>+#include <string>+#include <memory>+#include <set>+#include <algorithm>++#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )+#define CATCH_PLATFORM_WINDOWS+#endif++namespace Catch { namespace clara {+namespace detail {++ // Traits for extracting arg and return type of lambdas (for single argument lambdas)+ template<typename L>+ struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};++ template<typename ClassT, typename ReturnT, typename... Args>+ struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {+ static const bool isValid = false;+ };++ template<typename ClassT, typename ReturnT, typename ArgT>+ struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {+ static const bool isValid = true;+ using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;+ using ReturnType = ReturnT;+ };++ class TokenStream;++ // Transport for raw args (copied from main args, or supplied via init list for testing)+ class Args {+ friend TokenStream;+ std::string m_exeName;+ std::vector<std::string> m_args;++ public:+ Args( int argc, char const* const* argv )+ : m_exeName(argv[0]),+ m_args(argv + 1, argv + argc) {}++ Args( std::initializer_list<std::string> args )+ : m_exeName( *args.begin() ),+ m_args( args.begin()+1, args.end() )+ {}++ auto exeName() const -> std::string {+ return m_exeName;+ }+ };++ // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string+ // may encode an option + its argument if the : or = form is used+ enum class TokenType {+ Option, Argument+ };+ struct Token {+ TokenType type;+ std::string token;+ };++ inline auto isOptPrefix( char c ) -> bool {+ return c == '-'+#ifdef CATCH_PLATFORM_WINDOWS+ || c == '/'+#endif+ ;+ }++ // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled+ class TokenStream {+ using Iterator = std::vector<std::string>::const_iterator;+ Iterator it;+ Iterator itEnd;+ std::vector<Token> m_tokenBuffer;++ void loadBuffer() {+ m_tokenBuffer.resize( 0 );++ // Skip any empty strings+ while( it != itEnd && it->empty() )+ ++it;++ if( it != itEnd ) {+ auto const &next = *it;+ if( isOptPrefix( next[0] ) ) {+ auto delimiterPos = next.find_first_of( " :=" );+ if( delimiterPos != std::string::npos ) {+ m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );+ m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );+ } else {+ if( next[1] != '-' && next.size() > 2 ) {+ std::string opt = "- ";+ for( size_t i = 1; i < next.size(); ++i ) {+ opt[1] = next[i];+ m_tokenBuffer.push_back( { TokenType::Option, opt } );+ }+ } else {+ m_tokenBuffer.push_back( { TokenType::Option, next } );+ }+ }+ } else {+ m_tokenBuffer.push_back( { TokenType::Argument, next } );+ }+ }+ }++ public:+ explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {}++ TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) {+ loadBuffer();+ }++ explicit operator bool() const {+ return !m_tokenBuffer.empty() || it != itEnd;+ }++ auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }++ auto operator*() const -> Token {+ assert( !m_tokenBuffer.empty() );+ return m_tokenBuffer.front();+ }++ auto operator->() const -> Token const * {+ assert( !m_tokenBuffer.empty() );+ return &m_tokenBuffer.front();+ }++ auto operator++() -> TokenStream & {+ if( m_tokenBuffer.size() >= 2 ) {+ m_tokenBuffer.erase( m_tokenBuffer.begin() );+ } else {+ if( it != itEnd )+ ++it;+ loadBuffer();+ }+ return *this;+ }+ };++ class ResultBase {+ public:+ enum Type {+ Ok, LogicError, RuntimeError+ };++ protected:+ ResultBase( Type type ) : m_type( type ) {}+ virtual ~ResultBase() = default;++ virtual void enforceOk() const = 0;++ Type m_type;+ };++ template<typename T>+ class ResultValueBase : public ResultBase {+ public:+ auto value() const -> T const & {+ enforceOk();+ return m_value;+ }++ protected:+ ResultValueBase( Type type ) : ResultBase( type ) {}++ ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {+ if( m_type == ResultBase::Ok )+ new( &m_value ) T( other.m_value );+ }++ ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {+ new( &m_value ) T( value );+ }++ auto operator=( ResultValueBase const &other ) -> ResultValueBase & {+ if( m_type == ResultBase::Ok )+ m_value.~T();+ ResultBase::operator=(other);+ if( m_type == ResultBase::Ok )+ new( &m_value ) T( other.m_value );+ return *this;+ }++ ~ResultValueBase() override {+ if( m_type == Ok )+ m_value.~T();+ }++ union {+ T m_value;+ };+ };++ template<>+ class ResultValueBase<void> : public ResultBase {+ protected:+ using ResultBase::ResultBase;+ };++ template<typename T = void>+ class BasicResult : public ResultValueBase<T> {+ public:+ template<typename U>+ explicit BasicResult( BasicResult<U> const &other )+ : ResultValueBase<T>( other.type() ),+ m_errorMessage( other.errorMessage() )+ {+ assert( type() != ResultBase::Ok );+ }++ template<typename U>+ static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; }+ static auto ok() -> BasicResult { return { ResultBase::Ok }; }+ static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }+ static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }++ explicit operator bool() const { return m_type == ResultBase::Ok; }+ auto type() const -> ResultBase::Type { return m_type; }+ auto errorMessage() const -> std::string { return m_errorMessage; }++ protected:+ void enforceOk() const override {++ // Errors shouldn't reach this point, but if they do+ // the actual error message will be in m_errorMessage+ assert( m_type != ResultBase::LogicError );+ assert( m_type != ResultBase::RuntimeError );+ if( m_type != ResultBase::Ok )+ std::abort();+ }++ std::string m_errorMessage; // Only populated if resultType is an error++ BasicResult( ResultBase::Type type, std::string const &message )+ : ResultValueBase<T>(type),+ m_errorMessage(message)+ {+ assert( m_type != ResultBase::Ok );+ }++ using ResultValueBase<T>::ResultValueBase;+ using ResultBase::m_type;+ };++ enum class ParseResultType {+ Matched, NoMatch, ShortCircuitAll, ShortCircuitSame+ };++ class ParseState {+ public:++ ParseState( ParseResultType type, TokenStream const &remainingTokens )+ : m_type(type),+ m_remainingTokens( remainingTokens )+ {}++ auto type() const -> ParseResultType { return m_type; }+ auto remainingTokens() const -> TokenStream { return m_remainingTokens; }++ private:+ ParseResultType m_type;+ TokenStream m_remainingTokens;+ };++ using Result = BasicResult<void>;+ using ParserResult = BasicResult<ParseResultType>;+ using InternalParseResult = BasicResult<ParseState>;++ struct HelpColumns {+ std::string left;+ std::string right;+ };++ template<typename T>+ inline auto convertInto( std::string const &source, T& target ) -> ParserResult {+ std::stringstream ss;+ ss << source;+ ss >> target;+ if( ss.fail() )+ return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" );+ else+ return ParserResult::ok( ParseResultType::Matched );+ }+ inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult {+ target = source;+ return ParserResult::ok( ParseResultType::Matched );+ }+ inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {+ std::string srcLC = source;+ std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } );+ if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")+ target = true;+ else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")+ target = false;+ else+ return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );+ return ParserResult::ok( ParseResultType::Matched );+ }+#ifdef CLARA_CONFIG_OPTIONAL_TYPE+ template<typename T>+ inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {+ T temp;+ auto result = convertInto( source, temp );+ if( result )+ target = std::move(temp);+ return result;+ }+#endif // CLARA_CONFIG_OPTIONAL_TYPE++ struct NonCopyable {+ NonCopyable() = default;+ NonCopyable( NonCopyable const & ) = delete;+ NonCopyable( NonCopyable && ) = delete;+ NonCopyable &operator=( NonCopyable const & ) = delete;+ NonCopyable &operator=( NonCopyable && ) = delete;+ };++ struct BoundRef : NonCopyable {+ virtual ~BoundRef() = default;+ virtual auto isContainer() const -> bool { return false; }+ virtual auto isFlag() const -> bool { return false; }+ };+ struct BoundValueRefBase : BoundRef {+ virtual auto setValue( std::string const &arg ) -> ParserResult = 0;+ };+ struct BoundFlagRefBase : BoundRef {+ virtual auto setFlag( bool flag ) -> ParserResult = 0;+ virtual auto isFlag() const -> bool { return true; }+ };++ template<typename T>+ struct BoundValueRef : BoundValueRefBase {+ T &m_ref;++ explicit BoundValueRef( T &ref ) : m_ref( ref ) {}++ auto setValue( std::string const &arg ) -> ParserResult override {+ return convertInto( arg, m_ref );+ }+ };++ template<typename T>+ struct BoundValueRef<std::vector<T>> : BoundValueRefBase {+ std::vector<T> &m_ref;++ explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}++ auto isContainer() const -> bool override { return true; }++ auto setValue( std::string const &arg ) -> ParserResult override {+ T temp;+ auto result = convertInto( arg, temp );+ if( result )+ m_ref.push_back( temp );+ return result;+ }+ };++ struct BoundFlagRef : BoundFlagRefBase {+ bool &m_ref;++ explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {}++ auto setFlag( bool flag ) -> ParserResult override {+ m_ref = flag;+ return ParserResult::ok( ParseResultType::Matched );+ }+ };++ template<typename ReturnType>+ struct LambdaInvoker {+ static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" );++ template<typename L, typename ArgType>+ static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {+ return lambda( arg );+ }+ };++ template<>+ struct LambdaInvoker<void> {+ template<typename L, typename ArgType>+ static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {+ lambda( arg );+ return ParserResult::ok( ParseResultType::Matched );+ }+ };++ template<typename ArgType, typename L>+ inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {+ ArgType temp{};+ auto result = convertInto( arg, temp );+ return !result+ ? result+ : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );+ }++ template<typename L>+ struct BoundLambda : BoundValueRefBase {+ L m_lambda;++ static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );+ explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {}++ auto setValue( std::string const &arg ) -> ParserResult override {+ return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );+ }+ };++ template<typename L>+ struct BoundFlagLambda : BoundFlagRefBase {+ L m_lambda;++ static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );+ static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" );++ explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {}++ auto setFlag( bool flag ) -> ParserResult override {+ return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );+ }+ };++ enum class Optionality { Optional, Required };++ struct Parser;++ class ParserBase {+ public:+ virtual ~ParserBase() = default;+ virtual auto validate() const -> Result { return Result::ok(); }+ virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0;+ virtual auto cardinality() const -> size_t { return 1; }++ auto parse( Args const &args ) const -> InternalParseResult {+ return parse( args.exeName(), TokenStream( args ) );+ }+ };++ template<typename DerivedT>+ class ComposableParserImpl : public ParserBase {+ public:+ template<typename T>+ auto operator|( T const &other ) const -> Parser;++ template<typename T>+ auto operator+( T const &other ) const -> Parser;+ };++ // Common code and state for Args and Opts+ template<typename DerivedT>+ class ParserRefImpl : public ComposableParserImpl<DerivedT> {+ protected:+ Optionality m_optionality = Optionality::Optional;+ std::shared_ptr<BoundRef> m_ref;+ std::string m_hint;+ std::string m_description;++ explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}++ public:+ template<typename T>+ ParserRefImpl( T &ref, std::string const &hint )+ : m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),+ m_hint( hint )+ {}++ template<typename LambdaT>+ ParserRefImpl( LambdaT const &ref, std::string const &hint )+ : m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),+ m_hint(hint)+ {}++ auto operator()( std::string const &description ) -> DerivedT & {+ m_description = description;+ return static_cast<DerivedT &>( *this );+ }++ auto optional() -> DerivedT & {+ m_optionality = Optionality::Optional;+ return static_cast<DerivedT &>( *this );+ };++ auto required() -> DerivedT & {+ m_optionality = Optionality::Required;+ return static_cast<DerivedT &>( *this );+ };++ auto isOptional() const -> bool {+ return m_optionality == Optionality::Optional;+ }++ auto cardinality() const -> size_t override {+ if( m_ref->isContainer() )+ return 0;+ else+ return 1;+ }++ auto hint() const -> std::string { return m_hint; }+ };++ class ExeName : public ComposableParserImpl<ExeName> {+ std::shared_ptr<std::string> m_name;+ std::shared_ptr<BoundValueRefBase> m_ref;++ template<typename LambdaT>+ static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {+ return std::make_shared<BoundLambda<LambdaT>>( lambda) ;+ }++ public:+ ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}++ explicit ExeName( std::string &ref ) : ExeName() {+ m_ref = std::make_shared<BoundValueRef<std::string>>( ref );+ }++ template<typename LambdaT>+ explicit ExeName( LambdaT const& lambda ) : ExeName() {+ m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda );+ }++ // The exe name is not parsed out of the normal tokens, but is handled specially+ auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {+ return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );+ }++ auto name() const -> std::string { return *m_name; }+ auto set( std::string const& newName ) -> ParserResult {++ auto lastSlash = newName.find_last_of( "\\/" );+ auto filename = ( lastSlash == std::string::npos )+ ? newName+ : newName.substr( lastSlash+1 );++ *m_name = filename;+ if( m_ref )+ return m_ref->setValue( filename );+ else+ return ParserResult::ok( ParseResultType::Matched );+ }+ };++ class Arg : public ParserRefImpl<Arg> {+ public:+ using ParserRefImpl::ParserRefImpl;++ auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override {+ auto validationResult = validate();+ if( !validationResult )+ return InternalParseResult( validationResult );++ auto remainingTokens = tokens;+ auto const &token = *remainingTokens;+ if( token.type != TokenType::Argument )+ return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );++ assert( !m_ref->isFlag() );+ auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );++ auto result = valueRef->setValue( remainingTokens->token );+ if( !result )+ return InternalParseResult( result );+ else+ return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );+ }+ };++ inline auto normaliseOpt( std::string const &optName ) -> std::string {+#ifdef CATCH_PLATFORM_WINDOWS+ if( optName[0] == '/' )+ return "-" + optName.substr( 1 );+ else+#endif+ return optName;+ }++ class Opt : public ParserRefImpl<Opt> {+ protected:+ std::vector<std::string> m_optNames;++ public:+ template<typename LambdaT>+ explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {}++ explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {}++ template<typename LambdaT>+ Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}++ template<typename T>+ Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}++ auto operator[]( std::string const &optName ) -> Opt & {+ m_optNames.push_back( optName );+ return *this;+ }++ auto getHelpColumns() const -> std::vector<HelpColumns> {+ std::ostringstream oss;+ bool first = true;+ for( auto const &opt : m_optNames ) {+ if (first)+ first = false;+ else+ oss << ", ";+ oss << opt;+ }+ if( !m_hint.empty() )+ oss << " <" << m_hint << ">";+ return { { oss.str(), m_description } };+ }++ auto isMatch( std::string const &optToken ) const -> bool {+ auto normalisedToken = normaliseOpt( optToken );+ for( auto const &name : m_optNames ) {+ if( normaliseOpt( name ) == normalisedToken )+ return true;+ }+ return false;+ }++ using ParserBase::parse;++ auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {+ auto validationResult = validate();+ if( !validationResult )+ return InternalParseResult( validationResult );++ auto remainingTokens = tokens;+ if( remainingTokens && remainingTokens->type == TokenType::Option ) {+ auto const &token = *remainingTokens;+ if( isMatch(token.token ) ) {+ if( m_ref->isFlag() ) {+ auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );+ auto result = flagRef->setFlag( true );+ if( !result )+ return InternalParseResult( result );+ if( result.value() == ParseResultType::ShortCircuitAll )+ return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );+ } else {+ auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );+ ++remainingTokens;+ if( !remainingTokens )+ return InternalParseResult::runtimeError( "Expected argument following " + token.token );+ auto const &argToken = *remainingTokens;+ if( argToken.type != TokenType::Argument )+ return InternalParseResult::runtimeError( "Expected argument following " + token.token );+ auto result = valueRef->setValue( argToken.token );+ if( !result )+ return InternalParseResult( result );+ if( result.value() == ParseResultType::ShortCircuitAll )+ return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );+ }+ return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );+ }+ }+ return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );+ }++ auto validate() const -> Result override {+ if( m_optNames.empty() )+ return Result::logicError( "No options supplied to Opt" );+ for( auto const &name : m_optNames ) {+ if( name.empty() )+ return Result::logicError( "Option name cannot be empty" );+#ifdef CATCH_PLATFORM_WINDOWS+ if( name[0] != '-' && name[0] != '/' )+ return Result::logicError( "Option name must begin with '-' or '/'" );+#else+ if( name[0] != '-' )+ return Result::logicError( "Option name must begin with '-'" );+#endif+ }+ return ParserRefImpl::validate();+ }+ };++ struct Help : Opt {+ Help( bool &showHelpFlag )+ : Opt([&]( bool flag ) {+ showHelpFlag = flag;+ return ParserResult::ok( ParseResultType::ShortCircuitAll );+ })+ {+ static_cast<Opt &>( *this )+ ("display usage information")+ ["-?"]["-h"]["--help"]+ .optional();+ }+ };++ struct Parser : ParserBase {++ mutable ExeName m_exeName;+ std::vector<Opt> m_options;+ std::vector<Arg> m_args;++ auto operator|=( ExeName const &exeName ) -> Parser & {+ m_exeName = exeName;+ return *this;+ }++ auto operator|=( Arg const &arg ) -> Parser & {+ m_args.push_back(arg);+ return *this;+ }++ auto operator|=( Opt const &opt ) -> Parser & {+ m_options.push_back(opt);+ return *this;+ }++ auto operator|=( Parser const &other ) -> Parser & {+ m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());+ m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());+ return *this;+ }++ template<typename T>+ auto operator|( T const &other ) const -> Parser {+ return Parser( *this ) |= other;+ }++ // Forward deprecated interface with '+' instead of '|'+ template<typename T>+ auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }+ template<typename T>+ auto operator+( T const &other ) const -> Parser { return operator|( other ); }++ auto getHelpColumns() const -> std::vector<HelpColumns> {+ std::vector<HelpColumns> cols;+ for (auto const &o : m_options) {+ auto childCols = o.getHelpColumns();+ cols.insert( cols.end(), childCols.begin(), childCols.end() );+ }+ return cols;+ }++ void writeToStream( std::ostream &os ) const {+ if (!m_exeName.name().empty()) {+ os << "usage:\n" << " " << m_exeName.name() << " ";+ bool required = true, first = true;+ for( auto const &arg : m_args ) {+ if (first)+ first = false;+ else+ os << " ";+ if( arg.isOptional() && required ) {+ os << "[";+ required = false;+ }+ os << "<" << arg.hint() << ">";+ if( arg.cardinality() == 0 )+ os << " ... ";+ }+ if( !required )+ os << "]";+ if( !m_options.empty() )+ os << " options";+ os << "\n\nwhere options are:" << std::endl;+ }++ auto rows = getHelpColumns();+ size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH;+ size_t optWidth = 0;+ for( auto const &cols : rows )+ optWidth = (std::max)(optWidth, cols.left.size() + 2);++ optWidth = (std::min)(optWidth, consoleWidth/2);++ for( auto const &cols : rows ) {+ auto row =+ TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) ++ TextFlow::Spacer(4) ++ TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );+ os << row << std::endl;+ }+ }++ friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {+ parser.writeToStream( os );+ return os;+ }++ auto validate() const -> Result override {+ for( auto const &opt : m_options ) {+ auto result = opt.validate();+ if( !result )+ return result;+ }+ for( auto const &arg : m_args ) {+ auto result = arg.validate();+ if( !result )+ return result;+ }+ return Result::ok();+ }++ using ParserBase::parse;++ auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override {++ struct ParserInfo {+ ParserBase const* parser = nullptr;+ size_t count = 0;+ };+ const size_t totalParsers = m_options.size() + m_args.size();+ assert( totalParsers < 512 );+ // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do+ ParserInfo parseInfos[512];++ {+ size_t i = 0;+ for (auto const &opt : m_options) parseInfos[i++].parser = &opt;+ for (auto const &arg : m_args) parseInfos[i++].parser = &arg;+ }++ m_exeName.set( exeName );++ auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );+ while( result.value().remainingTokens() ) {+ bool tokenParsed = false;++ for( size_t i = 0; i < totalParsers; ++i ) {+ auto& parseInfo = parseInfos[i];+ if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {+ result = parseInfo.parser->parse(exeName, result.value().remainingTokens());+ if (!result)+ return result;+ if (result.value().type() != ParseResultType::NoMatch) {+ tokenParsed = true;+ ++parseInfo.count;+ break;+ }+ }+ }++ if( result.value().type() == ParseResultType::ShortCircuitAll )+ return result;+ if( !tokenParsed )+ return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token );+ }+ // !TBD Check missing required options+ return result;+ }+ };++ template<typename DerivedT>+ template<typename T>+ auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {+ return Parser() | static_cast<DerivedT const &>( *this ) | other;+ }+} // namespace detail++// A Combined parser+using detail::Parser;++// A parser for options+using detail::Opt;++// A parser for arguments+using detail::Arg;++// Wrapper for argc, argv from main()+using detail::Args;++// Specifies the name of the executable+using detail::ExeName;++// Convenience wrapper for option parser that specifies the help option+using detail::Help;++// enum of result types from a parse+using detail::ParseResultType;++// Result type for parser operation+using detail::ParserResult;++}} // namespace Catch::clara++// end clara.hpp+#ifdef __clang__+#pragma clang diagnostic pop+#endif++// Restore Clara's value for console width, if present+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH+#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH+#endif++// end catch_clara.h+namespace Catch {++ clara::Parser makeCommandLineParser( ConfigData& config );++} // end namespace Catch++// end catch_commandline.h+#include <fstream>+#include <ctime>++namespace Catch {++ clara::Parser makeCommandLineParser( ConfigData& config ) {++ using namespace clara;++ auto const setWarning = [&]( std::string const& warning ) {+ auto warningSet = [&]() {+ if( warning == "NoAssertions" )+ return WarnAbout::NoAssertions;++ if ( warning == "NoTests" )+ return WarnAbout::NoTests;++ return WarnAbout::Nothing;+ }();++ if (warningSet == WarnAbout::Nothing)+ return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" );+ config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet );+ return ParserResult::ok( ParseResultType::Matched );+ };+ auto const loadTestNamesFromFile = [&]( std::string const& filename ) {+ std::ifstream f( filename.c_str() );+ if( !f.is_open() )+ return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" );++ std::string line;+ while( std::getline( f, line ) ) {+ line = trim(line);+ if( !line.empty() && !startsWith( line, '#' ) ) {+ if( !startsWith( line, '"' ) )+ line = '"' + line + '"';+ config.testsOrTags.push_back( line );+ config.testsOrTags.emplace_back( "," );+ }+ }+ //Remove comma in the end+ if(!config.testsOrTags.empty())+ config.testsOrTags.erase( config.testsOrTags.end()-1 );++ return ParserResult::ok( ParseResultType::Matched );+ };+ auto const setTestOrder = [&]( std::string const& order ) {+ if( startsWith( "declared", order ) )+ config.runOrder = RunTests::InDeclarationOrder;+ else if( startsWith( "lexical", order ) )+ config.runOrder = RunTests::InLexicographicalOrder;+ else if( startsWith( "random", order ) )+ config.runOrder = RunTests::InRandomOrder;+ else+ return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" );+ return ParserResult::ok( ParseResultType::Matched );+ };+ auto const setRngSeed = [&]( std::string const& seed ) {+ if( seed != "time" )+ return clara::detail::convertInto( seed, config.rngSeed );+ config.rngSeed = static_cast<unsigned int>( std::time(nullptr) );+ return ParserResult::ok( ParseResultType::Matched );+ };+ auto const setColourUsage = [&]( std::string const& useColour ) {+ auto mode = toLower( useColour );++ if( mode == "yes" )+ config.useColour = UseColour::Yes;+ else if( mode == "no" )+ config.useColour = UseColour::No;+ else if( mode == "auto" )+ config.useColour = UseColour::Auto;+ else+ return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" );+ return ParserResult::ok( ParseResultType::Matched );+ };+ auto const setWaitForKeypress = [&]( std::string const& keypress ) {+ auto keypressLc = toLower( keypress );+ if (keypressLc == "never")+ config.waitForKeypress = WaitForKeypress::Never;+ else if( keypressLc == "start" )+ config.waitForKeypress = WaitForKeypress::BeforeStart;+ else if( keypressLc == "exit" )+ config.waitForKeypress = WaitForKeypress::BeforeExit;+ else if( keypressLc == "both" )+ config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;+ else+ return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" );+ return ParserResult::ok( ParseResultType::Matched );+ };+ auto const setVerbosity = [&]( std::string const& verbosity ) {+ auto lcVerbosity = toLower( verbosity );+ if( lcVerbosity == "quiet" )+ config.verbosity = Verbosity::Quiet;+ else if( lcVerbosity == "normal" )+ config.verbosity = Verbosity::Normal;+ else if( lcVerbosity == "high" )+ config.verbosity = Verbosity::High;+ else+ return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" );+ return ParserResult::ok( ParseResultType::Matched );+ };+ auto const setReporter = [&]( std::string const& reporter ) {+ IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();++ auto lcReporter = toLower( reporter );+ auto result = factories.find( lcReporter );++ if( factories.end() != result )+ config.reporterName = lcReporter;+ else+ return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" );+ return ParserResult::ok( ParseResultType::Matched );+ };++ auto cli+ = ExeName( config.processName )+ | Help( config.showHelp )+ | Opt( config.listTests )+ ["-l"]["--list-tests"]+ ( "list all/matching test cases" )+ | Opt( config.listTags )+ ["-t"]["--list-tags"]+ ( "list all/matching tags" )+ | Opt( config.showSuccessfulTests )+ ["-s"]["--success"]+ ( "include successful tests in output" )+ | Opt( config.shouldDebugBreak )+ ["-b"]["--break"]+ ( "break into debugger on failure" )+ | Opt( config.noThrow )+ ["-e"]["--nothrow"]+ ( "skip exception tests" )+ | Opt( config.showInvisibles )+ ["-i"]["--invisibles"]+ ( "show invisibles (tabs, newlines)" )+ | Opt( config.outputFilename, "filename" )+ ["-o"]["--out"]+ ( "output filename" )+ | Opt( setReporter, "name" )+ ["-r"]["--reporter"]+ ( "reporter to use (defaults to console)" )+ | Opt( config.name, "name" )+ ["-n"]["--name"]+ ( "suite name" )+ | Opt( [&]( bool ){ config.abortAfter = 1; } )+ ["-a"]["--abort"]+ ( "abort at first failure" )+ | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )+ ["-x"]["--abortx"]+ ( "abort after x failures" )+ | Opt( setWarning, "warning name" )+ ["-w"]["--warn"]+ ( "enable warnings" )+ | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )+ ["-d"]["--durations"]+ ( "show test durations" )+ | Opt( config.minDuration, "seconds" )+ ["-D"]["--min-duration"]+ ( "show test durations for tests taking at least the given number of seconds" )+ | Opt( loadTestNamesFromFile, "filename" )+ ["-f"]["--input-file"]+ ( "load test names to run from a file" )+ | Opt( config.filenamesAsTags )+ ["-#"]["--filenames-as-tags"]+ ( "adds a tag for the filename" )+ | Opt( config.sectionsToRun, "section name" )+ ["-c"]["--section"]+ ( "specify section to run" )+ | Opt( setVerbosity, "quiet|normal|high" )+ ["-v"]["--verbosity"]+ ( "set output verbosity" )+ | Opt( config.listTestNamesOnly )+ ["--list-test-names-only"]+ ( "list all/matching test cases names only" )+ | Opt( config.listReporters )+ ["--list-reporters"]+ ( "list all reporters" )+ | Opt( setTestOrder, "decl|lex|rand" )+ ["--order"]+ ( "test case order (defaults to decl)" )+ | Opt( setRngSeed, "'time'|number" )+ ["--rng-seed"]+ ( "set a specific seed for random numbers" )+ | Opt( setColourUsage, "yes|no" )+ ["--use-colour"]+ ( "should output be colourised" )+ | Opt( config.libIdentify )+ ["--libidentify"]+ ( "report name and version according to libidentify standard" )+ | Opt( setWaitForKeypress, "never|start|exit|both" )+ ["--wait-for-keypress"]+ ( "waits for a keypress before exiting" )+ | Opt( config.benchmarkSamples, "samples" )+ ["--benchmark-samples"]+ ( "number of samples to collect (default: 100)" )+ | Opt( config.benchmarkResamples, "resamples" )+ ["--benchmark-resamples"]+ ( "number of resamples for the bootstrap (default: 100000)" )+ | Opt( config.benchmarkConfidenceInterval, "confidence interval" )+ ["--benchmark-confidence-interval"]+ ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )+ | Opt( config.benchmarkNoAnalysis )+ ["--benchmark-no-analysis"]+ ( "perform only measurements; do not perform any analysis" )+ | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" )+ ["--benchmark-warmup-time"]+ ( "amount of time in milliseconds spent on warming up each test (default: 100)" )+ | Arg( config.testsOrTags, "test name|pattern|tags" )+ ( "which test or tests to use" );++ return cli;+ }++} // end namespace Catch+// end catch_commandline.cpp+// start catch_common.cpp++#include <cstring>+#include <ostream>++namespace Catch {++ bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {+ return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);+ }+ bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {+ // We can assume that the same file will usually have the same pointer.+ // Thus, if the pointers are the same, there is no point in calling the strcmp+ return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));+ }++ std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {+#ifndef __GNUG__+ os << info.file << '(' << info.line << ')';+#else+ os << info.file << ':' << info.line;+#endif+ return os;+ }++ std::string StreamEndStop::operator+() const {+ return std::string();+ }++ NonCopyable::NonCopyable() = default;+ NonCopyable::~NonCopyable() = default;++}+// end catch_common.cpp+// start catch_config.cpp++namespace Catch {++ Config::Config( ConfigData const& data )+ : m_data( data ),+ m_stream( openStream() )+ {+ // We need to trim filter specs to avoid trouble with superfluous+ // whitespace (esp. important for bdd macros, as those are manually+ // aligned with whitespace).++ for (auto& elem : m_data.testsOrTags) {+ elem = trim(elem);+ }+ for (auto& elem : m_data.sectionsToRun) {+ elem = trim(elem);+ }++ TestSpecParser parser(ITagAliasRegistry::get());+ if (!m_data.testsOrTags.empty()) {+ m_hasTestFilters = true;+ for (auto const& testOrTags : m_data.testsOrTags) {+ parser.parse(testOrTags);+ }+ }+ m_testSpec = parser.testSpec();+ }++ std::string const& Config::getFilename() const {+ return m_data.outputFilename ;+ }++ bool Config::listTests() const { return m_data.listTests; }+ bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; }+ bool Config::listTags() const { return m_data.listTags; }+ bool Config::listReporters() const { return m_data.listReporters; }++ std::string Config::getProcessName() const { return m_data.processName; }+ std::string const& Config::getReporterName() const { return m_data.reporterName; }++ std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }+ std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }++ TestSpec const& Config::testSpec() const { return m_testSpec; }+ bool Config::hasTestFilters() const { return m_hasTestFilters; }++ bool Config::showHelp() const { return m_data.showHelp; }++ // IConfig interface+ bool Config::allowThrows() const { return !m_data.noThrow; }+ std::ostream& Config::stream() const { return m_stream->stream(); }+ std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }+ bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }+ bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); }+ bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }+ ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }+ double Config::minDuration() const { return m_data.minDuration; }+ RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }+ unsigned int Config::rngSeed() const { return m_data.rngSeed; }+ UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }+ bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }+ int Config::abortAfter() const { return m_data.abortAfter; }+ bool Config::showInvisibles() const { return m_data.showInvisibles; }+ Verbosity Config::verbosity() const { return m_data.verbosity; }++ bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }+ int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }+ double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }+ unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }+ std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }++ IStream const* Config::openStream() {+ return Catch::makeStream(m_data.outputFilename);+ }++} // end namespace Catch+// end catch_config.cpp+// start catch_console_colour.cpp++#if defined(__clang__)+# pragma clang diagnostic push+# pragma clang diagnostic ignored "-Wexit-time-destructors"+#endif++// start catch_errno_guard.h++namespace Catch {++ class ErrnoGuard {+ public:+ ErrnoGuard();+ ~ErrnoGuard();+ private:+ int m_oldErrno;+ };++}++// end catch_errno_guard.h+// start catch_windows_h_proxy.h+++#if defined(CATCH_PLATFORM_WINDOWS)++#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)+# define CATCH_DEFINED_NOMINMAX+# define NOMINMAX+#endif+#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)+# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN+# define WIN32_LEAN_AND_MEAN+#endif++#ifdef __AFXDLL+#include <AfxWin.h>+#else+#include <windows.h>+#endif++#ifdef CATCH_DEFINED_NOMINMAX+# undef NOMINMAX+#endif+#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN+# undef WIN32_LEAN_AND_MEAN+#endif++#endif // defined(CATCH_PLATFORM_WINDOWS)++// end catch_windows_h_proxy.h+#include <sstream>++namespace Catch {+ namespace {++ struct IColourImpl {+ virtual ~IColourImpl() = default;+ virtual void use( Colour::Code _colourCode ) = 0;+ };++ struct NoColourImpl : IColourImpl {+ void use( Colour::Code ) override {}++ static IColourImpl* instance() {+ static NoColourImpl s_instance;+ return &s_instance;+ }+ };++ } // anon namespace+} // namespace Catch++#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )+# ifdef CATCH_PLATFORM_WINDOWS+# define CATCH_CONFIG_COLOUR_WINDOWS+# else+# define CATCH_CONFIG_COLOUR_ANSI+# endif+#endif++#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////++namespace Catch {+namespace {++ class Win32ColourImpl : public IColourImpl {+ public:+ Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )+ {+ CONSOLE_SCREEN_BUFFER_INFO csbiInfo;+ GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );+ originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );+ originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );+ }++ void use( Colour::Code _colourCode ) override {+ switch( _colourCode ) {+ case Colour::None: return setTextAttribute( originalForegroundAttributes );+ case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );+ case Colour::Red: return setTextAttribute( FOREGROUND_RED );+ case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );+ case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );+ case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );+ case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );+ case Colour::Grey: return setTextAttribute( 0 );++ case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );+ case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );+ case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );+ case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );+ case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );++ case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );++ default:+ CATCH_ERROR( "Unknown colour requested" );+ }+ }++ private:+ void setTextAttribute( WORD _textAttribute ) {+ SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );+ }+ HANDLE stdoutHandle;+ WORD originalForegroundAttributes;+ WORD originalBackgroundAttributes;+ };++ IColourImpl* platformColourInstance() {+ static Win32ColourImpl s_instance;++ IConfigPtr config = getCurrentContext().getConfig();+ UseColour::YesOrNo colourMode = config+ ? config->useColour()+ : UseColour::Auto;+ if( colourMode == UseColour::Auto )+ colourMode = UseColour::Yes;+ return colourMode == UseColour::Yes+ ? &s_instance+ : NoColourImpl::instance();+ }++} // end anon namespace+} // end namespace Catch++#elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////++#include <unistd.h>++namespace Catch {+namespace {++ // use POSIX/ ANSI console terminal codes+ // Thanks to Adam Strzelecki for original contribution+ // (http://github.com/nanoant)+ // https://github.com/philsquared/Catch/pull/131+ class PosixColourImpl : public IColourImpl {+ public:+ void use( Colour::Code _colourCode ) override {+ switch( _colourCode ) {+ case Colour::None:+ case Colour::White: return setColour( "[0m" );+ case Colour::Red: return setColour( "[0;31m" );+ case Colour::Green: return setColour( "[0;32m" );+ case Colour::Blue: return setColour( "[0;34m" );+ case Colour::Cyan: return setColour( "[0;36m" );+ case Colour::Yellow: return setColour( "[0;33m" );+ case Colour::Grey: return setColour( "[1;30m" );++ case Colour::LightGrey: return setColour( "[0;37m" );+ case Colour::BrightRed: return setColour( "[1;31m" );+ case Colour::BrightGreen: return setColour( "[1;32m" );+ case Colour::BrightWhite: return setColour( "[1;37m" );+ case Colour::BrightYellow: return setColour( "[1;33m" );++ case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );+ default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );+ }+ }+ static IColourImpl* instance() {+ static PosixColourImpl s_instance;+ return &s_instance;+ }++ private:+ void setColour( const char* _escapeCode ) {+ getCurrentContext().getConfig()->stream()+ << '\033' << _escapeCode;+ }+ };++ bool useColourOnPlatform() {+ return+#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)+ !isDebuggerActive() &&+#endif+#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))+ isatty(STDOUT_FILENO)+#else+ false+#endif+ ;+ }+ IColourImpl* platformColourInstance() {+ ErrnoGuard guard;+ IConfigPtr config = getCurrentContext().getConfig();+ UseColour::YesOrNo colourMode = config+ ? config->useColour()+ : UseColour::Auto;+ if( colourMode == UseColour::Auto )+ colourMode = useColourOnPlatform()+ ? UseColour::Yes+ : UseColour::No;+ return colourMode == UseColour::Yes+ ? PosixColourImpl::instance()+ : NoColourImpl::instance();+ }++} // end anon namespace+} // end namespace Catch++#else // not Windows or ANSI ///////////////////////////////////////////////++namespace Catch {++ static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }++} // end namespace Catch++#endif // Windows/ ANSI/ None++namespace Catch {++ Colour::Colour( Code _colourCode ) { use( _colourCode ); }+ Colour::Colour( Colour&& other ) noexcept {+ m_moved = other.m_moved;+ other.m_moved = true;+ }+ Colour& Colour::operator=( Colour&& other ) noexcept {+ m_moved = other.m_moved;+ other.m_moved = true;+ return *this;+ }++ Colour::~Colour(){ if( !m_moved ) use( None ); }++ void Colour::use( Code _colourCode ) {+ static IColourImpl* impl = platformColourInstance();+ // Strictly speaking, this cannot possibly happen.+ // However, under some conditions it does happen (see #1626),+ // and this change is small enough that we can let practicality+ // triumph over purity in this case.+ if (impl != nullptr) {+ impl->use( _colourCode );+ }+ }++ std::ostream& operator << ( std::ostream& os, Colour const& ) {+ return os;+ }++} // end namespace Catch++#if defined(__clang__)+# pragma clang diagnostic pop+#endif++// end catch_console_colour.cpp+// start catch_context.cpp++namespace Catch {++ class Context : public IMutableContext, NonCopyable {++ public: // IContext+ IResultCapture* getResultCapture() override {+ return m_resultCapture;+ }+ IRunner* getRunner() override {+ return m_runner;+ }++ IConfigPtr const& getConfig() const override {+ return m_config;+ }++ ~Context() override;++ public: // IMutableContext+ void setResultCapture( IResultCapture* resultCapture ) override {+ m_resultCapture = resultCapture;+ }+ void setRunner( IRunner* runner ) override {+ m_runner = runner;+ }+ void setConfig( IConfigPtr const& config ) override {+ m_config = config;+ }++ friend IMutableContext& getCurrentMutableContext();++ private:+ IConfigPtr m_config;+ IRunner* m_runner = nullptr;+ IResultCapture* m_resultCapture = nullptr;+ };++ IMutableContext *IMutableContext::currentContext = nullptr;++ void IMutableContext::createContext()+ {+ currentContext = new Context();+ }++ void cleanUpContext() {+ delete IMutableContext::currentContext;+ IMutableContext::currentContext = nullptr;+ }+ IContext::~IContext() = default;+ IMutableContext::~IMutableContext() = default;+ Context::~Context() = default;++ SimplePcg32& rng() {+ static SimplePcg32 s_rng;+ return s_rng;+ }++}+// end catch_context.cpp+// start catch_debug_console.cpp++// start catch_debug_console.h++#include <string>++namespace Catch {+ void writeToDebugConsole( std::string const& text );+}++// end catch_debug_console.h+#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)+#include <android/log.h>++ namespace Catch {+ void writeToDebugConsole( std::string const& text ) {+ __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );+ }+ }++#elif defined(CATCH_PLATFORM_WINDOWS)++ namespace Catch {+ void writeToDebugConsole( std::string const& text ) {+ ::OutputDebugStringA( text.c_str() );+ }+ }++#else++ namespace Catch {+ void writeToDebugConsole( std::string const& text ) {+ // !TBD: Need a version for Mac/ XCode and other IDEs+ Catch::cout() << text;+ }+ }++#endif // Platform+// end catch_debug_console.cpp+// start catch_debugger.cpp++#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)++# include <cassert>+# include <sys/types.h>+# include <unistd.h>+# include <cstddef>+# include <ostream>++#ifdef __apple_build_version__+ // These headers will only compile with AppleClang (XCode)+ // For other compilers (Clang, GCC, ... ) we need to exclude them+# include <sys/sysctl.h>+#endif++ namespace Catch {+ #ifdef __apple_build_version__+ // The following function is taken directly from the following technical note:+ // https://developer.apple.com/library/archive/qa/qa1361/_index.html++ // Returns true if the current process is being debugged (either+ // running under the debugger or has a debugger attached post facto).+ bool isDebuggerActive(){+ int mib[4];+ struct kinfo_proc info;+ std::size_t size;++ // Initialize the flags so that, if sysctl fails for some bizarre+ // reason, we get a predictable result.++ info.kp_proc.p_flag = 0;++ // Initialize mib, which tells sysctl the info we want, in this case+ // we're looking for information about a specific process ID.++ mib[0] = CTL_KERN;+ mib[1] = KERN_PROC;+ mib[2] = KERN_PROC_PID;+ mib[3] = getpid();++ // Call sysctl.++ size = sizeof(info);+ if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {+ Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;+ return false;+ }++ // We're being debugged if the P_TRACED flag is set.++ return ( (info.kp_proc.p_flag & P_TRACED) != 0 );+ }+ #else+ bool isDebuggerActive() {+ // We need to find another way to determine this for non-appleclang compilers on macOS+ return false;+ }+ #endif+ } // namespace Catch++#elif defined(CATCH_PLATFORM_LINUX)+ #include <fstream>+ #include <string>++ namespace Catch{+ // The standard POSIX way of detecting a debugger is to attempt to+ // ptrace() the process, but this needs to be done from a child and not+ // this process itself to still allow attaching to this process later+ // if wanted, so is rather heavy. Under Linux we have the PID of the+ // "debugger" (which doesn't need to be gdb, of course, it could also+ // be strace, for example) in /proc/$PID/status, so just get it from+ // there instead.+ bool isDebuggerActive(){+ // Libstdc++ has a bug, where std::ifstream sets errno to 0+ // This way our users can properly assert over errno values+ ErrnoGuard guard;+ std::ifstream in("/proc/self/status");+ for( std::string line; std::getline(in, line); ) {+ static const int PREFIX_LEN = 11;+ if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {+ // We're traced if the PID is not 0 and no other PID starts+ // with 0 digit, so it's enough to check for just a single+ // character.+ return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';+ }+ }++ return false;+ }+ } // namespace Catch+#elif defined(_MSC_VER)+ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();+ namespace Catch {+ bool isDebuggerActive() {+ return IsDebuggerPresent() != 0;+ }+ }+#elif defined(__MINGW32__)+ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();+ namespace Catch {+ bool isDebuggerActive() {+ return IsDebuggerPresent() != 0;+ }+ }+#else+ namespace Catch {+ bool isDebuggerActive() { return false; }+ }+#endif // Platform+// end catch_debugger.cpp+// start catch_decomposer.cpp++namespace Catch {++ ITransientExpression::~ITransientExpression() = default;++ void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {+ if( lhs.size() + rhs.size() < 40 &&+ lhs.find('\n') == std::string::npos &&+ rhs.find('\n') == std::string::npos )+ os << lhs << " " << op << " " << rhs;+ else+ os << lhs << "\n" << op << "\n" << rhs;+ }+}+// end catch_decomposer.cpp+// start catch_enforce.cpp++#include <stdexcept>++namespace Catch {+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)+ [[noreturn]]+ void throw_exception(std::exception const& e) {+ Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"+ << "The message was: " << e.what() << '\n';+ std::terminate();+ }+#endif++ [[noreturn]]+ void throw_logic_error(std::string const& msg) {+ throw_exception(std::logic_error(msg));+ }++ [[noreturn]]+ void throw_domain_error(std::string const& msg) {+ throw_exception(std::domain_error(msg));+ }++ [[noreturn]]+ void throw_runtime_error(std::string const& msg) {+ throw_exception(std::runtime_error(msg));+ }++} // namespace Catch;+// end catch_enforce.cpp+// start catch_enum_values_registry.cpp+// start catch_enum_values_registry.h++#include <vector>+#include <memory>++namespace Catch {++ namespace Detail {++ std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );++ class EnumValuesRegistry : public IMutableEnumValuesRegistry {++ std::vector<std::unique_ptr<EnumInfo>> m_enumInfos;++ EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;+ };++ std::vector<StringRef> parseEnums( StringRef enums );++ } // Detail++} // Catch++// end catch_enum_values_registry.h++#include <map>+#include <cassert>++namespace Catch {++ IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {}++ namespace Detail {++ namespace {+ // Extracts the actual name part of an enum instance+ // In other words, it returns the Blue part of Bikeshed::Colour::Blue+ StringRef extractInstanceName(StringRef enumInstance) {+ // Find last occurrence of ":"+ size_t name_start = enumInstance.size();+ while (name_start > 0 && enumInstance[name_start - 1] != ':') {+ --name_start;+ }+ return enumInstance.substr(name_start, enumInstance.size() - name_start);+ }+ }++ std::vector<StringRef> parseEnums( StringRef enums ) {+ auto enumValues = splitStringRef( enums, ',' );+ std::vector<StringRef> parsed;+ parsed.reserve( enumValues.size() );+ for( auto const& enumValue : enumValues ) {+ parsed.push_back(trim(extractInstanceName(enumValue)));+ }+ return parsed;+ }++ EnumInfo::~EnumInfo() {}++ StringRef EnumInfo::lookup( int value ) const {+ for( auto const& valueToName : m_values ) {+ if( valueToName.first == value )+ return valueToName.second;+ }+ return "{** unexpected enum value **}"_sr;+ }++ std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {+ std::unique_ptr<EnumInfo> enumInfo( new EnumInfo );+ enumInfo->m_name = enumName;+ enumInfo->m_values.reserve( values.size() );++ const auto valueNames = Catch::Detail::parseEnums( allValueNames );+ assert( valueNames.size() == values.size() );+ std::size_t i = 0;+ for( auto value : values )+ enumInfo->m_values.emplace_back(value, valueNames[i++]);++ return enumInfo;+ }++ EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {+ m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));+ return *m_enumInfos.back();+ }++ } // Detail+} // Catch++// end catch_enum_values_registry.cpp+// start catch_errno_guard.cpp++#include <cerrno>++namespace Catch {+ ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}+ ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }+}+// end catch_errno_guard.cpp+// start catch_exception_translator_registry.cpp++// start catch_exception_translator_registry.h++#include <vector>+#include <string>+#include <memory>++namespace Catch {++ class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {+ public:+ ~ExceptionTranslatorRegistry();+ virtual void registerTranslator( const IExceptionTranslator* translator );+ std::string translateActiveException() const override;+ std::string tryTranslators() const;++ private:+ std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators;+ };+}++// end catch_exception_translator_registry.h+#ifdef __OBJC__+#import "Foundation/Foundation.h"+#endif++namespace Catch {++ ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {+ }++ void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) {+ m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );+ }++#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+ std::string ExceptionTranslatorRegistry::translateActiveException() const {+ try {+#ifdef __OBJC__+ // In Objective-C try objective-c exceptions first+ @try {+ return tryTranslators();+ }+ @catch (NSException *exception) {+ return Catch::Detail::stringify( [exception description] );+ }+#else+ // Compiling a mixed mode project with MSVC means that CLR+ // exceptions will be caught in (...) as well. However, these+ // do not fill-in std::current_exception and thus lead to crash+ // when attempting rethrow.+ // /EHa switch also causes structured exceptions to be caught+ // here, but they fill-in current_exception properly, so+ // at worst the output should be a little weird, instead of+ // causing a crash.+ if (std::current_exception() == nullptr) {+ return "Non C++ exception. Possibly a CLR exception.";+ }+ return tryTranslators();+#endif+ }+ catch( TestFailureException& ) {+ std::rethrow_exception(std::current_exception());+ }+ catch( std::exception& ex ) {+ return ex.what();+ }+ catch( std::string& msg ) {+ return msg;+ }+ catch( const char* msg ) {+ return msg;+ }+ catch(...) {+ return "Unknown exception";+ }+ }++ std::string ExceptionTranslatorRegistry::tryTranslators() const {+ if (m_translators.empty()) {+ std::rethrow_exception(std::current_exception());+ } else {+ return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());+ }+ }++#else // ^^ Exceptions are enabled // Exceptions are disabled vv+ std::string ExceptionTranslatorRegistry::translateActiveException() const {+ CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");+ }++ std::string ExceptionTranslatorRegistry::tryTranslators() const {+ CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!");+ }+#endif++}+// end catch_exception_translator_registry.cpp+// start catch_fatal_condition.cpp++#include <algorithm>++#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )++namespace Catch {++ // If neither SEH nor signal handling is required, the handler impls+ // do not have to do anything, and can be empty.+ void FatalConditionHandler::engage_platform() {}+ void FatalConditionHandler::disengage_platform() {}+ FatalConditionHandler::FatalConditionHandler() = default;+ FatalConditionHandler::~FatalConditionHandler() = default;++} // end namespace Catch++#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS++#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )+#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"+#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS++#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )++namespace {+ //! Signals fatal error message to the run context+ void reportFatal( char const * const message ) {+ Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );+ }++ //! Minimal size Catch2 needs for its own fatal error handling.+ //! Picked anecdotally, so it might not be sufficient on all+ //! platforms, and for all configurations.+ constexpr std::size_t minStackSizeForErrors = 32 * 1024;+} // end unnamed namespace++#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS++#if defined( CATCH_CONFIG_WINDOWS_SEH )++namespace Catch {++ struct SignalDefs { DWORD id; const char* name; };++ // There is no 1-1 mapping between signals and windows exceptions.+ // Windows can easily distinguish between SO and SigSegV,+ // but SigInt, SigTerm, etc are handled differently.+ static SignalDefs signalDefs[] = {+ { static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" },+ { static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" },+ { static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" },+ { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" },+ };++ static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {+ for (auto const& def : signalDefs) {+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {+ reportFatal(def.name);+ }+ }+ // If its not an exception we care about, pass it along.+ // This stops us from eating debugger breaks etc.+ return EXCEPTION_CONTINUE_SEARCH;+ }++ // Since we do not support multiple instantiations, we put these+ // into global variables and rely on cleaning them up in outlined+ // constructors/destructors+ static PVOID exceptionHandlerHandle = nullptr;++ // For MSVC, we reserve part of the stack memory for handling+ // memory overflow structured exception.+ FatalConditionHandler::FatalConditionHandler() {+ ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);+ if (!SetThreadStackGuarantee(&guaranteeSize)) {+ // We do not want to fully error out, because needing+ // the stack reserve should be rare enough anyway.+ Catch::cerr()+ << "Failed to reserve piece of stack."+ << " Stack overflows will not be reported successfully.";+ }+ }++ // We do not attempt to unset the stack guarantee, because+ // Windows does not support lowering the stack size guarantee.+ FatalConditionHandler::~FatalConditionHandler() = default;++ void FatalConditionHandler::engage_platform() {+ // Register as first handler in current chain+ exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);+ if (!exceptionHandlerHandle) {+ CATCH_RUNTIME_ERROR("Could not register vectored exception handler");+ }+ }++ void FatalConditionHandler::disengage_platform() {+ if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) {+ CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler");+ }+ exceptionHandlerHandle = nullptr;+ }++} // end namespace Catch++#endif // CATCH_CONFIG_WINDOWS_SEH++#if defined( CATCH_CONFIG_POSIX_SIGNALS )++#include <signal.h>++namespace Catch {++ struct SignalDefs {+ int id;+ const char* name;+ };++ static SignalDefs signalDefs[] = {+ { SIGINT, "SIGINT - Terminal interrupt signal" },+ { SIGILL, "SIGILL - Illegal instruction signal" },+ { SIGFPE, "SIGFPE - Floating point error signal" },+ { SIGSEGV, "SIGSEGV - Segmentation violation signal" },+ { SIGTERM, "SIGTERM - Termination request signal" },+ { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }+ };++// Older GCCs trigger -Wmissing-field-initializers for T foo = {}+// which is zero initialization, but not explicit. We want to avoid+// that.+#if defined(__GNUC__)+# pragma GCC diagnostic push+# pragma GCC diagnostic ignored "-Wmissing-field-initializers"+#endif++ static char* altStackMem = nullptr;+ static std::size_t altStackSize = 0;+ static stack_t oldSigStack{};+ static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};++ static void restorePreviousSignalHandlers() {+ // We set signal handlers back to the previous ones. Hopefully+ // nobody overwrote them in the meantime, and doesn't expect+ // their signal handlers to live past ours given that they+ // installed them after ours..+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {+ sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);+ }+ // Return the old stack+ sigaltstack(&oldSigStack, nullptr);+ }++ static void handleSignal( int sig ) {+ char const * name = "<unknown signal>";+ for (auto const& def : signalDefs) {+ if (sig == def.id) {+ name = def.name;+ break;+ }+ }+ // We need to restore previous signal handlers and let them do+ // their thing, so that the users can have the debugger break+ // when a signal is raised, and so on.+ restorePreviousSignalHandlers();+ reportFatal( name );+ raise( sig );+ }++ FatalConditionHandler::FatalConditionHandler() {+ assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");+ if (altStackSize == 0) {+ altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);+ }+ altStackMem = new char[altStackSize]();+ }++ FatalConditionHandler::~FatalConditionHandler() {+ delete[] altStackMem;+ // We signal that another instance can be constructed by zeroing+ // out the pointer.+ altStackMem = nullptr;+ }++ void FatalConditionHandler::engage_platform() {+ stack_t sigStack;+ sigStack.ss_sp = altStackMem;+ sigStack.ss_size = altStackSize;+ sigStack.ss_flags = 0;+ sigaltstack(&sigStack, &oldSigStack);+ struct sigaction sa = { };++ sa.sa_handler = handleSignal;+ sa.sa_flags = SA_ONSTACK;+ for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {+ sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);+ }+ }++#if defined(__GNUC__)+# pragma GCC diagnostic pop+#endif++ void FatalConditionHandler::disengage_platform() {+ restorePreviousSignalHandlers();+ }++} // end namespace Catch++#endif // CATCH_CONFIG_POSIX_SIGNALS+// end catch_fatal_condition.cpp+// start catch_generators.cpp++#include <limits>+#include <set>++namespace Catch {++IGeneratorTracker::~IGeneratorTracker() {}++const char* GeneratorException::what() const noexcept {+ return m_msg;+}++namespace Generators {++ GeneratorUntypedBase::~GeneratorUntypedBase() {}++ auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {+ return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );+ }++} // namespace Generators+} // namespace Catch+// end catch_generators.cpp+// start catch_interfaces_capture.cpp++namespace Catch {+ IResultCapture::~IResultCapture() = default;+}+// end catch_interfaces_capture.cpp+// start catch_interfaces_config.cpp++namespace Catch {+ IConfig::~IConfig() = default;+}+// end catch_interfaces_config.cpp+// start catch_interfaces_exception.cpp++namespace Catch {+ IExceptionTranslator::~IExceptionTranslator() = default;+ IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;+}+// end catch_interfaces_exception.cpp+// start catch_interfaces_registry_hub.cpp++namespace Catch {+ IRegistryHub::~IRegistryHub() = default;+ IMutableRegistryHub::~IMutableRegistryHub() = default;+}+// end catch_interfaces_registry_hub.cpp+// start catch_interfaces_reporter.cpp++// start catch_reporter_listening.h++namespace Catch {++ class ListeningReporter : public IStreamingReporter {+ using Reporters = std::vector<IStreamingReporterPtr>;+ Reporters m_listeners;+ IStreamingReporterPtr m_reporter = nullptr;+ ReporterPreferences m_preferences;++ public:+ ListeningReporter();++ void addListener( IStreamingReporterPtr&& listener );+ void addReporter( IStreamingReporterPtr&& reporter );++ public: // IStreamingReporter++ ReporterPreferences getPreferences() const override;++ void noMatchingTestCases( std::string const& spec ) override;++ void reportInvalidArguments(std::string const&arg) override;++ static std::set<Verbosity> getSupportedVerbosities();++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+ void benchmarkPreparing(std::string const& name) override;+ void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;+ void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;+ void benchmarkFailed(std::string const&) override;+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++ void testRunStarting( TestRunInfo const& testRunInfo ) override;+ void testGroupStarting( GroupInfo const& groupInfo ) override;+ void testCaseStarting( TestCaseInfo const& testInfo ) override;+ void sectionStarting( SectionInfo const& sectionInfo ) override;+ void assertionStarting( AssertionInfo const& assertionInfo ) override;++ // The return value indicates if the messages buffer should be cleared:+ bool assertionEnded( AssertionStats const& assertionStats ) override;+ void sectionEnded( SectionStats const& sectionStats ) override;+ void testCaseEnded( TestCaseStats const& testCaseStats ) override;+ void testGroupEnded( TestGroupStats const& testGroupStats ) override;+ void testRunEnded( TestRunStats const& testRunStats ) override;++ void skipTest( TestCaseInfo const& testInfo ) override;+ bool isMulti() const override;++ };++} // end namespace Catch++// end catch_reporter_listening.h+namespace Catch {++ ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig )+ : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}++ ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream )+ : m_stream( &_stream ), m_fullConfig( _fullConfig ) {}++ std::ostream& ReporterConfig::stream() const { return *m_stream; }+ IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; }++ TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {}++ GroupInfo::GroupInfo( std::string const& _name,+ std::size_t _groupIndex,+ std::size_t _groupsCount )+ : name( _name ),+ groupIndex( _groupIndex ),+ groupsCounts( _groupsCount )+ {}++ AssertionStats::AssertionStats( AssertionResult const& _assertionResult,+ std::vector<MessageInfo> const& _infoMessages,+ Totals const& _totals )+ : assertionResult( _assertionResult ),+ infoMessages( _infoMessages ),+ totals( _totals )+ {+ assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression;++ if( assertionResult.hasMessage() ) {+ // Copy message into messages list.+ // !TBD This should have been done earlier, somewhere+ MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );+ builder << assertionResult.getMessage();+ builder.m_info.message = builder.m_stream.str();++ infoMessages.push_back( builder.m_info );+ }+ }++ AssertionStats::~AssertionStats() = default;++ SectionStats::SectionStats( SectionInfo const& _sectionInfo,+ Counts const& _assertions,+ double _durationInSeconds,+ bool _missingAssertions )+ : sectionInfo( _sectionInfo ),+ assertions( _assertions ),+ durationInSeconds( _durationInSeconds ),+ missingAssertions( _missingAssertions )+ {}++ SectionStats::~SectionStats() = default;++ TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,+ Totals const& _totals,+ std::string const& _stdOut,+ std::string const& _stdErr,+ bool _aborting )+ : testInfo( _testInfo ),+ totals( _totals ),+ stdOut( _stdOut ),+ stdErr( _stdErr ),+ aborting( _aborting )+ {}++ TestCaseStats::~TestCaseStats() = default;++ TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo,+ Totals const& _totals,+ bool _aborting )+ : groupInfo( _groupInfo ),+ totals( _totals ),+ aborting( _aborting )+ {}++ TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo )+ : groupInfo( _groupInfo ),+ aborting( false )+ {}++ TestGroupStats::~TestGroupStats() = default;++ TestRunStats::TestRunStats( TestRunInfo const& _runInfo,+ Totals const& _totals,+ bool _aborting )+ : runInfo( _runInfo ),+ totals( _totals ),+ aborting( _aborting )+ {}++ TestRunStats::~TestRunStats() = default;++ void IStreamingReporter::fatalErrorEncountered( StringRef ) {}+ bool IStreamingReporter::isMulti() const { return false; }++ IReporterFactory::~IReporterFactory() = default;+ IReporterRegistry::~IReporterRegistry() = default;++} // end namespace Catch+// end catch_interfaces_reporter.cpp+// start catch_interfaces_runner.cpp++namespace Catch {+ IRunner::~IRunner() = default;+}+// end catch_interfaces_runner.cpp+// start catch_interfaces_testcase.cpp++namespace Catch {+ ITestInvoker::~ITestInvoker() = default;+ ITestCaseRegistry::~ITestCaseRegistry() = default;+}+// end catch_interfaces_testcase.cpp+// start catch_leak_detector.cpp++#ifdef CATCH_CONFIG_WINDOWS_CRTDBG+#include <crtdbg.h>++namespace Catch {++ LeakDetector::LeakDetector() {+ int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);+ flag |= _CRTDBG_LEAK_CHECK_DF;+ flag |= _CRTDBG_ALLOC_MEM_DF;+ _CrtSetDbgFlag(flag);+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);+ // Change this to leaking allocation's number to break there+ _CrtSetBreakAlloc(-1);+ }+}++#else++ Catch::LeakDetector::LeakDetector() {}++#endif++Catch::LeakDetector::~LeakDetector() {+ Catch::cleanUp();+}+// end catch_leak_detector.cpp+// start catch_list.cpp++// start catch_list.h++#include <set>++namespace Catch {++ std::size_t listTests( Config const& config );++ std::size_t listTestsNamesOnly( Config const& config );++ struct TagInfo {+ void add( std::string const& spelling );+ std::string all() const;++ std::set<std::string> spellings;+ std::size_t count = 0;+ };++ std::size_t listTags( Config const& config );++ std::size_t listReporters();++ Option<std::size_t> list( std::shared_ptr<Config> const& config );++} // end namespace Catch++// end catch_list.h+// start catch_text.h++namespace Catch {+ using namespace clara::TextFlow;+}++// end catch_text.h+#include <limits>+#include <algorithm>+#include <iomanip>++namespace Catch {++ std::size_t listTests( Config const& config ) {+ TestSpec const& testSpec = config.testSpec();+ if( config.hasTestFilters() )+ Catch::cout() << "Matching test cases:\n";+ else {+ Catch::cout() << "All available test cases:\n";+ }++ auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );+ for( auto const& testCaseInfo : matchedTestCases ) {+ Colour::Code colour = testCaseInfo.isHidden()+ ? Colour::SecondaryText+ : Colour::None;+ Colour colourGuard( colour );++ Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n";+ if( config.verbosity() >= Verbosity::High ) {+ Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl;+ std::string description = testCaseInfo.description;+ if( description.empty() )+ description = "(NO DESCRIPTION)";+ Catch::cout() << Column( description ).indent(4) << std::endl;+ }+ if( !testCaseInfo.tags.empty() )+ Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n";+ }++ if( !config.hasTestFilters() )+ Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl;+ else+ Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;+ return matchedTestCases.size();+ }++ std::size_t listTestsNamesOnly( Config const& config ) {+ TestSpec const& testSpec = config.testSpec();+ std::size_t matchedTests = 0;+ std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );+ for( auto const& testCaseInfo : matchedTestCases ) {+ matchedTests++;+ if( startsWith( testCaseInfo.name, '#' ) )+ Catch::cout() << '"' << testCaseInfo.name << '"';+ else+ Catch::cout() << testCaseInfo.name;+ if ( config.verbosity() >= Verbosity::High )+ Catch::cout() << "\t@" << testCaseInfo.lineInfo;+ Catch::cout() << std::endl;+ }+ return matchedTests;+ }++ void TagInfo::add( std::string const& spelling ) {+ ++count;+ spellings.insert( spelling );+ }++ std::string TagInfo::all() const {+ size_t size = 0;+ for (auto const& spelling : spellings) {+ // Add 2 for the brackes+ size += spelling.size() + 2;+ }++ std::string out; out.reserve(size);+ for (auto const& spelling : spellings) {+ out += '[';+ out += spelling;+ out += ']';+ }+ return out;+ }++ std::size_t listTags( Config const& config ) {+ TestSpec const& testSpec = config.testSpec();+ if( config.hasTestFilters() )+ Catch::cout() << "Tags for matching test cases:\n";+ else {+ Catch::cout() << "All available tags:\n";+ }++ std::map<std::string, TagInfo> tagCounts;++ std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );+ for( auto const& testCase : matchedTestCases ) {+ for( auto const& tagName : testCase.getTestCaseInfo().tags ) {+ std::string lcaseTagName = toLower( tagName );+ auto countIt = tagCounts.find( lcaseTagName );+ if( countIt == tagCounts.end() )+ countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;+ countIt->second.add( tagName );+ }+ }++ for( auto const& tagCount : tagCounts ) {+ ReusableStringStream rss;+ rss << " " << std::setw(2) << tagCount.second.count << " ";+ auto str = rss.str();+ auto wrapper = Column( tagCount.second.all() )+ .initialIndent( 0 )+ .indent( str.size() )+ .width( CATCH_CONFIG_CONSOLE_WIDTH-10 );+ Catch::cout() << str << wrapper << '\n';+ }+ Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;+ return tagCounts.size();+ }++ std::size_t listReporters() {+ Catch::cout() << "Available reporters:\n";+ IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();+ std::size_t maxNameLen = 0;+ for( auto const& factoryKvp : factories )+ maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() );++ for( auto const& factoryKvp : factories ) {+ Catch::cout()+ << Column( factoryKvp.first + ":" )+ .indent(2)+ .width( 5+maxNameLen )+ + Column( factoryKvp.second->getDescription() )+ .initialIndent(0)+ .indent(2)+ .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 )+ << "\n";+ }+ Catch::cout() << std::endl;+ return factories.size();+ }++ Option<std::size_t> list( std::shared_ptr<Config> const& config ) {+ Option<std::size_t> listedCount;+ getCurrentMutableContext().setConfig( config );+ if( config->listTests() )+ listedCount = listedCount.valueOr(0) + listTests( *config );+ if( config->listTestNamesOnly() )+ listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config );+ if( config->listTags() )+ listedCount = listedCount.valueOr(0) + listTags( *config );+ if( config->listReporters() )+ listedCount = listedCount.valueOr(0) + listReporters();+ return listedCount;+ }++} // end namespace Catch+// end catch_list.cpp+// start catch_matchers.cpp++namespace Catch {+namespace Matchers {+ namespace Impl {++ std::string MatcherUntypedBase::toString() const {+ if( m_cachedToString.empty() )+ m_cachedToString = describe();+ return m_cachedToString;+ }++ MatcherUntypedBase::~MatcherUntypedBase() = default;++ } // namespace Impl+} // namespace Matchers++using namespace Matchers;+using Matchers::Impl::MatcherBase;++} // namespace Catch+// end catch_matchers.cpp+// start catch_matchers_exception.cpp++namespace Catch {+namespace Matchers {+namespace Exception {++bool ExceptionMessageMatcher::match(std::exception const& ex) const {+ return ex.what() == m_message;+}++std::string ExceptionMessageMatcher::describe() const {+ return "exception message matches \"" + m_message + "\"";+}++}+Exception::ExceptionMessageMatcher Message(std::string const& message) {+ return Exception::ExceptionMessageMatcher(message);+}++// namespace Exception+} // namespace Matchers+} // namespace Catch+// end catch_matchers_exception.cpp+// start catch_matchers_floating.cpp++// start catch_polyfills.hpp++namespace Catch {+ bool isnan(float f);+ bool isnan(double d);+}++// end catch_polyfills.hpp+// start catch_to_string.hpp++#include <string>++namespace Catch {+ template <typename T>+ std::string to_string(T const& t) {+#if defined(CATCH_CONFIG_CPP11_TO_STRING)+ return std::to_string(t);+#else+ ReusableStringStream rss;+ rss << t;+ return rss.str();+#endif+ }+} // end namespace Catch++// end catch_to_string.hpp+#include <algorithm>+#include <cmath>+#include <cstdlib>+#include <cstdint>+#include <cstring>+#include <sstream>+#include <type_traits>+#include <iomanip>+#include <limits>++namespace Catch {+namespace {++ int32_t convert(float f) {+ static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");+ int32_t i;+ std::memcpy(&i, &f, sizeof(f));+ return i;+ }++ int64_t convert(double d) {+ static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");+ int64_t i;+ std::memcpy(&i, &d, sizeof(d));+ return i;+ }++ template <typename FP>+ bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {+ // Comparison with NaN should always be false.+ // This way we can rule it out before getting into the ugly details+ if (Catch::isnan(lhs) || Catch::isnan(rhs)) {+ return false;+ }++ auto lc = convert(lhs);+ auto rc = convert(rhs);++ if ((lc < 0) != (rc < 0)) {+ // Potentially we can have +0 and -0+ return lhs == rhs;+ }++ // static cast as a workaround for IBM XLC+ auto ulpDiff = std::abs(static_cast<FP>(lc - rc));+ return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;+ }++#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)++ float nextafter(float x, float y) {+ return ::nextafterf(x, y);+ }++ double nextafter(double x, double y) {+ return ::nextafter(x, y);+ }++#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^++template <typename FP>+FP step(FP start, FP direction, uint64_t steps) {+ for (uint64_t i = 0; i < steps; ++i) {+#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)+ start = Catch::nextafter(start, direction);+#else+ start = std::nextafter(start, direction);+#endif+ }+ return start;+}++// Performs equivalent check of std::fabs(lhs - rhs) <= margin+// But without the subtraction to allow for INFINITY in comparison+bool marginComparison(double lhs, double rhs, double margin) {+ return (lhs + margin >= rhs) && (rhs + margin >= lhs);+}++template <typename FloatingPoint>+void write(std::ostream& out, FloatingPoint num) {+ out << std::scientific+ << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)+ << num;+}++} // end anonymous namespace++namespace Matchers {+namespace Floating {++ enum class FloatingPointKind : uint8_t {+ Float,+ Double+ };++ WithinAbsMatcher::WithinAbsMatcher(double target, double margin)+ :m_target{ target }, m_margin{ margin } {+ CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'+ << " Margin has to be non-negative.");+ }++ // Performs equivalent check of std::fabs(lhs - rhs) <= margin+ // But without the subtraction to allow for INFINITY in comparison+ bool WithinAbsMatcher::match(double const& matchee) const {+ return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);+ }++ std::string WithinAbsMatcher::describe() const {+ return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);+ }++ WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType)+ :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {+ CATCH_ENFORCE(m_type == FloatingPointKind::Double+ || m_ulps < (std::numeric_limits<uint32_t>::max)(),+ "Provided ULP is impossibly large for a float comparison.");+ }++#if defined(__clang__)+#pragma clang diagnostic push+// Clang <3.5 reports on the default branch in the switch below+#pragma clang diagnostic ignored "-Wunreachable-code"+#endif++ bool WithinUlpsMatcher::match(double const& matchee) const {+ switch (m_type) {+ case FloatingPointKind::Float:+ return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);+ case FloatingPointKind::Double:+ return almostEqualUlps<double>(matchee, m_target, m_ulps);+ default:+ CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" );+ }+ }++#if defined(__clang__)+#pragma clang diagnostic pop+#endif++ std::string WithinUlpsMatcher::describe() const {+ std::stringstream ret;++ ret << "is within " << m_ulps << " ULPs of ";++ if (m_type == FloatingPointKind::Float) {+ write(ret, static_cast<float>(m_target));+ ret << 'f';+ } else {+ write(ret, m_target);+ }++ ret << " ([";+ if (m_type == FloatingPointKind::Double) {+ write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps));+ ret << ", ";+ write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps));+ } else {+ // We have to cast INFINITY to float because of MinGW, see #1782+ write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps));+ ret << ", ";+ write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps));+ }+ ret << "])";++ return ret.str();+ }++ WithinRelMatcher::WithinRelMatcher(double target, double epsilon):+ m_target(target),+ m_epsilon(epsilon){+ CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense.");+ CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense.");+ }++ bool WithinRelMatcher::match(double const& matchee) const {+ const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));+ return marginComparison(matchee, m_target,+ std::isinf(relMargin)? 0 : relMargin);+ }++ std::string WithinRelMatcher::describe() const {+ Catch::ReusableStringStream sstr;+ sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other";+ return sstr.str();+ }++}// namespace Floating++Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {+ return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);+}++Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {+ return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);+}++Floating::WithinAbsMatcher WithinAbs(double target, double margin) {+ return Floating::WithinAbsMatcher(target, margin);+}++Floating::WithinRelMatcher WithinRel(double target, double eps) {+ return Floating::WithinRelMatcher(target, eps);+}++Floating::WithinRelMatcher WithinRel(double target) {+ return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);+}++Floating::WithinRelMatcher WithinRel(float target, float eps) {+ return Floating::WithinRelMatcher(target, eps);+}++Floating::WithinRelMatcher WithinRel(float target) {+ return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);+}++} // namespace Matchers+} // namespace Catch+// end catch_matchers_floating.cpp+// start catch_matchers_generic.cpp++std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) {+ if (desc.empty()) {+ return "matches undescribed predicate";+ } else {+ return "matches predicate: \"" + desc + '"';+ }+}+// end catch_matchers_generic.cpp+// start catch_matchers_string.cpp++#include <regex>++namespace Catch {+namespace Matchers {++ namespace StdString {++ CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )+ : m_caseSensitivity( caseSensitivity ),+ m_str( adjustString( str ) )+ {}+ std::string CasedString::adjustString( std::string const& str ) const {+ return m_caseSensitivity == CaseSensitive::No+ ? toLower( str )+ : str;+ }+ std::string CasedString::caseSensitivitySuffix() const {+ return m_caseSensitivity == CaseSensitive::No+ ? " (case insensitive)"+ : std::string();+ }++ StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )+ : m_comparator( comparator ),+ m_operation( operation ) {+ }++ std::string StringMatcherBase::describe() const {+ std::string description;+ description.reserve(5 + m_operation.size() + m_comparator.m_str.size() ++ m_comparator.caseSensitivitySuffix().size());+ description += m_operation;+ description += ": \"";+ description += m_comparator.m_str;+ description += "\"";+ description += m_comparator.caseSensitivitySuffix();+ return description;+ }++ EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}++ bool EqualsMatcher::match( std::string const& source ) const {+ return m_comparator.adjustString( source ) == m_comparator.m_str;+ }++ ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}++ bool ContainsMatcher::match( std::string const& source ) const {+ return contains( m_comparator.adjustString( source ), m_comparator.m_str );+ }++ StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}++ bool StartsWithMatcher::match( std::string const& source ) const {+ return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );+ }++ EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}++ bool EndsWithMatcher::match( std::string const& source ) const {+ return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );+ }++ RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {}++ bool RegexMatcher::match(std::string const& matchee) const {+ auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway+ if (m_caseSensitivity == CaseSensitive::Choice::No) {+ flags |= std::regex::icase;+ }+ auto reg = std::regex(m_regex, flags);+ return std::regex_match(matchee, reg);+ }++ std::string RegexMatcher::describe() const {+ return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively");+ }++ } // namespace StdString++ StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {+ return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );+ }+ StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {+ return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );+ }+ StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {+ return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );+ }+ StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {+ return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );+ }++ StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) {+ return StdString::RegexMatcher(regex, caseSensitivity);+ }++} // namespace Matchers+} // namespace Catch+// end catch_matchers_string.cpp+// start catch_message.cpp++// start catch_uncaught_exceptions.h++namespace Catch {+ bool uncaught_exceptions();+} // end namespace Catch++// end catch_uncaught_exceptions.h+#include <cassert>+#include <stack>++namespace Catch {++ MessageInfo::MessageInfo( StringRef const& _macroName,+ SourceLineInfo const& _lineInfo,+ ResultWas::OfType _type )+ : macroName( _macroName ),+ lineInfo( _lineInfo ),+ type( _type ),+ sequence( ++globalCount )+ {}++ bool MessageInfo::operator==( MessageInfo const& other ) const {+ return sequence == other.sequence;+ }++ bool MessageInfo::operator<( MessageInfo const& other ) const {+ return sequence < other.sequence;+ }++ // This may need protecting if threading support is added+ unsigned int MessageInfo::globalCount = 0;++ ////////////////////////////////////////////////////////////////////////////++ Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,+ SourceLineInfo const& lineInfo,+ ResultWas::OfType type )+ :m_info(macroName, lineInfo, type) {}++ ////////////////////////////////////////////////////////////////////////////++ ScopedMessage::ScopedMessage( MessageBuilder const& builder )+ : m_info( builder.m_info ), m_moved()+ {+ m_info.message = builder.m_stream.str();+ getResultCapture().pushScopedMessage( m_info );+ }++ ScopedMessage::ScopedMessage( ScopedMessage&& old )+ : m_info( old.m_info ), m_moved()+ {+ old.m_moved = true;+ }++ ScopedMessage::~ScopedMessage() {+ if ( !uncaught_exceptions() && !m_moved ){+ getResultCapture().popScopedMessage(m_info);+ }+ }++ Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {+ auto trimmed = [&] (size_t start, size_t end) {+ while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {+ ++start;+ }+ while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {+ --end;+ }+ return names.substr(start, end - start + 1);+ };+ auto skipq = [&] (size_t start, char quote) {+ for (auto i = start + 1; i < names.size() ; ++i) {+ if (names[i] == quote)+ return i;+ if (names[i] == '\\')+ ++i;+ }+ CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");+ };++ size_t start = 0;+ std::stack<char> openings;+ for (size_t pos = 0; pos < names.size(); ++pos) {+ char c = names[pos];+ switch (c) {+ case '[':+ case '{':+ case '(':+ // It is basically impossible to disambiguate between+ // comparison and start of template args in this context+// case '<':+ openings.push(c);+ break;+ case ']':+ case '}':+ case ')':+// case '>':+ openings.pop();+ break;+ case '"':+ case '\'':+ pos = skipq(pos, c);+ break;+ case ',':+ if (start != pos && openings.empty()) {+ m_messages.emplace_back(macroName, lineInfo, resultType);+ m_messages.back().message = static_cast<std::string>(trimmed(start, pos));+ m_messages.back().message += " := ";+ start = pos;+ }+ }+ }+ assert(openings.empty() && "Mismatched openings");+ m_messages.emplace_back(macroName, lineInfo, resultType);+ m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));+ m_messages.back().message += " := ";+ }+ Capturer::~Capturer() {+ if ( !uncaught_exceptions() ){+ assert( m_captured == m_messages.size() );+ for( size_t i = 0; i < m_captured; ++i )+ m_resultCapture.popScopedMessage( m_messages[i] );+ }+ }++ void Capturer::captureValue( size_t index, std::string const& value ) {+ assert( index < m_messages.size() );+ m_messages[index].message += value;+ m_resultCapture.pushScopedMessage( m_messages[index] );+ m_captured++;+ }++} // end namespace Catch+// end catch_message.cpp+// start catch_output_redirect.cpp++// start catch_output_redirect.h+#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H+#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H++#include <cstdio>+#include <iosfwd>+#include <string>++namespace Catch {++ class RedirectedStream {+ std::ostream& m_originalStream;+ std::ostream& m_redirectionStream;+ std::streambuf* m_prevBuf;++ public:+ RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );+ ~RedirectedStream();+ };++ class RedirectedStdOut {+ ReusableStringStream m_rss;+ RedirectedStream m_cout;+ public:+ RedirectedStdOut();+ auto str() const -> std::string;+ };++ // StdErr has two constituent streams in C++, std::cerr and std::clog+ // This means that we need to redirect 2 streams into 1 to keep proper+ // order of writes+ class RedirectedStdErr {+ ReusableStringStream m_rss;+ RedirectedStream m_cerr;+ RedirectedStream m_clog;+ public:+ RedirectedStdErr();+ auto str() const -> std::string;+ };++ class RedirectedStreams {+ public:+ RedirectedStreams(RedirectedStreams const&) = delete;+ RedirectedStreams& operator=(RedirectedStreams const&) = delete;+ RedirectedStreams(RedirectedStreams&&) = delete;+ RedirectedStreams& operator=(RedirectedStreams&&) = delete;++ RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);+ ~RedirectedStreams();+ private:+ std::string& m_redirectedCout;+ std::string& m_redirectedCerr;+ RedirectedStdOut m_redirectedStdOut;+ RedirectedStdErr m_redirectedStdErr;+ };++#if defined(CATCH_CONFIG_NEW_CAPTURE)++ // Windows's implementation of std::tmpfile is terrible (it tries+ // to create a file inside system folder, thus requiring elevated+ // privileges for the binary), so we have to use tmpnam(_s) and+ // create the file ourselves there.+ class TempFile {+ public:+ TempFile(TempFile const&) = delete;+ TempFile& operator=(TempFile const&) = delete;+ TempFile(TempFile&&) = delete;+ TempFile& operator=(TempFile&&) = delete;++ TempFile();+ ~TempFile();++ std::FILE* getFile();+ std::string getContents();++ private:+ std::FILE* m_file = nullptr;+ #if defined(_MSC_VER)+ char m_buffer[L_tmpnam] = { 0 };+ #endif+ };++ class OutputRedirect {+ public:+ OutputRedirect(OutputRedirect const&) = delete;+ OutputRedirect& operator=(OutputRedirect const&) = delete;+ OutputRedirect(OutputRedirect&&) = delete;+ OutputRedirect& operator=(OutputRedirect&&) = delete;++ OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);+ ~OutputRedirect();++ private:+ int m_originalStdout = -1;+ int m_originalStderr = -1;+ TempFile m_stdoutFile;+ TempFile m_stderrFile;+ std::string& m_stdoutDest;+ std::string& m_stderrDest;+ };++#endif++} // end namespace Catch++#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H+// end catch_output_redirect.h+#include <cstdio>+#include <cstring>+#include <fstream>+#include <sstream>+#include <stdexcept>++#if defined(CATCH_CONFIG_NEW_CAPTURE)+ #if defined(_MSC_VER)+ #include <io.h> //_dup and _dup2+ #define dup _dup+ #define dup2 _dup2+ #define fileno _fileno+ #else+ #include <unistd.h> // dup and dup2+ #endif+#endif++namespace Catch {++ RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )+ : m_originalStream( originalStream ),+ m_redirectionStream( redirectionStream ),+ m_prevBuf( m_originalStream.rdbuf() )+ {+ m_originalStream.rdbuf( m_redirectionStream.rdbuf() );+ }++ RedirectedStream::~RedirectedStream() {+ m_originalStream.rdbuf( m_prevBuf );+ }++ RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}+ auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }++ RedirectedStdErr::RedirectedStdErr()+ : m_cerr( Catch::cerr(), m_rss.get() ),+ m_clog( Catch::clog(), m_rss.get() )+ {}+ auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }++ RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)+ : m_redirectedCout(redirectedCout),+ m_redirectedCerr(redirectedCerr)+ {}++ RedirectedStreams::~RedirectedStreams() {+ m_redirectedCout += m_redirectedStdOut.str();+ m_redirectedCerr += m_redirectedStdErr.str();+ }++#if defined(CATCH_CONFIG_NEW_CAPTURE)++#if defined(_MSC_VER)+ TempFile::TempFile() {+ if (tmpnam_s(m_buffer)) {+ CATCH_RUNTIME_ERROR("Could not get a temp filename");+ }+ if (fopen_s(&m_file, m_buffer, "w+")) {+ char buffer[100];+ if (strerror_s(buffer, errno)) {+ CATCH_RUNTIME_ERROR("Could not translate errno to a string");+ }+ CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer);+ }+ }+#else+ TempFile::TempFile() {+ m_file = std::tmpfile();+ if (!m_file) {+ CATCH_RUNTIME_ERROR("Could not create a temp file.");+ }+ }++#endif++ TempFile::~TempFile() {+ // TBD: What to do about errors here?+ std::fclose(m_file);+ // We manually create the file on Windows only, on Linux+ // it will be autodeleted+#if defined(_MSC_VER)+ std::remove(m_buffer);+#endif+ }++ FILE* TempFile::getFile() {+ return m_file;+ }++ std::string TempFile::getContents() {+ std::stringstream sstr;+ char buffer[100] = {};+ std::rewind(m_file);+ while (std::fgets(buffer, sizeof(buffer), m_file)) {+ sstr << buffer;+ }+ return sstr.str();+ }++ OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :+ m_originalStdout(dup(1)),+ m_originalStderr(dup(2)),+ m_stdoutDest(stdout_dest),+ m_stderrDest(stderr_dest) {+ dup2(fileno(m_stdoutFile.getFile()), 1);+ dup2(fileno(m_stderrFile.getFile()), 2);+ }++ OutputRedirect::~OutputRedirect() {+ Catch::cout() << std::flush;+ fflush(stdout);+ // Since we support overriding these streams, we flush cerr+ // even though std::cerr is unbuffered+ Catch::cerr() << std::flush;+ Catch::clog() << std::flush;+ fflush(stderr);++ dup2(m_originalStdout, 1);+ dup2(m_originalStderr, 2);++ m_stdoutDest += m_stdoutFile.getContents();+ m_stderrDest += m_stderrFile.getContents();+ }++#endif // CATCH_CONFIG_NEW_CAPTURE++} // namespace Catch++#if defined(CATCH_CONFIG_NEW_CAPTURE)+ #if defined(_MSC_VER)+ #undef dup+ #undef dup2+ #undef fileno+ #endif+#endif+// end catch_output_redirect.cpp+// start catch_polyfills.cpp++#include <cmath>++namespace Catch {++#if !defined(CATCH_CONFIG_POLYFILL_ISNAN)+ bool isnan(float f) {+ return std::isnan(f);+ }+ bool isnan(double d) {+ return std::isnan(d);+ }+#else+ // For now we only use this for embarcadero+ bool isnan(float f) {+ return std::_isnan(f);+ }+ bool isnan(double d) {+ return std::_isnan(d);+ }+#endif++} // end namespace Catch+// end catch_polyfills.cpp+// start catch_random_number_generator.cpp++namespace Catch {++namespace {++#if defined(_MSC_VER)+#pragma warning(push)+#pragma warning(disable:4146) // we negate uint32 during the rotate+#endif+ // Safe rotr implementation thanks to John Regehr+ uint32_t rotate_right(uint32_t val, uint32_t count) {+ const uint32_t mask = 31;+ count &= mask;+ return (val >> count) | (val << (-count & mask));+ }++#if defined(_MSC_VER)+#pragma warning(pop)+#endif++}++ SimplePcg32::SimplePcg32(result_type seed_) {+ seed(seed_);+ }++ void SimplePcg32::seed(result_type seed_) {+ m_state = 0;+ (*this)();+ m_state += seed_;+ (*this)();+ }++ void SimplePcg32::discard(uint64_t skip) {+ // We could implement this to run in O(log n) steps, but this+ // should suffice for our use case.+ for (uint64_t s = 0; s < skip; ++s) {+ static_cast<void>((*this)());+ }+ }++ SimplePcg32::result_type SimplePcg32::operator()() {+ // prepare the output value+ const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u);+ const auto output = rotate_right(xorshifted, m_state >> 59u);++ // advance state+ m_state = m_state * 6364136223846793005ULL + s_inc;++ return output;+ }++ bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {+ return lhs.m_state == rhs.m_state;+ }++ bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {+ return lhs.m_state != rhs.m_state;+ }+}+// end catch_random_number_generator.cpp+// start catch_registry_hub.cpp++// start catch_test_case_registry_impl.h++#include <vector>+#include <set>+#include <algorithm>+#include <ios>++namespace Catch {++ class TestCase;+ struct IConfig;++ std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );++ bool isThrowSafe( TestCase const& testCase, IConfig const& config );+ bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );++ void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );++ std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );+ std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );++ class TestRegistry : public ITestCaseRegistry {+ public:+ virtual ~TestRegistry() = default;++ virtual void registerTest( TestCase const& testCase );++ std::vector<TestCase> const& getAllTests() const override;+ std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override;++ private:+ std::vector<TestCase> m_functions;+ mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder;+ mutable std::vector<TestCase> m_sortedFunctions;+ std::size_t m_unnamedCount = 0;+ std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised+ };++ ///////////////////////////////////////////////////////////////////////////++ class TestInvokerAsFunction : public ITestInvoker {+ void(*m_testAsFunction)();+ public:+ TestInvokerAsFunction( void(*testAsFunction)() ) noexcept;++ void invoke() const override;+ };++ std::string extractClassName( StringRef const& classOrQualifiedMethodName );++ ///////////////////////////////////////////////////////////////////////////++} // end namespace Catch++// end catch_test_case_registry_impl.h+// start catch_reporter_registry.h++#include <map>++namespace Catch {++ class ReporterRegistry : public IReporterRegistry {++ public:++ ~ReporterRegistry() override;++ IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override;++ void registerReporter( std::string const& name, IReporterFactoryPtr const& factory );+ void registerListener( IReporterFactoryPtr const& factory );++ FactoryMap const& getFactories() const override;+ Listeners const& getListeners() const override;++ private:+ FactoryMap m_factories;+ Listeners m_listeners;+ };+}++// end catch_reporter_registry.h+// start catch_tag_alias_registry.h++// start catch_tag_alias.h++#include <string>++namespace Catch {++ struct TagAlias {+ TagAlias(std::string const& _tag, SourceLineInfo _lineInfo);++ std::string tag;+ SourceLineInfo lineInfo;+ };++} // end namespace Catch++// end catch_tag_alias.h+#include <map>++namespace Catch {++ class TagAliasRegistry : public ITagAliasRegistry {+ public:+ ~TagAliasRegistry() override;+ TagAlias const* find( std::string const& alias ) const override;+ std::string expandAliases( std::string const& unexpandedTestSpec ) const override;+ void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );++ private:+ std::map<std::string, TagAlias> m_registry;+ };++} // end namespace Catch++// end catch_tag_alias_registry.h+// start catch_startup_exception_registry.h++#include <vector>+#include <exception>++namespace Catch {++ class StartupExceptionRegistry {+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+ public:+ void add(std::exception_ptr const& exception) noexcept;+ std::vector<std::exception_ptr> const& getExceptions() const noexcept;+ private:+ std::vector<std::exception_ptr> m_exceptions;+#endif+ };++} // end namespace Catch++// end catch_startup_exception_registry.h+// start catch_singletons.hpp++namespace Catch {++ struct ISingleton {+ virtual ~ISingleton();+ };++ void addSingleton( ISingleton* singleton );+ void cleanupSingletons();++ template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>+ class Singleton : SingletonImplT, public ISingleton {++ static auto getInternal() -> Singleton* {+ static Singleton* s_instance = nullptr;+ if( !s_instance ) {+ s_instance = new Singleton;+ addSingleton( s_instance );+ }+ return s_instance;+ }++ public:+ static auto get() -> InterfaceT const& {+ return *getInternal();+ }+ static auto getMutable() -> MutableInterfaceT& {+ return *getInternal();+ }+ };++} // namespace Catch++// end catch_singletons.hpp+namespace Catch {++ namespace {++ class RegistryHub : public IRegistryHub, public IMutableRegistryHub,+ private NonCopyable {++ public: // IRegistryHub+ RegistryHub() = default;+ IReporterRegistry const& getReporterRegistry() const override {+ return m_reporterRegistry;+ }+ ITestCaseRegistry const& getTestCaseRegistry() const override {+ return m_testCaseRegistry;+ }+ IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {+ return m_exceptionTranslatorRegistry;+ }+ ITagAliasRegistry const& getTagAliasRegistry() const override {+ return m_tagAliasRegistry;+ }+ StartupExceptionRegistry const& getStartupExceptionRegistry() const override {+ return m_exceptionRegistry;+ }++ public: // IMutableRegistryHub+ void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override {+ m_reporterRegistry.registerReporter( name, factory );+ }+ void registerListener( IReporterFactoryPtr const& factory ) override {+ m_reporterRegistry.registerListener( factory );+ }+ void registerTest( TestCase const& testInfo ) override {+ m_testCaseRegistry.registerTest( testInfo );+ }+ void registerTranslator( const IExceptionTranslator* translator ) override {+ m_exceptionTranslatorRegistry.registerTranslator( translator );+ }+ void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {+ m_tagAliasRegistry.add( alias, tag, lineInfo );+ }+ void registerStartupException() noexcept override {+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+ m_exceptionRegistry.add(std::current_exception());+#else+ CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");+#endif+ }+ IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {+ return m_enumValuesRegistry;+ }++ private:+ TestRegistry m_testCaseRegistry;+ ReporterRegistry m_reporterRegistry;+ ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;+ TagAliasRegistry m_tagAliasRegistry;+ StartupExceptionRegistry m_exceptionRegistry;+ Detail::EnumValuesRegistry m_enumValuesRegistry;+ };+ }++ using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;++ IRegistryHub const& getRegistryHub() {+ return RegistryHubSingleton::get();+ }+ IMutableRegistryHub& getMutableRegistryHub() {+ return RegistryHubSingleton::getMutable();+ }+ void cleanUp() {+ cleanupSingletons();+ cleanUpContext();+ }+ std::string translateActiveException() {+ return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();+ }++} // end namespace Catch+// end catch_registry_hub.cpp+// start catch_reporter_registry.cpp++namespace Catch {++ ReporterRegistry::~ReporterRegistry() = default;++ IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const {+ auto it = m_factories.find( name );+ if( it == m_factories.end() )+ return nullptr;+ return it->second->create( ReporterConfig( config ) );+ }++ void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) {+ m_factories.emplace(name, factory);+ }+ void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) {+ m_listeners.push_back( factory );+ }++ IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const {+ return m_factories;+ }+ IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const {+ return m_listeners;+ }++}+// end catch_reporter_registry.cpp+// start catch_result_type.cpp++namespace Catch {++ bool isOk( ResultWas::OfType resultType ) {+ return ( resultType & ResultWas::FailureBit ) == 0;+ }+ bool isJustInfo( int flags ) {+ return flags == ResultWas::Info;+ }++ ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {+ return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );+ }++ bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }+ bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }++} // end namespace Catch+// end catch_result_type.cpp+// start catch_run_context.cpp++#include <cassert>+#include <algorithm>+#include <sstream>++namespace Catch {++ namespace Generators {+ struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {+ GeneratorBasePtr m_generator;++ GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )+ : TrackerBase( nameAndLocation, ctx, parent )+ {}+ ~GeneratorTracker();++ static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {+ std::shared_ptr<GeneratorTracker> tracker;++ ITracker& currentTracker = ctx.currentTracker();+ // Under specific circumstances, the generator we want+ // to acquire is also the current tracker. If this is+ // the case, we have to avoid looking through current+ // tracker's children, and instead return the current+ // tracker.+ // A case where this check is important is e.g.+ // for (int i = 0; i < 5; ++i) {+ // int n = GENERATE(1, 2);+ // }+ //+ // without it, the code above creates 5 nested generators.+ if (currentTracker.nameAndLocation() == nameAndLocation) {+ auto thisTracker = currentTracker.parent().findChild(nameAndLocation);+ assert(thisTracker);+ assert(thisTracker->isGeneratorTracker());+ tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker);+ } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {+ assert( childTracker );+ assert( childTracker->isGeneratorTracker() );+ tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );+ } else {+ tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker );+ currentTracker.addChild( tracker );+ }++ if( !tracker->isComplete() ) {+ tracker->open();+ }++ return *tracker;+ }++ // TrackerBase interface+ bool isGeneratorTracker() const override { return true; }+ auto hasGenerator() const -> bool override {+ return !!m_generator;+ }+ void close() override {+ TrackerBase::close();+ // If a generator has a child (it is followed by a section)+ // and none of its children have started, then we must wait+ // until later to start consuming its values.+ // This catches cases where `GENERATE` is placed between two+ // `SECTION`s.+ // **The check for m_children.empty cannot be removed**.+ // doing so would break `GENERATE` _not_ followed by `SECTION`s.+ const bool should_wait_for_child = [&]() {+ // No children -> nobody to wait for+ if ( m_children.empty() ) {+ return false;+ }+ // If at least one child started executing, don't wait+ if ( std::find_if(+ m_children.begin(),+ m_children.end(),+ []( TestCaseTracking::ITrackerPtr tracker ) {+ return tracker->hasStarted();+ } ) != m_children.end() ) {+ return false;+ }++ // No children have started. We need to check if they _can_+ // start, and thus we should wait for them, or they cannot+ // start (due to filters), and we shouldn't wait for them+ auto* parent = m_parent;+ // This is safe: there is always at least one section+ // tracker in a test case tracking tree+ while ( !parent->isSectionTracker() ) {+ parent = &( parent->parent() );+ }+ assert( parent &&+ "Missing root (test case) level section" );++ auto const& parentSection =+ static_cast<SectionTracker&>( *parent );+ auto const& filters = parentSection.getFilters();+ // No filters -> no restrictions on running sections+ if ( filters.empty() ) {+ return true;+ }++ for ( auto const& child : m_children ) {+ if ( child->isSectionTracker() &&+ std::find( filters.begin(),+ filters.end(),+ static_cast<SectionTracker&>( *child )+ .trimmedName() ) !=+ filters.end() ) {+ return true;+ }+ }+ return false;+ }();++ // This check is a bit tricky, because m_generator->next()+ // has a side-effect, where it consumes generator's current+ // value, but we do not want to invoke the side-effect if+ // this generator is still waiting for any child to start.+ if ( should_wait_for_child ||+ ( m_runState == CompletedSuccessfully &&+ m_generator->next() ) ) {+ m_children.clear();+ m_runState = Executing;+ }+ }++ // IGeneratorTracker interface+ auto getGenerator() const -> GeneratorBasePtr const& override {+ return m_generator;+ }+ void setGenerator( GeneratorBasePtr&& generator ) override {+ m_generator = std::move( generator );+ }+ };+ GeneratorTracker::~GeneratorTracker() {}+ }++ RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)+ : m_runInfo(_config->name()),+ m_context(getCurrentMutableContext()),+ m_config(_config),+ m_reporter(std::move(reporter)),+ m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },+ m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )+ {+ m_context.setRunner(this);+ m_context.setConfig(m_config);+ m_context.setResultCapture(this);+ m_reporter->testRunStarting(m_runInfo);+ }++ RunContext::~RunContext() {+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));+ }++ void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) {+ m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount));+ }++ void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) {+ m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting()));+ }++ Totals RunContext::runTest(TestCase const& testCase) {+ Totals prevTotals = m_totals;++ std::string redirectedCout;+ std::string redirectedCerr;++ auto const& testInfo = testCase.getTestCaseInfo();++ m_reporter->testCaseStarting(testInfo);++ m_activeTestCase = &testCase;++ ITracker& rootTracker = m_trackerContext.startRun();+ assert(rootTracker.isSectionTracker());+ static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());+ do {+ m_trackerContext.startCycle();+ m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo));+ runCurrentTest(redirectedCout, redirectedCerr);+ } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());++ Totals deltaTotals = m_totals.delta(prevTotals);+ if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {+ deltaTotals.assertions.failed++;+ deltaTotals.testCases.passed--;+ deltaTotals.testCases.failed++;+ }+ m_totals.testCases += deltaTotals.testCases;+ m_reporter->testCaseEnded(TestCaseStats(testInfo,+ deltaTotals,+ redirectedCout,+ redirectedCerr,+ aborting()));++ m_activeTestCase = nullptr;+ m_testCaseTracker = nullptr;++ return deltaTotals;+ }++ IConfigPtr RunContext::config() const {+ return m_config;+ }++ IStreamingReporter& RunContext::reporter() const {+ return *m_reporter;+ }++ void RunContext::assertionEnded(AssertionResult const & result) {+ if (result.getResultType() == ResultWas::Ok) {+ m_totals.assertions.passed++;+ m_lastAssertionPassed = true;+ } else if (!result.isOk()) {+ m_lastAssertionPassed = false;+ if( m_activeTestCase->getTestCaseInfo().okToFail() )+ m_totals.assertions.failedButOk++;+ else+ m_totals.assertions.failed++;+ }+ else {+ m_lastAssertionPassed = true;+ }++ // We have no use for the return value (whether messages should be cleared), because messages were made scoped+ // and should be let to clear themselves out.+ static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));++ if (result.getResultType() != ResultWas::Warning)+ m_messageScopes.clear();++ // Reset working state+ resetAssertionInfo();+ m_lastResult = result;+ }+ void RunContext::resetAssertionInfo() {+ m_lastAssertionInfo.macroName = StringRef();+ m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;+ }++ bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) {+ ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo));+ if (!sectionTracker.isOpen())+ return false;+ m_activeSections.push_back(§ionTracker);++ m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;++ m_reporter->sectionStarting(sectionInfo);++ assertions = m_totals.assertions;++ return true;+ }+ auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {+ using namespace Generators;+ GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext,+ TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) );+ m_lastAssertionInfo.lineInfo = lineInfo;+ return tracker;+ }++ bool RunContext::testForMissingAssertions(Counts& assertions) {+ if (assertions.total() != 0)+ return false;+ if (!m_config->warnAboutMissingAssertions())+ return false;+ if (m_trackerContext.currentTracker().hasChildren())+ return false;+ m_totals.assertions.failed++;+ assertions.failed++;+ return true;+ }++ void RunContext::sectionEnded(SectionEndInfo const & endInfo) {+ Counts assertions = m_totals.assertions - endInfo.prevAssertions;+ bool missingAssertions = testForMissingAssertions(assertions);++ if (!m_activeSections.empty()) {+ m_activeSections.back()->close();+ m_activeSections.pop_back();+ }++ m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));+ m_messages.clear();+ m_messageScopes.clear();+ }++ void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {+ if (m_unfinishedSections.empty())+ m_activeSections.back()->fail();+ else+ m_activeSections.back()->close();+ m_activeSections.pop_back();++ m_unfinishedSections.push_back(endInfo);+ }++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+ void RunContext::benchmarkPreparing(std::string const& name) {+ m_reporter->benchmarkPreparing(name);+ }+ void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {+ m_reporter->benchmarkStarting( info );+ }+ void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {+ m_reporter->benchmarkEnded( stats );+ }+ void RunContext::benchmarkFailed(std::string const & error) {+ m_reporter->benchmarkFailed(error);+ }+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++ void RunContext::pushScopedMessage(MessageInfo const & message) {+ m_messages.push_back(message);+ }++ void RunContext::popScopedMessage(MessageInfo const & message) {+ m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());+ }++ void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) {+ m_messageScopes.emplace_back( builder );+ }++ std::string RunContext::getCurrentTestName() const {+ return m_activeTestCase+ ? m_activeTestCase->getTestCaseInfo().name+ : std::string();+ }++ const AssertionResult * RunContext::getLastResult() const {+ return &(*m_lastResult);+ }++ void RunContext::exceptionEarlyReported() {+ m_shouldReportUnexpected = false;+ }++ void RunContext::handleFatalErrorCondition( StringRef message ) {+ // First notify reporter that bad things happened+ m_reporter->fatalErrorEncountered(message);++ // Don't rebuild the result -- the stringification itself can cause more fatal errors+ // Instead, fake a result data.+ AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );+ tempResult.message = static_cast<std::string>(message);+ AssertionResult result(m_lastAssertionInfo, tempResult);++ assertionEnded(result);++ handleUnfinishedSections();++ // Recreate section for test case (as we will lose the one that was in scope)+ auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);++ Counts assertions;+ assertions.failed = 1;+ SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);+ m_reporter->sectionEnded(testCaseSectionStats);++ auto const& testInfo = m_activeTestCase->getTestCaseInfo();++ Totals deltaTotals;+ deltaTotals.testCases.failed = 1;+ deltaTotals.assertions.failed = 1;+ m_reporter->testCaseEnded(TestCaseStats(testInfo,+ deltaTotals,+ std::string(),+ std::string(),+ false));+ m_totals.testCases.failed++;+ testGroupEnded(std::string(), m_totals, 1, 1);+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));+ }++ bool RunContext::lastAssertionPassed() {+ return m_lastAssertionPassed;+ }++ void RunContext::assertionPassed() {+ m_lastAssertionPassed = true;+ ++m_totals.assertions.passed;+ resetAssertionInfo();+ m_messageScopes.clear();+ }++ bool RunContext::aborting() const {+ return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());+ }++ void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {+ auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);+ m_reporter->sectionStarting(testCaseSection);+ Counts prevAssertions = m_totals.assertions;+ double duration = 0;+ m_shouldReportUnexpected = true;+ m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };++ seedRng(*m_config);++ Timer timer;+ CATCH_TRY {+ if (m_reporter->getPreferences().shouldRedirectStdOut) {+#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)+ RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);++ timer.start();+ invokeActiveTestCase();+#else+ OutputRedirect r(redirectedCout, redirectedCerr);+ timer.start();+ invokeActiveTestCase();+#endif+ } else {+ timer.start();+ invokeActiveTestCase();+ }+ duration = timer.getElapsedSeconds();+ } CATCH_CATCH_ANON (TestFailureException&) {+ // This just means the test was aborted due to failure+ } CATCH_CATCH_ALL {+ // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions+ // are reported without translation at the point of origin.+ if( m_shouldReportUnexpected ) {+ AssertionReaction dummyReaction;+ handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );+ }+ }+ Counts assertions = m_totals.assertions - prevAssertions;+ bool missingAssertions = testForMissingAssertions(assertions);++ m_testCaseTracker->close();+ handleUnfinishedSections();+ m_messages.clear();+ m_messageScopes.clear();++ SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);+ m_reporter->sectionEnded(testCaseSectionStats);+ }++ void RunContext::invokeActiveTestCase() {+ FatalConditionHandlerGuard _(&m_fatalConditionhandler);+ m_activeTestCase->invoke();+ }++ void RunContext::handleUnfinishedSections() {+ // If sections ended prematurely due to an exception we stored their+ // infos here so we can tear them down outside the unwind process.+ for (auto it = m_unfinishedSections.rbegin(),+ itEnd = m_unfinishedSections.rend();+ it != itEnd;+ ++it)+ sectionEnded(*it);+ m_unfinishedSections.clear();+ }++ void RunContext::handleExpr(+ AssertionInfo const& info,+ ITransientExpression const& expr,+ AssertionReaction& reaction+ ) {+ m_reporter->assertionStarting( info );++ bool negated = isFalseTest( info.resultDisposition );+ bool result = expr.getResult() != negated;++ if( result ) {+ if (!m_includeSuccessfulResults) {+ assertionPassed();+ }+ else {+ reportExpr(info, ResultWas::Ok, &expr, negated);+ }+ }+ else {+ reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );+ populateReaction( reaction );+ }+ }+ void RunContext::reportExpr(+ AssertionInfo const &info,+ ResultWas::OfType resultType,+ ITransientExpression const *expr,+ bool negated ) {++ m_lastAssertionInfo = info;+ AssertionResultData data( resultType, LazyExpression( negated ) );++ AssertionResult assertionResult{ info, data };+ assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;++ assertionEnded( assertionResult );+ }++ void RunContext::handleMessage(+ AssertionInfo const& info,+ ResultWas::OfType resultType,+ StringRef const& message,+ AssertionReaction& reaction+ ) {+ m_reporter->assertionStarting( info );++ m_lastAssertionInfo = info;++ AssertionResultData data( resultType, LazyExpression( false ) );+ data.message = static_cast<std::string>(message);+ AssertionResult assertionResult{ m_lastAssertionInfo, data };+ assertionEnded( assertionResult );+ if( !assertionResult.isOk() )+ populateReaction( reaction );+ }+ void RunContext::handleUnexpectedExceptionNotThrown(+ AssertionInfo const& info,+ AssertionReaction& reaction+ ) {+ handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction);+ }++ void RunContext::handleUnexpectedInflightException(+ AssertionInfo const& info,+ std::string const& message,+ AssertionReaction& reaction+ ) {+ m_lastAssertionInfo = info;++ AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );+ data.message = message;+ AssertionResult assertionResult{ info, data };+ assertionEnded( assertionResult );+ populateReaction( reaction );+ }++ void RunContext::populateReaction( AssertionReaction& reaction ) {+ reaction.shouldDebugBreak = m_config->shouldDebugBreak();+ reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal);+ }++ void RunContext::handleIncomplete(+ AssertionInfo const& info+ ) {+ m_lastAssertionInfo = info;++ AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );+ data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";+ AssertionResult assertionResult{ info, data };+ assertionEnded( assertionResult );+ }+ void RunContext::handleNonExpr(+ AssertionInfo const &info,+ ResultWas::OfType resultType,+ AssertionReaction &reaction+ ) {+ m_lastAssertionInfo = info;++ AssertionResultData data( resultType, LazyExpression( false ) );+ AssertionResult assertionResult{ info, data };+ assertionEnded( assertionResult );++ if( !assertionResult.isOk() )+ populateReaction( reaction );+ }++ IResultCapture& getResultCapture() {+ if (auto* capture = getCurrentContext().getResultCapture())+ return *capture;+ else+ CATCH_INTERNAL_ERROR("No result capture instance");+ }++ void seedRng(IConfig const& config) {+ if (config.rngSeed() != 0) {+ std::srand(config.rngSeed());+ rng().seed(config.rngSeed());+ }+ }++ unsigned int rngSeed() {+ return getCurrentContext().getConfig()->rngSeed();+ }++}+// end catch_run_context.cpp+// start catch_section.cpp++namespace Catch {++ Section::Section( SectionInfo const& info )+ : m_info( info ),+ m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )+ {+ m_timer.start();+ }++ Section::~Section() {+ if( m_sectionIncluded ) {+ SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };+ if( uncaught_exceptions() )+ getResultCapture().sectionEndedEarly( endInfo );+ else+ getResultCapture().sectionEnded( endInfo );+ }+ }++ // This indicates whether the section should be executed or not+ Section::operator bool() const {+ return m_sectionIncluded;+ }++} // end namespace Catch+// end catch_section.cpp+// start catch_section_info.cpp++namespace Catch {++ SectionInfo::SectionInfo+ ( SourceLineInfo const& _lineInfo,+ std::string const& _name )+ : name( _name ),+ lineInfo( _lineInfo )+ {}++} // end namespace Catch+// end catch_section_info.cpp+// start catch_session.cpp++// start catch_session.h++#include <memory>++namespace Catch {++ class Session : NonCopyable {+ public:++ Session();+ ~Session() override;++ void showHelp() const;+ void libIdentify();++ int applyCommandLine( int argc, char const * const * argv );+ #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)+ int applyCommandLine( int argc, wchar_t const * const * argv );+ #endif++ void useConfigData( ConfigData const& configData );++ template<typename CharT>+ int run(int argc, CharT const * const argv[]) {+ if (m_startupExceptions)+ return 1;+ int returnCode = applyCommandLine(argc, argv);+ if (returnCode == 0)+ returnCode = run();+ return returnCode;+ }++ int run();++ clara::Parser const& cli() const;+ void cli( clara::Parser const& newParser );+ ConfigData& configData();+ Config& config();+ private:+ int runInternal();++ clara::Parser m_cli;+ ConfigData m_configData;+ std::shared_ptr<Config> m_config;+ bool m_startupExceptions = false;+ };++} // end namespace Catch++// end catch_session.h+// start catch_version.h++#include <iosfwd>++namespace Catch {++ // Versioning information+ struct Version {+ Version( Version const& ) = delete;+ Version& operator=( Version const& ) = delete;+ Version( unsigned int _majorVersion,+ unsigned int _minorVersion,+ unsigned int _patchNumber,+ char const * const _branchName,+ unsigned int _buildNumber );++ unsigned int const majorVersion;+ unsigned int const minorVersion;+ unsigned int const patchNumber;++ // buildNumber is only used if branchName is not null+ char const * const branchName;+ unsigned int const buildNumber;++ friend std::ostream& operator << ( std::ostream& os, Version const& version );+ };++ Version const& libraryVersion();+}++// end catch_version.h+#include <cstdlib>+#include <iomanip>+#include <set>+#include <iterator>++namespace Catch {++ namespace {+ const int MaxExitCode = 255;++ IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) {+ auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config);+ CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'");++ return reporter;+ }++ IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {+ if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {+ return createReporter(config->getReporterName(), config);+ }++ // On older platforms, returning std::unique_ptr<ListeningReporter>+ // when the return type is std::unique_ptr<IStreamingReporter>+ // doesn't compile without a std::move call. However, this causes+ // a warning on newer platforms. Thus, we have to work around+ // it a bit and downcast the pointer manually.+ auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter);+ auto& multi = static_cast<ListeningReporter&>(*ret);+ auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();+ for (auto const& listener : listeners) {+ multi.addListener(listener->create(Catch::ReporterConfig(config)));+ }+ multi.addReporter(createReporter(config->getReporterName(), config));+ return ret;+ }++ class TestGroup {+ public:+ explicit TestGroup(std::shared_ptr<Config> const& config)+ : m_config{config}+ , m_context{config, makeReporter(config)}+ {+ auto const& allTestCases = getAllTestCasesSorted(*m_config);+ m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);+ auto const& invalidArgs = m_config->testSpec().getInvalidArgs();++ if (m_matches.empty() && invalidArgs.empty()) {+ for (auto const& test : allTestCases)+ if (!test.isHidden())+ m_tests.emplace(&test);+ } else {+ for (auto const& match : m_matches)+ m_tests.insert(match.tests.begin(), match.tests.end());+ }+ }++ Totals execute() {+ auto const& invalidArgs = m_config->testSpec().getInvalidArgs();+ Totals totals;+ m_context.testGroupStarting(m_config->name(), 1, 1);+ for (auto const& testCase : m_tests) {+ if (!m_context.aborting())+ totals += m_context.runTest(*testCase);+ else+ m_context.reporter().skipTest(*testCase);+ }++ for (auto const& match : m_matches) {+ if (match.tests.empty()) {+ m_context.reporter().noMatchingTestCases(match.name);+ totals.error = -1;+ }+ }++ if (!invalidArgs.empty()) {+ for (auto const& invalidArg: invalidArgs)+ m_context.reporter().reportInvalidArguments(invalidArg);+ }++ m_context.testGroupEnded(m_config->name(), totals, 1, 1);+ return totals;+ }++ private:+ using Tests = std::set<TestCase const*>;++ std::shared_ptr<Config> m_config;+ RunContext m_context;+ Tests m_tests;+ TestSpec::Matches m_matches;+ };++ void applyFilenamesAsTags(Catch::IConfig const& config) {+ auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));+ for (auto& testCase : tests) {+ auto tags = testCase.tags;++ std::string filename = testCase.lineInfo.file;+ auto lastSlash = filename.find_last_of("\\/");+ if (lastSlash != std::string::npos) {+ filename.erase(0, lastSlash);+ filename[0] = '#';+ }++ auto lastDot = filename.find_last_of('.');+ if (lastDot != std::string::npos) {+ filename.erase(lastDot);+ }++ tags.push_back(std::move(filename));+ setTags(testCase, tags);+ }+ }++ } // anon namespace++ Session::Session() {+ static bool alreadyInstantiated = false;+ if( alreadyInstantiated ) {+ CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }+ CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }+ }++ // There cannot be exceptions at startup in no-exception mode.+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+ const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();+ if ( !exceptions.empty() ) {+ config();+ getCurrentMutableContext().setConfig(m_config);++ m_startupExceptions = true;+ Colour colourGuard( Colour::Red );+ Catch::cerr() << "Errors occurred during startup!" << '\n';+ // iterate over all exceptions and notify user+ for ( const auto& ex_ptr : exceptions ) {+ try {+ std::rethrow_exception(ex_ptr);+ } catch ( std::exception const& ex ) {+ Catch::cerr() << Column( ex.what() ).indent(2) << '\n';+ }+ }+ }+#endif++ alreadyInstantiated = true;+ m_cli = makeCommandLineParser( m_configData );+ }+ Session::~Session() {+ Catch::cleanUp();+ }++ void Session::showHelp() const {+ Catch::cout()+ << "\nCatch v" << libraryVersion() << "\n"+ << m_cli << std::endl+ << "For more detailed usage please see the project docs\n" << std::endl;+ }+ void Session::libIdentify() {+ Catch::cout()+ << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"+ << std::left << std::setw(16) << "category: " << "testframework\n"+ << std::left << std::setw(16) << "framework: " << "Catch Test\n"+ << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;+ }++ int Session::applyCommandLine( int argc, char const * const * argv ) {+ if( m_startupExceptions )+ return 1;++ auto result = m_cli.parse( clara::Args( argc, argv ) );+ if( !result ) {+ config();+ getCurrentMutableContext().setConfig(m_config);+ Catch::cerr()+ << Colour( Colour::Red )+ << "\nError(s) in input:\n"+ << Column( result.errorMessage() ).indent( 2 )+ << "\n\n";+ Catch::cerr() << "Run with -? for usage\n" << std::endl;+ return MaxExitCode;+ }++ if( m_configData.showHelp )+ showHelp();+ if( m_configData.libIdentify )+ libIdentify();+ m_config.reset();+ return 0;+ }++#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)+ int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {++ char **utf8Argv = new char *[ argc ];++ for ( int i = 0; i < argc; ++i ) {+ int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );++ utf8Argv[ i ] = new char[ bufSize ];++ WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );+ }++ int returnCode = applyCommandLine( argc, utf8Argv );++ for ( int i = 0; i < argc; ++i )+ delete [] utf8Argv[ i ];++ delete [] utf8Argv;++ return returnCode;+ }+#endif++ void Session::useConfigData( ConfigData const& configData ) {+ m_configData = configData;+ m_config.reset();+ }++ int Session::run() {+ if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {+ Catch::cout() << "...waiting for enter/ return before starting" << std::endl;+ static_cast<void>(std::getchar());+ }+ int exitCode = runInternal();+ if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {+ Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;+ static_cast<void>(std::getchar());+ }+ return exitCode;+ }++ clara::Parser const& Session::cli() const {+ return m_cli;+ }+ void Session::cli( clara::Parser const& newParser ) {+ m_cli = newParser;+ }+ ConfigData& Session::configData() {+ return m_configData;+ }+ Config& Session::config() {+ if( !m_config )+ m_config = std::make_shared<Config>( m_configData );+ return *m_config;+ }++ int Session::runInternal() {+ if( m_startupExceptions )+ return 1;++ if (m_configData.showHelp || m_configData.libIdentify) {+ return 0;+ }++ CATCH_TRY {+ config(); // Force config to be constructed++ seedRng( *m_config );++ if( m_configData.filenamesAsTags )+ applyFilenamesAsTags( *m_config );++ // Handle list request+ if( Option<std::size_t> listed = list( m_config ) )+ return static_cast<int>( *listed );++ TestGroup tests { m_config };+ auto const totals = tests.execute();++ if( m_config->warnAboutNoTests() && totals.error == -1 )+ return 2;++ // Note that on unices only the lower 8 bits are usually used, clamping+ // the return value to 255 prevents false negative when some multiple+ // of 256 tests has failed+ return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));+ }+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+ catch( std::exception& ex ) {+ Catch::cerr() << ex.what() << std::endl;+ return MaxExitCode;+ }+#endif+ }++} // end namespace Catch+// end catch_session.cpp+// start catch_singletons.cpp++#include <vector>++namespace Catch {++ namespace {+ static auto getSingletons() -> std::vector<ISingleton*>*& {+ static std::vector<ISingleton*>* g_singletons = nullptr;+ if( !g_singletons )+ g_singletons = new std::vector<ISingleton*>();+ return g_singletons;+ }+ }++ ISingleton::~ISingleton() {}++ void addSingleton(ISingleton* singleton ) {+ getSingletons()->push_back( singleton );+ }+ void cleanupSingletons() {+ auto& singletons = getSingletons();+ for( auto singleton : *singletons )+ delete singleton;+ delete singletons;+ singletons = nullptr;+ }++} // namespace Catch+// end catch_singletons.cpp+// start catch_startup_exception_registry.cpp++#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+namespace Catch {+void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {+ CATCH_TRY {+ m_exceptions.push_back(exception);+ } CATCH_CATCH_ALL {+ // If we run out of memory during start-up there's really not a lot more we can do about it+ std::terminate();+ }+ }++ std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept {+ return m_exceptions;+ }++} // end namespace Catch+#endif+// end catch_startup_exception_registry.cpp+// start catch_stream.cpp++#include <cstdio>+#include <iostream>+#include <fstream>+#include <sstream>+#include <vector>+#include <memory>++namespace Catch {++ Catch::IStream::~IStream() = default;++ namespace Detail { namespace {+ template<typename WriterF, std::size_t bufferSize=256>+ class StreamBufImpl : public std::streambuf {+ char data[bufferSize];+ WriterF m_writer;++ public:+ StreamBufImpl() {+ setp( data, data + sizeof(data) );+ }++ ~StreamBufImpl() noexcept {+ StreamBufImpl::sync();+ }++ private:+ int overflow( int c ) override {+ sync();++ if( c != EOF ) {+ if( pbase() == epptr() )+ m_writer( std::string( 1, static_cast<char>( c ) ) );+ else+ sputc( static_cast<char>( c ) );+ }+ return 0;+ }++ int sync() override {+ if( pbase() != pptr() ) {+ m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );+ setp( pbase(), epptr() );+ }+ return 0;+ }+ };++ ///////////////////////////////////////////////////////////////////////////++ struct OutputDebugWriter {++ void operator()( std::string const&str ) {+ writeToDebugConsole( str );+ }+ };++ ///////////////////////////////////////////////////////////////////////////++ class FileStream : public IStream {+ mutable std::ofstream m_ofs;+ public:+ FileStream( StringRef filename ) {+ m_ofs.open( filename.c_str() );+ CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" );+ }+ ~FileStream() override = default;+ public: // IStream+ std::ostream& stream() const override {+ return m_ofs;+ }+ };++ ///////////////////////////////////////////////////////////////////////////++ class CoutStream : public IStream {+ mutable std::ostream m_os;+ public:+ // Store the streambuf from cout up-front because+ // cout may get redirected when running tests+ CoutStream() : m_os( Catch::cout().rdbuf() ) {}+ ~CoutStream() override = default;++ public: // IStream+ std::ostream& stream() const override { return m_os; }+ };++ ///////////////////////////////////////////////////////////////////////////++ class DebugOutStream : public IStream {+ std::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;+ mutable std::ostream m_os;+ public:+ DebugOutStream()+ : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),+ m_os( m_streamBuf.get() )+ {}++ ~DebugOutStream() override = default;++ public: // IStream+ std::ostream& stream() const override { return m_os; }+ };++ }} // namespace anon::detail++ ///////////////////////////////////////////////////////////////////////////++ auto makeStream( StringRef const &filename ) -> IStream const* {+ if( filename.empty() )+ return new Detail::CoutStream();+ else if( filename[0] == '%' ) {+ if( filename == "%debug" )+ return new Detail::DebugOutStream();+ else+ CATCH_ERROR( "Unrecognised stream: '" << filename << "'" );+ }+ else+ return new Detail::FileStream( filename );+ }++ // This class encapsulates the idea of a pool of ostringstreams that can be reused.+ struct StringStreams {+ std::vector<std::unique_ptr<std::ostringstream>> m_streams;+ std::vector<std::size_t> m_unused;+ std::ostringstream m_referenceStream; // Used for copy state/ flags from++ auto add() -> std::size_t {+ if( m_unused.empty() ) {+ m_streams.push_back( std::unique_ptr<std::ostringstream>( new std::ostringstream ) );+ return m_streams.size()-1;+ }+ else {+ auto index = m_unused.back();+ m_unused.pop_back();+ return index;+ }+ }++ void release( std::size_t index ) {+ m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state+ m_unused.push_back(index);+ }+ };++ ReusableStringStream::ReusableStringStream()+ : m_index( Singleton<StringStreams>::getMutable().add() ),+ m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )+ {}++ ReusableStringStream::~ReusableStringStream() {+ static_cast<std::ostringstream*>( m_oss )->str("");+ m_oss->clear();+ Singleton<StringStreams>::getMutable().release( m_index );+ }++ auto ReusableStringStream::str() const -> std::string {+ return static_cast<std::ostringstream*>( m_oss )->str();+ }++ ///////////////////////////////////////////////////////////////////////////++#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions+ std::ostream& cout() { return std::cout; }+ std::ostream& cerr() { return std::cerr; }+ std::ostream& clog() { return std::clog; }+#endif+}+// end catch_stream.cpp+// start catch_string_manip.cpp++#include <algorithm>+#include <ostream>+#include <cstring>+#include <cctype>+#include <vector>++namespace Catch {++ namespace {+ char toLowerCh(char c) {+ return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) );+ }+ }++ bool startsWith( std::string const& s, std::string const& prefix ) {+ return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());+ }+ bool startsWith( std::string const& s, char prefix ) {+ return !s.empty() && s[0] == prefix;+ }+ bool endsWith( std::string const& s, std::string const& suffix ) {+ return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());+ }+ bool endsWith( std::string const& s, char suffix ) {+ return !s.empty() && s[s.size()-1] == suffix;+ }+ bool contains( std::string const& s, std::string const& infix ) {+ return s.find( infix ) != std::string::npos;+ }+ void toLowerInPlace( std::string& s ) {+ std::transform( s.begin(), s.end(), s.begin(), toLowerCh );+ }+ std::string toLower( std::string const& s ) {+ std::string lc = s;+ toLowerInPlace( lc );+ return lc;+ }+ std::string trim( std::string const& str ) {+ static char const* whitespaceChars = "\n\r\t ";+ std::string::size_type start = str.find_first_not_of( whitespaceChars );+ std::string::size_type end = str.find_last_not_of( whitespaceChars );++ return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();+ }++ StringRef trim(StringRef ref) {+ const auto is_ws = [](char c) {+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';+ };+ size_t real_begin = 0;+ while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; }+ size_t real_end = ref.size();+ while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; }++ return ref.substr(real_begin, real_end - real_begin);+ }++ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {+ bool replaced = false;+ std::size_t i = str.find( replaceThis );+ while( i != std::string::npos ) {+ replaced = true;+ str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );+ if( i < str.size()-withThis.size() )+ i = str.find( replaceThis, i+withThis.size() );+ else+ i = std::string::npos;+ }+ return replaced;+ }++ std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {+ std::vector<StringRef> subStrings;+ std::size_t start = 0;+ for(std::size_t pos = 0; pos < str.size(); ++pos ) {+ if( str[pos] == delimiter ) {+ if( pos - start > 1 )+ subStrings.push_back( str.substr( start, pos-start ) );+ start = pos+1;+ }+ }+ if( start < str.size() )+ subStrings.push_back( str.substr( start, str.size()-start ) );+ return subStrings;+ }++ pluralise::pluralise( std::size_t count, std::string const& label )+ : m_count( count ),+ m_label( label )+ {}++ std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {+ os << pluraliser.m_count << ' ' << pluraliser.m_label;+ if( pluraliser.m_count != 1 )+ os << 's';+ return os;+ }++}+// end catch_string_manip.cpp+// start catch_stringref.cpp++#include <algorithm>+#include <ostream>+#include <cstring>+#include <cstdint>++namespace Catch {+ StringRef::StringRef( char const* rawChars ) noexcept+ : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) )+ {}++ auto StringRef::c_str() const -> char const* {+ CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance");+ return m_start;+ }+ auto StringRef::data() const noexcept -> char const* {+ return m_start;+ }++ auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {+ if (start < m_size) {+ return StringRef(m_start + start, (std::min)(m_size - start, size));+ } else {+ return StringRef();+ }+ }+ auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {+ return m_size == other.m_size+ && (std::memcmp( m_start, other.m_start, m_size ) == 0);+ }++ auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {+ return os.write(str.data(), str.size());+ }++ auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {+ lhs.append(rhs.data(), rhs.size());+ return lhs;+ }++} // namespace Catch+// end catch_stringref.cpp+// start catch_tag_alias.cpp++namespace Catch {+ TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {}+}+// end catch_tag_alias.cpp+// start catch_tag_alias_autoregistrar.cpp++namespace Catch {++ RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {+ CATCH_TRY {+ getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);+ } CATCH_CATCH_ALL {+ // Do not throw when constructing global objects, instead register the exception to be processed later+ getMutableRegistryHub().registerStartupException();+ }+ }++}+// end catch_tag_alias_autoregistrar.cpp+// start catch_tag_alias_registry.cpp++#include <sstream>++namespace Catch {++ TagAliasRegistry::~TagAliasRegistry() {}++ TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {+ auto it = m_registry.find( alias );+ if( it != m_registry.end() )+ return &(it->second);+ else+ return nullptr;+ }++ std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {+ std::string expandedTestSpec = unexpandedTestSpec;+ for( auto const& registryKvp : m_registry ) {+ std::size_t pos = expandedTestSpec.find( registryKvp.first );+ if( pos != std::string::npos ) {+ expandedTestSpec = expandedTestSpec.substr( 0, pos ) ++ registryKvp.second.tag ++ expandedTestSpec.substr( pos + registryKvp.first.size() );+ }+ }+ return expandedTestSpec;+ }++ void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {+ CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'),+ "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo );++ CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,+ "error: tag alias, '" << alias << "' already registered.\n"+ << "\tFirst seen at: " << find(alias)->lineInfo << "\n"+ << "\tRedefined at: " << lineInfo );+ }++ ITagAliasRegistry::~ITagAliasRegistry() {}++ ITagAliasRegistry const& ITagAliasRegistry::get() {+ return getRegistryHub().getTagAliasRegistry();+ }++} // end namespace Catch+// end catch_tag_alias_registry.cpp+// start catch_test_case_info.cpp++#include <cctype>+#include <exception>+#include <algorithm>+#include <sstream>++namespace Catch {++ namespace {+ TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {+ if( startsWith( tag, '.' ) ||+ tag == "!hide" )+ return TestCaseInfo::IsHidden;+ else if( tag == "!throws" )+ return TestCaseInfo::Throws;+ else if( tag == "!shouldfail" )+ return TestCaseInfo::ShouldFail;+ else if( tag == "!mayfail" )+ return TestCaseInfo::MayFail;+ else if( tag == "!nonportable" )+ return TestCaseInfo::NonPortable;+ else if( tag == "!benchmark" )+ return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden );+ else+ return TestCaseInfo::None;+ }+ bool isReservedTag( std::string const& tag ) {+ return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) );+ }+ void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {+ CATCH_ENFORCE( !isReservedTag(tag),+ "Tag name: [" << tag << "] is not allowed.\n"+ << "Tag names starting with non alphanumeric characters are reserved\n"+ << _lineInfo );+ }+ }++ TestCase makeTestCase( ITestInvoker* _testCase,+ std::string const& _className,+ NameAndTags const& nameAndTags,+ SourceLineInfo const& _lineInfo )+ {+ bool isHidden = false;++ // Parse out tags+ std::vector<std::string> tags;+ std::string desc, tag;+ bool inTag = false;+ for (char c : nameAndTags.tags) {+ if( !inTag ) {+ if( c == '[' )+ inTag = true;+ else+ desc += c;+ }+ else {+ if( c == ']' ) {+ TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );+ if( ( prop & TestCaseInfo::IsHidden ) != 0 )+ isHidden = true;+ else if( prop == TestCaseInfo::None )+ enforceNotReservedTag( tag, _lineInfo );++ // Merged hide tags like `[.approvals]` should be added as+ // `[.][approvals]`. The `[.]` is added at later point, so+ // we only strip the prefix+ if (startsWith(tag, '.') && tag.size() > 1) {+ tag.erase(0, 1);+ }+ tags.push_back( tag );+ tag.clear();+ inTag = false;+ }+ else+ tag += c;+ }+ }+ if( isHidden ) {+ // Add all "hidden" tags to make them behave identically+ tags.insert( tags.end(), { ".", "!hide" } );+ }++ TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo );+ return TestCase( _testCase, std::move(info) );+ }++ void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) {+ std::sort(begin(tags), end(tags));+ tags.erase(std::unique(begin(tags), end(tags)), end(tags));+ testCaseInfo.lcaseTags.clear();++ for( auto const& tag : tags ) {+ std::string lcaseTag = toLower( tag );+ testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );+ testCaseInfo.lcaseTags.push_back( lcaseTag );+ }+ testCaseInfo.tags = std::move(tags);+ }++ TestCaseInfo::TestCaseInfo( std::string const& _name,+ std::string const& _className,+ std::string const& _description,+ std::vector<std::string> const& _tags,+ SourceLineInfo const& _lineInfo )+ : name( _name ),+ className( _className ),+ description( _description ),+ lineInfo( _lineInfo ),+ properties( None )+ {+ setTags( *this, _tags );+ }++ bool TestCaseInfo::isHidden() const {+ return ( properties & IsHidden ) != 0;+ }+ bool TestCaseInfo::throws() const {+ return ( properties & Throws ) != 0;+ }+ bool TestCaseInfo::okToFail() const {+ return ( properties & (ShouldFail | MayFail ) ) != 0;+ }+ bool TestCaseInfo::expectedToFail() const {+ return ( properties & (ShouldFail ) ) != 0;+ }++ std::string TestCaseInfo::tagsAsString() const {+ std::string ret;+ // '[' and ']' per tag+ std::size_t full_size = 2 * tags.size();+ for (const auto& tag : tags) {+ full_size += tag.size();+ }+ ret.reserve(full_size);+ for (const auto& tag : tags) {+ ret.push_back('[');+ ret.append(tag);+ ret.push_back(']');+ }++ return ret;+ }++ TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {}++ TestCase TestCase::withName( std::string const& _newName ) const {+ TestCase other( *this );+ other.name = _newName;+ return other;+ }++ void TestCase::invoke() const {+ test->invoke();+ }++ bool TestCase::operator == ( TestCase const& other ) const {+ return test.get() == other.test.get() &&+ name == other.name &&+ className == other.className;+ }++ bool TestCase::operator < ( TestCase const& other ) const {+ return name < other.name;+ }++ TestCaseInfo const& TestCase::getTestCaseInfo() const+ {+ return *this;+ }++} // end namespace Catch+// end catch_test_case_info.cpp+// start catch_test_case_registry_impl.cpp++#include <algorithm>+#include <sstream>++namespace Catch {++ namespace {+ struct TestHasher {+ using hash_t = uint64_t;++ explicit TestHasher( hash_t hashSuffix ):+ m_hashSuffix{ hashSuffix } {}++ uint32_t operator()( TestCase const& t ) const {+ // FNV-1a hash with multiplication fold.+ const hash_t prime = 1099511628211u;+ hash_t hash = 14695981039346656037u;+ for ( const char c : t.name ) {+ hash ^= c;+ hash *= prime;+ }+ hash ^= m_hashSuffix;+ hash *= prime;+ const uint32_t low{ static_cast<uint32_t>( hash ) };+ const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };+ return low * high;+ }++ private:+ hash_t m_hashSuffix;+ };+ } // end unnamed namespace++ std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {+ switch( config.runOrder() ) {+ case RunTests::InDeclarationOrder:+ // already in declaration order+ break;++ case RunTests::InLexicographicalOrder: {+ std::vector<TestCase> sorted = unsortedTestCases;+ std::sort( sorted.begin(), sorted.end() );+ return sorted;+ }++ case RunTests::InRandomOrder: {+ seedRng( config );+ TestHasher h{ config.rngSeed() };++ using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>;+ std::vector<hashedTest> indexed_tests;+ indexed_tests.reserve( unsortedTestCases.size() );++ for (auto const& testCase : unsortedTestCases) {+ indexed_tests.emplace_back(h(testCase), &testCase);+ }++ std::sort(indexed_tests.begin(), indexed_tests.end(),+ [](hashedTest const& lhs, hashedTest const& rhs) {+ if (lhs.first == rhs.first) {+ return lhs.second->name < rhs.second->name;+ }+ return lhs.first < rhs.first;+ });++ std::vector<TestCase> sorted;+ sorted.reserve( indexed_tests.size() );++ for (auto const& hashed : indexed_tests) {+ sorted.emplace_back(*hashed.second);+ }++ return sorted;+ }+ }+ return unsortedTestCases;+ }++ bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {+ return !testCase.throws() || config.allowThrows();+ }++ bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {+ return testSpec.matches( testCase ) && isThrowSafe( testCase, config );+ }++ void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {+ std::set<TestCase> seenFunctions;+ for( auto const& function : functions ) {+ auto prev = seenFunctions.insert( function );+ CATCH_ENFORCE( prev.second,+ "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n"+ << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"+ << "\tRedefined at " << function.getTestCaseInfo().lineInfo );+ }+ }++ std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {+ std::vector<TestCase> filtered;+ filtered.reserve( testCases.size() );+ for (auto const& testCase : testCases) {+ if ((!testSpec.hasFilters() && !testCase.isHidden()) ||+ (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {+ filtered.push_back(testCase);+ }+ }+ return filtered;+ }+ std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {+ return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );+ }++ void TestRegistry::registerTest( TestCase const& testCase ) {+ std::string name = testCase.getTestCaseInfo().name;+ if( name.empty() ) {+ ReusableStringStream rss;+ rss << "Anonymous test case " << ++m_unnamedCount;+ return registerTest( testCase.withName( rss.str() ) );+ }+ m_functions.push_back( testCase );+ }++ std::vector<TestCase> const& TestRegistry::getAllTests() const {+ return m_functions;+ }+ std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {+ if( m_sortedFunctions.empty() )+ enforceNoDuplicateTestCases( m_functions );++ if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {+ m_sortedFunctions = sortTests( config, m_functions );+ m_currentSortOrder = config.runOrder();+ }+ return m_sortedFunctions;+ }++ ///////////////////////////////////////////////////////////////////////////+ TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {}++ void TestInvokerAsFunction::invoke() const {+ m_testAsFunction();+ }++ std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {+ std::string className(classOrQualifiedMethodName);+ if( startsWith( className, '&' ) )+ {+ std::size_t lastColons = className.rfind( "::" );+ std::size_t penultimateColons = className.rfind( "::", lastColons-1 );+ if( penultimateColons == std::string::npos )+ penultimateColons = 1;+ className = className.substr( penultimateColons, lastColons-penultimateColons );+ }+ return className;+ }++} // end namespace Catch+// end catch_test_case_registry_impl.cpp+// start catch_test_case_tracker.cpp++#include <algorithm>+#include <cassert>+#include <stdexcept>+#include <memory>+#include <sstream>++#if defined(__clang__)+# pragma clang diagnostic push+# pragma clang diagnostic ignored "-Wexit-time-destructors"+#endif++namespace Catch {+namespace TestCaseTracking {++ NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location )+ : name( _name ),+ location( _location )+ {}++ ITracker::~ITracker() = default;++ ITracker& TrackerContext::startRun() {+ m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr );+ m_currentTracker = nullptr;+ m_runState = Executing;+ return *m_rootTracker;+ }++ void TrackerContext::endRun() {+ m_rootTracker.reset();+ m_currentTracker = nullptr;+ m_runState = NotStarted;+ }++ void TrackerContext::startCycle() {+ m_currentTracker = m_rootTracker.get();+ m_runState = Executing;+ }+ void TrackerContext::completeCycle() {+ m_runState = CompletedCycle;+ }++ bool TrackerContext::completedCycle() const {+ return m_runState == CompletedCycle;+ }+ ITracker& TrackerContext::currentTracker() {+ return *m_currentTracker;+ }+ void TrackerContext::setCurrentTracker( ITracker* tracker ) {+ m_currentTracker = tracker;+ }++ TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ):+ ITracker(nameAndLocation),+ m_ctx( ctx ),+ m_parent( parent )+ {}++ bool TrackerBase::isComplete() const {+ return m_runState == CompletedSuccessfully || m_runState == Failed;+ }+ bool TrackerBase::isSuccessfullyCompleted() const {+ return m_runState == CompletedSuccessfully;+ }+ bool TrackerBase::isOpen() const {+ return m_runState != NotStarted && !isComplete();+ }+ bool TrackerBase::hasChildren() const {+ return !m_children.empty();+ }++ void TrackerBase::addChild( ITrackerPtr const& child ) {+ m_children.push_back( child );+ }++ ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) {+ auto it = std::find_if( m_children.begin(), m_children.end(),+ [&nameAndLocation]( ITrackerPtr const& tracker ){+ return+ tracker->nameAndLocation().location == nameAndLocation.location &&+ tracker->nameAndLocation().name == nameAndLocation.name;+ } );+ return( it != m_children.end() )+ ? *it+ : nullptr;+ }+ ITracker& TrackerBase::parent() {+ assert( m_parent ); // Should always be non-null except for root+ return *m_parent;+ }++ void TrackerBase::openChild() {+ if( m_runState != ExecutingChildren ) {+ m_runState = ExecutingChildren;+ if( m_parent )+ m_parent->openChild();+ }+ }++ bool TrackerBase::isSectionTracker() const { return false; }+ bool TrackerBase::isGeneratorTracker() const { return false; }++ void TrackerBase::open() {+ m_runState = Executing;+ moveToThis();+ if( m_parent )+ m_parent->openChild();+ }++ void TrackerBase::close() {++ // Close any still open children (e.g. generators)+ while( &m_ctx.currentTracker() != this )+ m_ctx.currentTracker().close();++ switch( m_runState ) {+ case NeedsAnotherRun:+ break;++ case Executing:+ m_runState = CompletedSuccessfully;+ break;+ case ExecutingChildren:+ if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )+ m_runState = CompletedSuccessfully;+ break;++ case NotStarted:+ case CompletedSuccessfully:+ case Failed:+ CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );++ default:+ CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );+ }+ moveToParent();+ m_ctx.completeCycle();+ }+ void TrackerBase::fail() {+ m_runState = Failed;+ if( m_parent )+ m_parent->markAsNeedingAnotherRun();+ moveToParent();+ m_ctx.completeCycle();+ }+ void TrackerBase::markAsNeedingAnotherRun() {+ m_runState = NeedsAnotherRun;+ }++ void TrackerBase::moveToParent() {+ assert( m_parent );+ m_ctx.setCurrentTracker( m_parent );+ }+ void TrackerBase::moveToThis() {+ m_ctx.setCurrentTracker( this );+ }++ SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )+ : TrackerBase( nameAndLocation, ctx, parent ),+ m_trimmed_name(trim(nameAndLocation.name))+ {+ if( parent ) {+ while( !parent->isSectionTracker() )+ parent = &parent->parent();++ SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );+ addNextFilters( parentSection.m_filters );+ }+ }++ bool SectionTracker::isComplete() const {+ bool complete = true;++ if (m_filters.empty()+ || m_filters[0] == ""+ || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {+ complete = TrackerBase::isComplete();+ }+ return complete;+ }++ bool SectionTracker::isSectionTracker() const { return true; }++ SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {+ std::shared_ptr<SectionTracker> section;++ ITracker& currentTracker = ctx.currentTracker();+ if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {+ assert( childTracker );+ assert( childTracker->isSectionTracker() );+ section = std::static_pointer_cast<SectionTracker>( childTracker );+ }+ else {+ section = std::make_shared<SectionTracker>( nameAndLocation, ctx, ¤tTracker );+ currentTracker.addChild( section );+ }+ if( !ctx.completedCycle() )+ section->tryOpen();+ return *section;+ }++ void SectionTracker::tryOpen() {+ if( !isComplete() )+ open();+ }++ void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {+ if( !filters.empty() ) {+ m_filters.reserve( m_filters.size() + filters.size() + 2 );+ m_filters.emplace_back(""); // Root - should never be consulted+ m_filters.emplace_back(""); // Test Case - not a section filter+ m_filters.insert( m_filters.end(), filters.begin(), filters.end() );+ }+ }+ void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) {+ if( filters.size() > 1 )+ m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );+ }++ std::vector<std::string> const& SectionTracker::getFilters() const {+ return m_filters;+ }++ std::string const& SectionTracker::trimmedName() const {+ return m_trimmed_name;+ }++} // namespace TestCaseTracking++using TestCaseTracking::ITracker;+using TestCaseTracking::TrackerContext;+using TestCaseTracking::SectionTracker;++} // namespace Catch++#if defined(__clang__)+# pragma clang diagnostic pop+#endif+// end catch_test_case_tracker.cpp+// start catch_test_registry.cpp++namespace Catch {++ auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* {+ return new(std::nothrow) TestInvokerAsFunction( testAsFunction );+ }++ NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {}++ AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept {+ CATCH_TRY {+ getMutableRegistryHub()+ .registerTest(+ makeTestCase(+ invoker,+ extractClassName( classOrMethod ),+ nameAndTags,+ lineInfo));+ } CATCH_CATCH_ALL {+ // Do not throw when constructing global objects, instead register the exception to be processed later+ getMutableRegistryHub().registerStartupException();+ }+ }++ AutoReg::~AutoReg() = default;+}+// end catch_test_registry.cpp+// start catch_test_spec.cpp++#include <algorithm>+#include <string>+#include <vector>+#include <memory>++namespace Catch {++ TestSpec::Pattern::Pattern( std::string const& name )+ : m_name( name )+ {}++ TestSpec::Pattern::~Pattern() = default;++ std::string const& TestSpec::Pattern::name() const {+ return m_name;+ }++ TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )+ : Pattern( filterString )+ , m_wildcardPattern( toLower( name ), CaseSensitive::No )+ {}++ bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {+ return m_wildcardPattern.matches( testCase.name );+ }++ TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )+ : Pattern( filterString )+ , m_tag( toLower( tag ) )+ {}++ bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {+ return std::find(begin(testCase.lcaseTags),+ end(testCase.lcaseTags),+ m_tag) != end(testCase.lcaseTags);+ }++ TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern )+ : Pattern( underlyingPattern->name() )+ , m_underlyingPattern( underlyingPattern )+ {}++ bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const {+ return !m_underlyingPattern->matches( testCase );+ }++ bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {+ return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } );+ }++ std::string TestSpec::Filter::name() const {+ std::string name;+ for( auto const& p : m_patterns )+ name += p->name();+ return name;+ }++ bool TestSpec::hasFilters() const {+ return !m_filters.empty();+ }++ bool TestSpec::matches( TestCaseInfo const& testCase ) const {+ return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );+ }++ TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const+ {+ Matches matches( m_filters.size() );+ std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){+ std::vector<TestCase const*> currentMatches;+ for( auto const& test : testCases )+ if( isThrowSafe( test, config ) && filter.matches( test ) )+ currentMatches.emplace_back( &test );+ return FilterMatch{ filter.name(), currentMatches };+ } );+ return matches;+ }++ const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{+ return (m_invalidArgs);+ }++}+// end catch_test_spec.cpp+// start catch_test_spec_parser.cpp++namespace Catch {++ TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}++ TestSpecParser& TestSpecParser::parse( std::string const& arg ) {+ m_mode = None;+ m_exclusion = false;+ m_arg = m_tagAliases->expandAliases( arg );+ m_escapeChars.clear();+ m_substring.reserve(m_arg.size());+ m_patternName.reserve(m_arg.size());+ m_realPatternPos = 0;++ for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )+ //if visitChar fails+ if( !visitChar( m_arg[m_pos] ) ){+ m_testSpec.m_invalidArgs.push_back(arg);+ break;+ }+ endMode();+ return *this;+ }+ TestSpec TestSpecParser::testSpec() {+ addFilter();+ return m_testSpec;+ }+ bool TestSpecParser::visitChar( char c ) {+ if( (m_mode != EscapedName) && (c == '\\') ) {+ escape();+ addCharToPattern(c);+ return true;+ }else if((m_mode != EscapedName) && (c == ',') ) {+ return separate();+ }++ switch( m_mode ) {+ case None:+ if( processNoneChar( c ) )+ return true;+ break;+ case Name:+ processNameChar( c );+ break;+ case EscapedName:+ endMode();+ addCharToPattern(c);+ return true;+ default:+ case Tag:+ case QuotedName:+ if( processOtherChar( c ) )+ return true;+ break;+ }++ m_substring += c;+ if( !isControlChar( c ) ) {+ m_patternName += c;+ m_realPatternPos++;+ }+ return true;+ }+ // Two of the processing methods return true to signal the caller to return+ // without adding the given character to the current pattern strings+ bool TestSpecParser::processNoneChar( char c ) {+ switch( c ) {+ case ' ':+ return true;+ case '~':+ m_exclusion = true;+ return false;+ case '[':+ startNewMode( Tag );+ return false;+ case '"':+ startNewMode( QuotedName );+ return false;+ default:+ startNewMode( Name );+ return false;+ }+ }+ void TestSpecParser::processNameChar( char c ) {+ if( c == '[' ) {+ if( m_substring == "exclude:" )+ m_exclusion = true;+ else+ endMode();+ startNewMode( Tag );+ }+ }+ bool TestSpecParser::processOtherChar( char c ) {+ if( !isControlChar( c ) )+ return false;+ m_substring += c;+ endMode();+ return true;+ }+ void TestSpecParser::startNewMode( Mode mode ) {+ m_mode = mode;+ }+ void TestSpecParser::endMode() {+ switch( m_mode ) {+ case Name:+ case QuotedName:+ return addNamePattern();+ case Tag:+ return addTagPattern();+ case EscapedName:+ revertBackToLastMode();+ return;+ case None:+ default:+ return startNewMode( None );+ }+ }+ void TestSpecParser::escape() {+ saveLastMode();+ m_mode = EscapedName;+ m_escapeChars.push_back(m_realPatternPos);+ }+ bool TestSpecParser::isControlChar( char c ) const {+ switch( m_mode ) {+ default:+ return false;+ case None:+ return c == '~';+ case Name:+ return c == '[';+ case EscapedName:+ return true;+ case QuotedName:+ return c == '"';+ case Tag:+ return c == '[' || c == ']';+ }+ }++ void TestSpecParser::addFilter() {+ if( !m_currentFilter.m_patterns.empty() ) {+ m_testSpec.m_filters.push_back( m_currentFilter );+ m_currentFilter = TestSpec::Filter();+ }+ }++ void TestSpecParser::saveLastMode() {+ lastMode = m_mode;+ }++ void TestSpecParser::revertBackToLastMode() {+ m_mode = lastMode;+ }++ bool TestSpecParser::separate() {+ if( (m_mode==QuotedName) || (m_mode==Tag) ){+ //invalid argument, signal failure to previous scope.+ m_mode = None;+ m_pos = m_arg.size();+ m_substring.clear();+ m_patternName.clear();+ m_realPatternPos = 0;+ return false;+ }+ endMode();+ addFilter();+ return true; //success+ }++ std::string TestSpecParser::preprocessPattern() {+ std::string token = m_patternName;+ for (std::size_t i = 0; i < m_escapeChars.size(); ++i)+ token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);+ m_escapeChars.clear();+ if (startsWith(token, "exclude:")) {+ m_exclusion = true;+ token = token.substr(8);+ }++ m_patternName.clear();+ m_realPatternPos = 0;++ return token;+ }++ void TestSpecParser::addNamePattern() {+ auto token = preprocessPattern();++ if (!token.empty()) {+ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring);+ if (m_exclusion)+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);+ m_currentFilter.m_patterns.push_back(pattern);+ }+ m_substring.clear();+ m_exclusion = false;+ m_mode = None;+ }++ void TestSpecParser::addTagPattern() {+ auto token = preprocessPattern();++ if (!token.empty()) {+ // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])+ // we have to create a separate hide tag and shorten the real one+ if (token.size() > 1 && token[0] == '.') {+ token.erase(token.begin());+ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(".", m_substring);+ if (m_exclusion) {+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);+ }+ m_currentFilter.m_patterns.push_back(pattern);+ }++ TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring);++ if (m_exclusion) {+ pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);+ }+ m_currentFilter.m_patterns.push_back(pattern);+ }+ m_substring.clear();+ m_exclusion = false;+ m_mode = None;+ }++ TestSpec parseTestSpec( std::string const& arg ) {+ return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();+ }++} // namespace Catch+// end catch_test_spec_parser.cpp+// start catch_timer.cpp++#include <chrono>++static const uint64_t nanosecondsInSecond = 1000000000;++namespace Catch {++ auto getCurrentNanosecondsSinceEpoch() -> uint64_t {+ return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();+ }++ namespace {+ auto estimateClockResolution() -> uint64_t {+ uint64_t sum = 0;+ static const uint64_t iterations = 1000000;++ auto startTime = getCurrentNanosecondsSinceEpoch();++ for( std::size_t i = 0; i < iterations; ++i ) {++ uint64_t ticks;+ uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();+ do {+ ticks = getCurrentNanosecondsSinceEpoch();+ } while( ticks == baseTicks );++ auto delta = ticks - baseTicks;+ sum += delta;++ // If we have been calibrating for over 3 seconds -- the clock+ // is terrible and we should move on.+ // TBD: How to signal that the measured resolution is probably wrong?+ if (ticks > startTime + 3 * nanosecondsInSecond) {+ return sum / ( i + 1u );+ }+ }++ // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers+ // - and potentially do more iterations if there's a high variance.+ return sum/iterations;+ }+ }+ auto getEstimatedClockResolution() -> uint64_t {+ static auto s_resolution = estimateClockResolution();+ return s_resolution;+ }++ void Timer::start() {+ m_nanoseconds = getCurrentNanosecondsSinceEpoch();+ }+ auto Timer::getElapsedNanoseconds() const -> uint64_t {+ return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;+ }+ auto Timer::getElapsedMicroseconds() const -> uint64_t {+ return getElapsedNanoseconds()/1000;+ }+ auto Timer::getElapsedMilliseconds() const -> unsigned int {+ return static_cast<unsigned int>(getElapsedMicroseconds()/1000);+ }+ auto Timer::getElapsedSeconds() const -> double {+ return getElapsedMicroseconds()/1000000.0;+ }++} // namespace Catch+// end catch_timer.cpp+// start catch_tostring.cpp++#if defined(__clang__)+# pragma clang diagnostic push+# pragma clang diagnostic ignored "-Wexit-time-destructors"+# pragma clang diagnostic ignored "-Wglobal-constructors"+#endif++// Enable specific decls locally+#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)+#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER+#endif++#include <cmath>+#include <iomanip>++namespace Catch {++namespace Detail {++ const std::string unprintableString = "{?}";++ namespace {+ const int hexThreshold = 255;++ struct Endianness {+ enum Arch { Big, Little };++ static Arch which() {+ int one = 1;+ // If the lowest byte we read is non-zero, we can assume+ // that little endian format is used.+ auto value = *reinterpret_cast<char*>(&one);+ return value ? Little : Big;+ }+ };+ }++ std::string rawMemoryToString( const void *object, std::size_t size ) {+ // Reverse order for little endian architectures+ int i = 0, end = static_cast<int>( size ), inc = 1;+ if( Endianness::which() == Endianness::Little ) {+ i = end-1;+ end = inc = -1;+ }++ unsigned char const *bytes = static_cast<unsigned char const *>(object);+ ReusableStringStream rss;+ rss << "0x" << std::setfill('0') << std::hex;+ for( ; i != end; i += inc )+ rss << std::setw(2) << static_cast<unsigned>(bytes[i]);+ return rss.str();+ }+}++template<typename T>+std::string fpToString( T value, int precision ) {+ if (Catch::isnan(value)) {+ return "nan";+ }++ ReusableStringStream rss;+ rss << std::setprecision( precision )+ << std::fixed+ << value;+ std::string d = rss.str();+ std::size_t i = d.find_last_not_of( '0' );+ if( i != std::string::npos && i != d.size()-1 ) {+ if( d[i] == '.' )+ i++;+ d = d.substr( 0, i+1 );+ }+ return d;+}++//// ======================================================= ////+//+// Out-of-line defs for full specialization of StringMaker+//+//// ======================================================= ////++std::string StringMaker<std::string>::convert(const std::string& str) {+ if (!getCurrentContext().getConfig()->showInvisibles()) {+ return '"' + str + '"';+ }++ std::string s("\"");+ for (char c : str) {+ switch (c) {+ case '\n':+ s.append("\\n");+ break;+ case '\t':+ s.append("\\t");+ break;+ default:+ s.push_back(c);+ break;+ }+ }+ s.append("\"");+ return s;+}++#ifdef CATCH_CONFIG_CPP17_STRING_VIEW+std::string StringMaker<std::string_view>::convert(std::string_view str) {+ return ::Catch::Detail::stringify(std::string{ str });+}+#endif++std::string StringMaker<char const*>::convert(char const* str) {+ if (str) {+ return ::Catch::Detail::stringify(std::string{ str });+ } else {+ return{ "{null string}" };+ }+}+std::string StringMaker<char*>::convert(char* str) {+ if (str) {+ return ::Catch::Detail::stringify(std::string{ str });+ } else {+ return{ "{null string}" };+ }+}++#ifdef CATCH_CONFIG_WCHAR+std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {+ std::string s;+ s.reserve(wstr.size());+ for (auto c : wstr) {+ s += (c <= 0xff) ? static_cast<char>(c) : '?';+ }+ return ::Catch::Detail::stringify(s);+}++# ifdef CATCH_CONFIG_CPP17_STRING_VIEW+std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {+ return StringMaker<std::wstring>::convert(std::wstring(str));+}+# endif++std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {+ if (str) {+ return ::Catch::Detail::stringify(std::wstring{ str });+ } else {+ return{ "{null string}" };+ }+}+std::string StringMaker<wchar_t *>::convert(wchar_t * str) {+ if (str) {+ return ::Catch::Detail::stringify(std::wstring{ str });+ } else {+ return{ "{null string}" };+ }+}+#endif++#if defined(CATCH_CONFIG_CPP17_BYTE)+#include <cstddef>+std::string StringMaker<std::byte>::convert(std::byte value) {+ return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));+}+#endif // defined(CATCH_CONFIG_CPP17_BYTE)++std::string StringMaker<int>::convert(int value) {+ return ::Catch::Detail::stringify(static_cast<long long>(value));+}+std::string StringMaker<long>::convert(long value) {+ return ::Catch::Detail::stringify(static_cast<long long>(value));+}+std::string StringMaker<long long>::convert(long long value) {+ ReusableStringStream rss;+ rss << value;+ if (value > Detail::hexThreshold) {+ rss << " (0x" << std::hex << value << ')';+ }+ return rss.str();+}++std::string StringMaker<unsigned int>::convert(unsigned int value) {+ return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));+}+std::string StringMaker<unsigned long>::convert(unsigned long value) {+ return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));+}+std::string StringMaker<unsigned long long>::convert(unsigned long long value) {+ ReusableStringStream rss;+ rss << value;+ if (value > Detail::hexThreshold) {+ rss << " (0x" << std::hex << value << ')';+ }+ return rss.str();+}++std::string StringMaker<bool>::convert(bool b) {+ return b ? "true" : "false";+}++std::string StringMaker<signed char>::convert(signed char value) {+ if (value == '\r') {+ return "'\\r'";+ } else if (value == '\f') {+ return "'\\f'";+ } else if (value == '\n') {+ return "'\\n'";+ } else if (value == '\t') {+ return "'\\t'";+ } else if ('\0' <= value && value < ' ') {+ return ::Catch::Detail::stringify(static_cast<unsigned int>(value));+ } else {+ char chstr[] = "' '";+ chstr[1] = value;+ return chstr;+ }+}+std::string StringMaker<char>::convert(char c) {+ return ::Catch::Detail::stringify(static_cast<signed char>(c));+}+std::string StringMaker<unsigned char>::convert(unsigned char c) {+ return ::Catch::Detail::stringify(static_cast<char>(c));+}++std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) {+ return "nullptr";+}++int StringMaker<float>::precision = 5;++std::string StringMaker<float>::convert(float value) {+ return fpToString(value, precision) + 'f';+}++int StringMaker<double>::precision = 10;++std::string StringMaker<double>::convert(double value) {+ return fpToString(value, precision);+}++std::string ratio_string<std::atto>::symbol() { return "a"; }+std::string ratio_string<std::femto>::symbol() { return "f"; }+std::string ratio_string<std::pico>::symbol() { return "p"; }+std::string ratio_string<std::nano>::symbol() { return "n"; }+std::string ratio_string<std::micro>::symbol() { return "u"; }+std::string ratio_string<std::milli>::symbol() { return "m"; }++} // end namespace Catch++#if defined(__clang__)+# pragma clang diagnostic pop+#endif++// end catch_tostring.cpp+// start catch_totals.cpp++namespace Catch {++ Counts Counts::operator - ( Counts const& other ) const {+ Counts diff;+ diff.passed = passed - other.passed;+ diff.failed = failed - other.failed;+ diff.failedButOk = failedButOk - other.failedButOk;+ return diff;+ }++ Counts& Counts::operator += ( Counts const& other ) {+ passed += other.passed;+ failed += other.failed;+ failedButOk += other.failedButOk;+ return *this;+ }++ std::size_t Counts::total() const {+ return passed + failed + failedButOk;+ }+ bool Counts::allPassed() const {+ return failed == 0 && failedButOk == 0;+ }+ bool Counts::allOk() const {+ return failed == 0;+ }++ Totals Totals::operator - ( Totals const& other ) const {+ Totals diff;+ diff.assertions = assertions - other.assertions;+ diff.testCases = testCases - other.testCases;+ return diff;+ }++ Totals& Totals::operator += ( Totals const& other ) {+ assertions += other.assertions;+ testCases += other.testCases;+ return *this;+ }++ Totals Totals::delta( Totals const& prevTotals ) const {+ Totals diff = *this - prevTotals;+ if( diff.assertions.failed > 0 )+ ++diff.testCases.failed;+ else if( diff.assertions.failedButOk > 0 )+ ++diff.testCases.failedButOk;+ else+ ++diff.testCases.passed;+ return diff;+ }++}+// end catch_totals.cpp+// start catch_uncaught_exceptions.cpp++// start catch_config_uncaught_exceptions.hpp++// Copyright Catch2 Authors+// Distributed under the Boost Software License, Version 1.0.+// (See accompanying file LICENSE_1_0.txt or copy at+// https://www.boost.org/LICENSE_1_0.txt)++// SPDX-License-Identifier: BSL-1.0++#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP+#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP++#if defined(_MSC_VER)+# if _MSC_VER >= 1900 // Visual Studio 2015 or newer+# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS+# endif+#endif++#include <exception>++#if defined(__cpp_lib_uncaught_exceptions) \+ && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)++# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS+#endif // __cpp_lib_uncaught_exceptions++#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \+ && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \+ && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)++# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS+#endif++#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP+// end catch_config_uncaught_exceptions.hpp+#include <exception>++namespace Catch {+ bool uncaught_exceptions() {+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)+ return false;+#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)+ return std::uncaught_exceptions() > 0;+#else+ return std::uncaught_exception();+#endif+ }+} // end namespace Catch+// end catch_uncaught_exceptions.cpp+// start catch_version.cpp++#include <ostream>++namespace Catch {++ Version::Version+ ( unsigned int _majorVersion,+ unsigned int _minorVersion,+ unsigned int _patchNumber,+ char const * const _branchName,+ unsigned int _buildNumber )+ : majorVersion( _majorVersion ),+ minorVersion( _minorVersion ),+ patchNumber( _patchNumber ),+ branchName( _branchName ),+ buildNumber( _buildNumber )+ {}++ std::ostream& operator << ( std::ostream& os, Version const& version ) {+ os << version.majorVersion << '.'+ << version.minorVersion << '.'+ << version.patchNumber;+ // branchName is never null -> 0th char is \0 if it is empty+ if (version.branchName[0]) {+ os << '-' << version.branchName+ << '.' << version.buildNumber;+ }+ return os;+ }++ Version const& libraryVersion() {+ static Version version( 2, 13, 7, "", 0 );+ return version;+ }++}+// end catch_version.cpp+// start catch_wildcard_pattern.cpp++namespace Catch {++ WildcardPattern::WildcardPattern( std::string const& pattern,+ CaseSensitive::Choice caseSensitivity )+ : m_caseSensitivity( caseSensitivity ),+ m_pattern( normaliseString( pattern ) )+ {+ if( startsWith( m_pattern, '*' ) ) {+ m_pattern = m_pattern.substr( 1 );+ m_wildcard = WildcardAtStart;+ }+ if( endsWith( m_pattern, '*' ) ) {+ m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );+ m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );+ }+ }++ bool WildcardPattern::matches( std::string const& str ) const {+ switch( m_wildcard ) {+ case NoWildcard:+ return m_pattern == normaliseString( str );+ case WildcardAtStart:+ return endsWith( normaliseString( str ), m_pattern );+ case WildcardAtEnd:+ return startsWith( normaliseString( str ), m_pattern );+ case WildcardAtBothEnds:+ return contains( normaliseString( str ), m_pattern );+ default:+ CATCH_INTERNAL_ERROR( "Unknown enum" );+ }+ }++ std::string WildcardPattern::normaliseString( std::string const& str ) const {+ return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str );+ }+}+// end catch_wildcard_pattern.cpp+// start catch_xmlwriter.cpp++#include <iomanip>+#include <type_traits>++namespace Catch {++namespace {++ size_t trailingBytes(unsigned char c) {+ if ((c & 0xE0) == 0xC0) {+ return 2;+ }+ if ((c & 0xF0) == 0xE0) {+ return 3;+ }+ if ((c & 0xF8) == 0xF0) {+ return 4;+ }+ CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");+ }++ uint32_t headerValue(unsigned char c) {+ if ((c & 0xE0) == 0xC0) {+ return c & 0x1F;+ }+ if ((c & 0xF0) == 0xE0) {+ return c & 0x0F;+ }+ if ((c & 0xF8) == 0xF0) {+ return c & 0x07;+ }+ CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");+ }++ void hexEscapeChar(std::ostream& os, unsigned char c) {+ std::ios_base::fmtflags f(os.flags());+ os << "\\x"+ << std::uppercase << std::hex << std::setfill('0') << std::setw(2)+ << static_cast<int>(c);+ os.flags(f);+ }++ bool shouldNewline(XmlFormatting fmt) {+ return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline));+ }++ bool shouldIndent(XmlFormatting fmt) {+ return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent));+ }++} // anonymous namespace++ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) {+ return static_cast<XmlFormatting>(+ static_cast<std::underlying_type<XmlFormatting>::type>(lhs) |+ static_cast<std::underlying_type<XmlFormatting>::type>(rhs)+ );+ }++ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) {+ return static_cast<XmlFormatting>(+ static_cast<std::underlying_type<XmlFormatting>::type>(lhs) &+ static_cast<std::underlying_type<XmlFormatting>::type>(rhs)+ );+ }++ XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )+ : m_str( str ),+ m_forWhat( forWhat )+ {}++ void XmlEncode::encodeTo( std::ostream& os ) const {+ // Apostrophe escaping not necessary if we always use " to write attributes+ // (see: http://www.w3.org/TR/xml/#syntax)++ for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {+ unsigned char c = m_str[idx];+ switch (c) {+ case '<': os << "<"; break;+ case '&': os << "&"; break;++ case '>':+ // See: http://www.w3.org/TR/xml/#syntax+ if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')+ os << ">";+ else+ os << c;+ break;++ case '\"':+ if (m_forWhat == ForAttributes)+ os << """;+ else+ os << c;+ break;++ default:+ // Check for control characters and invalid utf-8++ // Escape control characters in standard ascii+ // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0+ if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {+ hexEscapeChar(os, c);+ break;+ }++ // Plain ASCII: Write it to stream+ if (c < 0x7F) {+ os << c;+ break;+ }++ // UTF-8 territory+ // Check if the encoding is valid and if it is not, hex escape bytes.+ // Important: We do not check the exact decoded values for validity, only the encoding format+ // First check that this bytes is a valid lead byte:+ // This means that it is not encoded as 1111 1XXX+ // Or as 10XX XXXX+ if (c < 0xC0 ||+ c >= 0xF8) {+ hexEscapeChar(os, c);+ break;+ }++ auto encBytes = trailingBytes(c);+ // Are there enough bytes left to avoid accessing out-of-bounds memory?+ if (idx + encBytes - 1 >= m_str.size()) {+ hexEscapeChar(os, c);+ break;+ }+ // The header is valid, check data+ // The next encBytes bytes must together be a valid utf-8+ // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)+ bool valid = true;+ uint32_t value = headerValue(c);+ for (std::size_t n = 1; n < encBytes; ++n) {+ unsigned char nc = m_str[idx + n];+ valid &= ((nc & 0xC0) == 0x80);+ value = (value << 6) | (nc & 0x3F);+ }++ if (+ // Wrong bit pattern of following bytes+ (!valid) ||+ // Overlong encodings+ (value < 0x80) ||+ (0x80 <= value && value < 0x800 && encBytes > 2) ||+ (0x800 < value && value < 0x10000 && encBytes > 3) ||+ // Encoded value out of range+ (value >= 0x110000)+ ) {+ hexEscapeChar(os, c);+ break;+ }++ // If we got here, this is in fact a valid(ish) utf-8 sequence+ for (std::size_t n = 0; n < encBytes; ++n) {+ os << m_str[idx + n];+ }+ idx += encBytes - 1;+ break;+ }+ }+ }++ std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {+ xmlEncode.encodeTo( os );+ return os;+ }++ XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )+ : m_writer( writer ),+ m_fmt(fmt)+ {}++ XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept+ : m_writer( other.m_writer ),+ m_fmt(other.m_fmt)+ {+ other.m_writer = nullptr;+ other.m_fmt = XmlFormatting::None;+ }+ XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {+ if ( m_writer ) {+ m_writer->endElement();+ }+ m_writer = other.m_writer;+ other.m_writer = nullptr;+ m_fmt = other.m_fmt;+ other.m_fmt = XmlFormatting::None;+ return *this;+ }++ XmlWriter::ScopedElement::~ScopedElement() {+ if (m_writer) {+ m_writer->endElement(m_fmt);+ }+ }++ XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) {+ m_writer->writeText( text, fmt );+ return *this;+ }++ XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )+ {+ writeDeclaration();+ }++ XmlWriter::~XmlWriter() {+ while (!m_tags.empty()) {+ endElement();+ }+ newlineIfNecessary();+ }++ XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {+ ensureTagClosed();+ newlineIfNecessary();+ if (shouldIndent(fmt)) {+ m_os << m_indent;+ m_indent += " ";+ }+ m_os << '<' << name;+ m_tags.push_back( name );+ m_tagIsOpen = true;+ applyFormatting(fmt);+ return *this;+ }++ XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {+ ScopedElement scoped( this, fmt );+ startElement( name, fmt );+ return scoped;+ }++ XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {+ m_indent = m_indent.substr(0, m_indent.size() - 2);++ if( m_tagIsOpen ) {+ m_os << "/>";+ m_tagIsOpen = false;+ } else {+ newlineIfNecessary();+ if (shouldIndent(fmt)) {+ m_os << m_indent;+ }+ m_os << "</" << m_tags.back() << ">";+ }+ m_os << std::flush;+ applyFormatting(fmt);+ m_tags.pop_back();+ return *this;+ }++ XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) {+ if( !name.empty() && !attribute.empty() )+ m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';+ return *this;+ }++ XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) {+ m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';+ return *this;+ }++ XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) {+ if( !text.empty() ){+ bool tagWasOpen = m_tagIsOpen;+ ensureTagClosed();+ if (tagWasOpen && shouldIndent(fmt)) {+ m_os << m_indent;+ }+ m_os << XmlEncode( text );+ applyFormatting(fmt);+ }+ return *this;+ }++ XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) {+ ensureTagClosed();+ if (shouldIndent(fmt)) {+ m_os << m_indent;+ }+ m_os << "<!--" << text << "-->";+ applyFormatting(fmt);+ return *this;+ }++ void XmlWriter::writeStylesheetRef( std::string const& url ) {+ m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";+ }++ XmlWriter& XmlWriter::writeBlankLine() {+ ensureTagClosed();+ m_os << '\n';+ return *this;+ }++ void XmlWriter::ensureTagClosed() {+ if( m_tagIsOpen ) {+ m_os << '>' << std::flush;+ newlineIfNecessary();+ m_tagIsOpen = false;+ }+ }++ void XmlWriter::applyFormatting(XmlFormatting fmt) {+ m_needsNewline = shouldNewline(fmt);+ }++ void XmlWriter::writeDeclaration() {+ m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";+ }++ void XmlWriter::newlineIfNecessary() {+ if( m_needsNewline ) {+ m_os << std::endl;+ m_needsNewline = false;+ }+ }+}+// end catch_xmlwriter.cpp+// start catch_reporter_bases.cpp++#include <cstring>+#include <cfloat>+#include <cstdio>+#include <cassert>+#include <memory>++namespace Catch {+ void prepareExpandedExpression(AssertionResult& result) {+ result.getExpandedExpression();+ }++ // Because formatting using c++ streams is stateful, drop down to C is required+ // Alternatively we could use stringstream, but its performance is... not good.+ std::string getFormattedDuration( double duration ) {+ // Max exponent + 1 is required to represent the whole part+ // + 1 for decimal point+ // + 3 for the 3 decimal places+ // + 1 for null terminator+ const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;+ char buffer[maxDoubleSize];++ // Save previous errno, to prevent sprintf from overwriting it+ ErrnoGuard guard;+#ifdef _MSC_VER+ sprintf_s(buffer, "%.3f", duration);+#else+ std::sprintf(buffer, "%.3f", duration);+#endif+ return std::string(buffer);+ }++ bool shouldShowDuration( IConfig const& config, double duration ) {+ if ( config.showDurations() == ShowDurations::Always ) {+ return true;+ }+ if ( config.showDurations() == ShowDurations::Never ) {+ return false;+ }+ const double min = config.minDuration();+ return min >= 0 && duration >= min;+ }++ std::string serializeFilters( std::vector<std::string> const& container ) {+ ReusableStringStream oss;+ bool first = true;+ for (auto&& filter : container)+ {+ if (!first)+ oss << ' ';+ else+ first = false;++ oss << filter;+ }+ return oss.str();+ }++ TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config)+ :StreamingReporterBase(_config) {}++ std::set<Verbosity> TestEventListenerBase::getSupportedVerbosities() {+ return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High };+ }++ void TestEventListenerBase::assertionStarting(AssertionInfo const &) {}++ bool TestEventListenerBase::assertionEnded(AssertionStats const &) {+ return false;+ }++} // end namespace Catch+// end catch_reporter_bases.cpp+// start catch_reporter_compact.cpp++namespace {++#ifdef CATCH_PLATFORM_MAC+ const char* failedString() { return "FAILED"; }+ const char* passedString() { return "PASSED"; }+#else+ const char* failedString() { return "failed"; }+ const char* passedString() { return "passed"; }+#endif++ // Colour::LightGrey+ Catch::Colour::Code dimColour() { return Catch::Colour::FileName; }++ std::string bothOrAll( std::size_t count ) {+ return count == 1 ? std::string() :+ count == 2 ? "both " : "all " ;+ }++} // anon namespace++namespace Catch {+namespace {+// Colour, message variants:+// - white: No tests ran.+// - red: Failed [both/all] N test cases, failed [both/all] M assertions.+// - white: Passed [both/all] N test cases (no assertions).+// - red: Failed N tests cases, failed M assertions.+// - green: Passed [both/all] N tests cases with M assertions.+void printTotals(std::ostream& out, const Totals& totals) {+ if (totals.testCases.total() == 0) {+ out << "No tests ran.";+ } else if (totals.testCases.failed == totals.testCases.total()) {+ Colour colour(Colour::ResultError);+ const std::string qualify_assertions_failed =+ totals.assertions.failed == totals.assertions.total() ?+ bothOrAll(totals.assertions.failed) : std::string();+ out <<+ "Failed " << bothOrAll(totals.testCases.failed)+ << pluralise(totals.testCases.failed, "test case") << ", "+ "failed " << qualify_assertions_failed <<+ pluralise(totals.assertions.failed, "assertion") << '.';+ } else if (totals.assertions.total() == 0) {+ out <<+ "Passed " << bothOrAll(totals.testCases.total())+ << pluralise(totals.testCases.total(), "test case")+ << " (no assertions).";+ } else if (totals.assertions.failed) {+ Colour colour(Colour::ResultError);+ out <<+ "Failed " << pluralise(totals.testCases.failed, "test case") << ", "+ "failed " << pluralise(totals.assertions.failed, "assertion") << '.';+ } else {+ Colour colour(Colour::ResultSuccess);+ out <<+ "Passed " << bothOrAll(totals.testCases.passed)+ << pluralise(totals.testCases.passed, "test case") <<+ " with " << pluralise(totals.assertions.passed, "assertion") << '.';+ }+}++// Implementation of CompactReporter formatting+class AssertionPrinter {+public:+ AssertionPrinter& operator= (AssertionPrinter const&) = delete;+ AssertionPrinter(AssertionPrinter const&) = delete;+ AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)+ : stream(_stream)+ , result(_stats.assertionResult)+ , messages(_stats.infoMessages)+ , itMessage(_stats.infoMessages.begin())+ , printInfoMessages(_printInfoMessages) {}++ void print() {+ printSourceInfo();++ itMessage = messages.begin();++ switch (result.getResultType()) {+ case ResultWas::Ok:+ printResultType(Colour::ResultSuccess, passedString());+ printOriginalExpression();+ printReconstructedExpression();+ if (!result.hasExpression())+ printRemainingMessages(Colour::None);+ else+ printRemainingMessages();+ break;+ case ResultWas::ExpressionFailed:+ if (result.isOk())+ printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok"));+ else+ printResultType(Colour::Error, failedString());+ printOriginalExpression();+ printReconstructedExpression();+ printRemainingMessages();+ break;+ case ResultWas::ThrewException:+ printResultType(Colour::Error, failedString());+ printIssue("unexpected exception with message:");+ printMessage();+ printExpressionWas();+ printRemainingMessages();+ break;+ case ResultWas::FatalErrorCondition:+ printResultType(Colour::Error, failedString());+ printIssue("fatal error condition with message:");+ printMessage();+ printExpressionWas();+ printRemainingMessages();+ break;+ case ResultWas::DidntThrowException:+ printResultType(Colour::Error, failedString());+ printIssue("expected exception, got none");+ printExpressionWas();+ printRemainingMessages();+ break;+ case ResultWas::Info:+ printResultType(Colour::None, "info");+ printMessage();+ printRemainingMessages();+ break;+ case ResultWas::Warning:+ printResultType(Colour::None, "warning");+ printMessage();+ printRemainingMessages();+ break;+ case ResultWas::ExplicitFailure:+ printResultType(Colour::Error, failedString());+ printIssue("explicitly");+ printRemainingMessages(Colour::None);+ break;+ // These cases are here to prevent compiler warnings+ case ResultWas::Unknown:+ case ResultWas::FailureBit:+ case ResultWas::Exception:+ printResultType(Colour::Error, "** internal error **");+ break;+ }+ }++private:+ void printSourceInfo() const {+ Colour colourGuard(Colour::FileName);+ stream << result.getSourceInfo() << ':';+ }++ void printResultType(Colour::Code colour, std::string const& passOrFail) const {+ if (!passOrFail.empty()) {+ {+ Colour colourGuard(colour);+ stream << ' ' << passOrFail;+ }+ stream << ':';+ }+ }++ void printIssue(std::string const& issue) const {+ stream << ' ' << issue;+ }++ void printExpressionWas() {+ if (result.hasExpression()) {+ stream << ';';+ {+ Colour colour(dimColour());+ stream << " expression was:";+ }+ printOriginalExpression();+ }+ }++ void printOriginalExpression() const {+ if (result.hasExpression()) {+ stream << ' ' << result.getExpression();+ }+ }++ void printReconstructedExpression() const {+ if (result.hasExpandedExpression()) {+ {+ Colour colour(dimColour());+ stream << " for: ";+ }+ stream << result.getExpandedExpression();+ }+ }++ void printMessage() {+ if (itMessage != messages.end()) {+ stream << " '" << itMessage->message << '\'';+ ++itMessage;+ }+ }++ void printRemainingMessages(Colour::Code colour = dimColour()) {+ if (itMessage == messages.end())+ return;++ const auto itEnd = messages.cend();+ const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd));++ {+ Colour colourGuard(colour);+ stream << " with " << pluralise(N, "message") << ':';+ }++ while (itMessage != itEnd) {+ // If this assertion is a warning ignore any INFO messages+ if (printInfoMessages || itMessage->type != ResultWas::Info) {+ printMessage();+ if (itMessage != itEnd) {+ Colour colourGuard(dimColour());+ stream << " and";+ }+ continue;+ }+ ++itMessage;+ }+ }++private:+ std::ostream& stream;+ AssertionResult const& result;+ std::vector<MessageInfo> messages;+ std::vector<MessageInfo>::const_iterator itMessage;+ bool printInfoMessages;+};++} // anon namespace++ std::string CompactReporter::getDescription() {+ return "Reports test results on a single line, suitable for IDEs";+ }++ void CompactReporter::noMatchingTestCases( std::string const& spec ) {+ stream << "No test cases matched '" << spec << '\'' << std::endl;+ }++ void CompactReporter::assertionStarting( AssertionInfo const& ) {}++ bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {+ AssertionResult const& result = _assertionStats.assertionResult;++ bool printInfoMessages = true;++ // Drop out if result was successful and we're not printing those+ if( !m_config->includeSuccessfulResults() && result.isOk() ) {+ if( result.getResultType() != ResultWas::Warning )+ return false;+ printInfoMessages = false;+ }++ AssertionPrinter printer( stream, _assertionStats, printInfoMessages );+ printer.print();++ stream << std::endl;+ return true;+ }++ void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {+ double dur = _sectionStats.durationInSeconds;+ if ( shouldShowDuration( *m_config, dur ) ) {+ stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl;+ }+ }++ void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) {+ printTotals( stream, _testRunStats.totals );+ stream << '\n' << std::endl;+ StreamingReporterBase::testRunEnded( _testRunStats );+ }++ CompactReporter::~CompactReporter() {}++ CATCH_REGISTER_REPORTER( "compact", CompactReporter )++} // end namespace Catch+// end catch_reporter_compact.cpp+// start catch_reporter_console.cpp++#include <cfloat>+#include <cstdio>++#if defined(_MSC_VER)+#pragma warning(push)+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch+ // Note that 4062 (not all labels are handled and default is missing) is enabled+#endif++#if defined(__clang__)+# pragma clang diagnostic push+// For simplicity, benchmarking-only helpers are always enabled+# pragma clang diagnostic ignored "-Wunused-function"+#endif++namespace Catch {++namespace {++// Formatter impl for ConsoleReporter+class ConsoleAssertionPrinter {+public:+ ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete;+ ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete;+ ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)+ : stream(_stream),+ stats(_stats),+ result(_stats.assertionResult),+ colour(Colour::None),+ message(result.getMessage()),+ messages(_stats.infoMessages),+ printInfoMessages(_printInfoMessages) {+ switch (result.getResultType()) {+ case ResultWas::Ok:+ colour = Colour::Success;+ passOrFail = "PASSED";+ //if( result.hasMessage() )+ if (_stats.infoMessages.size() == 1)+ messageLabel = "with message";+ if (_stats.infoMessages.size() > 1)+ messageLabel = "with messages";+ break;+ case ResultWas::ExpressionFailed:+ if (result.isOk()) {+ colour = Colour::Success;+ passOrFail = "FAILED - but was ok";+ } else {+ colour = Colour::Error;+ passOrFail = "FAILED";+ }+ if (_stats.infoMessages.size() == 1)+ messageLabel = "with message";+ if (_stats.infoMessages.size() > 1)+ messageLabel = "with messages";+ break;+ case ResultWas::ThrewException:+ colour = Colour::Error;+ passOrFail = "FAILED";+ messageLabel = "due to unexpected exception with ";+ if (_stats.infoMessages.size() == 1)+ messageLabel += "message";+ if (_stats.infoMessages.size() > 1)+ messageLabel += "messages";+ break;+ case ResultWas::FatalErrorCondition:+ colour = Colour::Error;+ passOrFail = "FAILED";+ messageLabel = "due to a fatal error condition";+ break;+ case ResultWas::DidntThrowException:+ colour = Colour::Error;+ passOrFail = "FAILED";+ messageLabel = "because no exception was thrown where one was expected";+ break;+ case ResultWas::Info:+ messageLabel = "info";+ break;+ case ResultWas::Warning:+ messageLabel = "warning";+ break;+ case ResultWas::ExplicitFailure:+ passOrFail = "FAILED";+ colour = Colour::Error;+ if (_stats.infoMessages.size() == 1)+ messageLabel = "explicitly with message";+ if (_stats.infoMessages.size() > 1)+ messageLabel = "explicitly with messages";+ break;+ // These cases are here to prevent compiler warnings+ case ResultWas::Unknown:+ case ResultWas::FailureBit:+ case ResultWas::Exception:+ passOrFail = "** internal error **";+ colour = Colour::Error;+ break;+ }+ }++ void print() const {+ printSourceInfo();+ if (stats.totals.assertions.total() > 0) {+ printResultType();+ printOriginalExpression();+ printReconstructedExpression();+ } else {+ stream << '\n';+ }+ printMessage();+ }++private:+ void printResultType() const {+ if (!passOrFail.empty()) {+ Colour colourGuard(colour);+ stream << passOrFail << ":\n";+ }+ }+ void printOriginalExpression() const {+ if (result.hasExpression()) {+ Colour colourGuard(Colour::OriginalExpression);+ stream << " ";+ stream << result.getExpressionInMacro();+ stream << '\n';+ }+ }+ void printReconstructedExpression() const {+ if (result.hasExpandedExpression()) {+ stream << "with expansion:\n";+ Colour colourGuard(Colour::ReconstructedExpression);+ stream << Column(result.getExpandedExpression()).indent(2) << '\n';+ }+ }+ void printMessage() const {+ if (!messageLabel.empty())+ stream << messageLabel << ':' << '\n';+ for (auto const& msg : messages) {+ // If this assertion is a warning ignore any INFO messages+ if (printInfoMessages || msg.type != ResultWas::Info)+ stream << Column(msg.message).indent(2) << '\n';+ }+ }+ void printSourceInfo() const {+ Colour colourGuard(Colour::FileName);+ stream << result.getSourceInfo() << ": ";+ }++ std::ostream& stream;+ AssertionStats const& stats;+ AssertionResult const& result;+ Colour::Code colour;+ std::string passOrFail;+ std::string messageLabel;+ std::string message;+ std::vector<MessageInfo> messages;+ bool printInfoMessages;+};++std::size_t makeRatio(std::size_t number, std::size_t total) {+ std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;+ return (ratio == 0 && number > 0) ? 1 : ratio;+}++std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) {+ if (i > j && i > k)+ return i;+ else if (j > k)+ return j;+ else+ return k;+}++struct ColumnInfo {+ enum Justification { Left, Right };+ std::string name;+ int width;+ Justification justification;+};+struct ColumnBreak {};+struct RowBreak {};++class Duration {+ enum class Unit {+ Auto,+ Nanoseconds,+ Microseconds,+ Milliseconds,+ Seconds,+ Minutes+ };+ static const uint64_t s_nanosecondsInAMicrosecond = 1000;+ static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;+ static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;+ static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;++ double m_inNanoseconds;+ Unit m_units;++public:+ explicit Duration(double inNanoseconds, Unit units = Unit::Auto)+ : m_inNanoseconds(inNanoseconds),+ m_units(units) {+ if (m_units == Unit::Auto) {+ if (m_inNanoseconds < s_nanosecondsInAMicrosecond)+ m_units = Unit::Nanoseconds;+ else if (m_inNanoseconds < s_nanosecondsInAMillisecond)+ m_units = Unit::Microseconds;+ else if (m_inNanoseconds < s_nanosecondsInASecond)+ m_units = Unit::Milliseconds;+ else if (m_inNanoseconds < s_nanosecondsInAMinute)+ m_units = Unit::Seconds;+ else+ m_units = Unit::Minutes;+ }++ }++ auto value() const -> double {+ switch (m_units) {+ case Unit::Microseconds:+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond);+ case Unit::Milliseconds:+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond);+ case Unit::Seconds:+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond);+ case Unit::Minutes:+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);+ default:+ return m_inNanoseconds;+ }+ }+ auto unitsAsString() const -> std::string {+ switch (m_units) {+ case Unit::Nanoseconds:+ return "ns";+ case Unit::Microseconds:+ return "us";+ case Unit::Milliseconds:+ return "ms";+ case Unit::Seconds:+ return "s";+ case Unit::Minutes:+ return "m";+ default:+ return "** internal error **";+ }++ }+ friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {+ return os << duration.value() << ' ' << duration.unitsAsString();+ }+};+} // end anon namespace++class TablePrinter {+ std::ostream& m_os;+ std::vector<ColumnInfo> m_columnInfos;+ std::ostringstream m_oss;+ int m_currentColumn = -1;+ bool m_isOpen = false;++public:+ TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )+ : m_os( os ),+ m_columnInfos( std::move( columnInfos ) ) {}++ auto columnInfos() const -> std::vector<ColumnInfo> const& {+ return m_columnInfos;+ }++ void open() {+ if (!m_isOpen) {+ m_isOpen = true;+ *this << RowBreak();++ Columns headerCols;+ Spacer spacer(2);+ for (auto const& info : m_columnInfos) {+ headerCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2));+ headerCols += spacer;+ }+ m_os << headerCols << '\n';++ m_os << Catch::getLineOfChars<'-'>() << '\n';+ }+ }+ void close() {+ if (m_isOpen) {+ *this << RowBreak();+ m_os << std::endl;+ m_isOpen = false;+ }+ }++ template<typename T>+ friend TablePrinter& operator << (TablePrinter& tp, T const& value) {+ tp.m_oss << value;+ return tp;+ }++ friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {+ auto colStr = tp.m_oss.str();+ const auto strSize = colStr.size();+ tp.m_oss.str("");+ tp.open();+ if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {+ tp.m_currentColumn = -1;+ tp.m_os << '\n';+ }+ tp.m_currentColumn++;++ auto colInfo = tp.m_columnInfos[tp.m_currentColumn];+ auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width))+ ? std::string(colInfo.width - (strSize + 1), ' ')+ : std::string();+ if (colInfo.justification == ColumnInfo::Left)+ tp.m_os << colStr << padding << ' ';+ else+ tp.m_os << padding << colStr << ' ';+ return tp;+ }++ friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {+ if (tp.m_currentColumn > 0) {+ tp.m_os << '\n';+ tp.m_currentColumn = -1;+ }+ return tp;+ }+};++ConsoleReporter::ConsoleReporter(ReporterConfig const& config)+ : StreamingReporterBase(config),+ m_tablePrinter(new TablePrinter(config.stream(),+ [&config]() -> std::vector<ColumnInfo> {+ if (config.fullConfig()->benchmarkNoAnalysis())+ {+ return{+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },+ { " samples", 14, ColumnInfo::Right },+ { " iterations", 14, ColumnInfo::Right },+ { " mean", 14, ColumnInfo::Right }+ };+ }+ else+ {+ return{+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },+ { "samples mean std dev", 14, ColumnInfo::Right },+ { "iterations low mean low std dev", 14, ColumnInfo::Right },+ { "estimated high mean high std dev", 14, ColumnInfo::Right }+ };+ }+ }())) {}+ConsoleReporter::~ConsoleReporter() = default;++std::string ConsoleReporter::getDescription() {+ return "Reports test results as plain lines of text";+}++void ConsoleReporter::noMatchingTestCases(std::string const& spec) {+ stream << "No test cases matched '" << spec << '\'' << std::endl;+}++void ConsoleReporter::reportInvalidArguments(std::string const&arg){+ stream << "Invalid Filter: " << arg << std::endl;+}++void ConsoleReporter::assertionStarting(AssertionInfo const&) {}++bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {+ AssertionResult const& result = _assertionStats.assertionResult;++ bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();++ // Drop out if result was successful but we're not printing them.+ if (!includeResults && result.getResultType() != ResultWas::Warning)+ return false;++ lazyPrint();++ ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults);+ printer.print();+ stream << std::endl;+ return true;+}++void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {+ m_tablePrinter->close();+ m_headerPrinted = false;+ StreamingReporterBase::sectionStarting(_sectionInfo);+}+void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {+ m_tablePrinter->close();+ if (_sectionStats.missingAssertions) {+ lazyPrint();+ Colour colour(Colour::ResultError);+ if (m_sectionStack.size() > 1)+ stream << "\nNo assertions in section";+ else+ stream << "\nNo assertions in test case";+ stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;+ }+ double dur = _sectionStats.durationInSeconds;+ if (shouldShowDuration(*m_config, dur)) {+ stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl;+ }+ if (m_headerPrinted) {+ m_headerPrinted = false;+ }+ StreamingReporterBase::sectionEnded(_sectionStats);+}++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+void ConsoleReporter::benchmarkPreparing(std::string const& name) {+ lazyPrintWithoutClosingBenchmarkTable();++ auto nameCol = Column(name).width(static_cast<std::size_t>(m_tablePrinter->columnInfos()[0].width - 2));++ bool firstLine = true;+ for (auto line : nameCol) {+ if (!firstLine)+ (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();+ else+ firstLine = false;++ (*m_tablePrinter) << line << ColumnBreak();+ }+}++void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {+ (*m_tablePrinter) << info.samples << ColumnBreak()+ << info.iterations << ColumnBreak();+ if (!m_config->benchmarkNoAnalysis())+ (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak();+}+void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {+ if (m_config->benchmarkNoAnalysis())+ {+ (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();+ }+ else+ {+ (*m_tablePrinter) << ColumnBreak()+ << Duration(stats.mean.point.count()) << ColumnBreak()+ << Duration(stats.mean.lower_bound.count()) << ColumnBreak()+ << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()+ << Duration(stats.standardDeviation.point.count()) << ColumnBreak()+ << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()+ << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();+ }+}++void ConsoleReporter::benchmarkFailed(std::string const& error) {+ Colour colour(Colour::Red);+ (*m_tablePrinter)+ << "Benchmark failed (" << error << ')'+ << ColumnBreak() << RowBreak();+}+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {+ m_tablePrinter->close();+ StreamingReporterBase::testCaseEnded(_testCaseStats);+ m_headerPrinted = false;+}+void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) {+ if (currentGroupInfo.used) {+ printSummaryDivider();+ stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";+ printTotals(_testGroupStats.totals);+ stream << '\n' << std::endl;+ }+ StreamingReporterBase::testGroupEnded(_testGroupStats);+}+void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {+ printTotalsDivider(_testRunStats.totals);+ printTotals(_testRunStats.totals);+ stream << std::endl;+ StreamingReporterBase::testRunEnded(_testRunStats);+}+void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) {+ StreamingReporterBase::testRunStarting(_testInfo);+ printTestFilters();+}++void ConsoleReporter::lazyPrint() {++ m_tablePrinter->close();+ lazyPrintWithoutClosingBenchmarkTable();+}++void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {++ if (!currentTestRunInfo.used)+ lazyPrintRunInfo();+ if (!currentGroupInfo.used)+ lazyPrintGroupInfo();++ if (!m_headerPrinted) {+ printTestCaseAndSectionHeader();+ m_headerPrinted = true;+ }+}+void ConsoleReporter::lazyPrintRunInfo() {+ stream << '\n' << getLineOfChars<'~'>() << '\n';+ Colour colour(Colour::SecondaryText);+ stream << currentTestRunInfo->name+ << " is a Catch v" << libraryVersion() << " host application.\n"+ << "Run with -? for options\n\n";++ if (m_config->rngSeed() != 0)+ stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";++ currentTestRunInfo.used = true;+}+void ConsoleReporter::lazyPrintGroupInfo() {+ if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) {+ printClosedHeader("Group: " + currentGroupInfo->name);+ currentGroupInfo.used = true;+ }+}+void ConsoleReporter::printTestCaseAndSectionHeader() {+ assert(!m_sectionStack.empty());+ printOpenHeader(currentTestCaseInfo->name);++ if (m_sectionStack.size() > 1) {+ Colour colourGuard(Colour::Headers);++ auto+ it = m_sectionStack.begin() + 1, // Skip first section (test case)+ itEnd = m_sectionStack.end();+ for (; it != itEnd; ++it)+ printHeaderString(it->name, 2);+ }++ SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;++ stream << getLineOfChars<'-'>() << '\n';+ Colour colourGuard(Colour::FileName);+ stream << lineInfo << '\n';+ stream << getLineOfChars<'.'>() << '\n' << std::endl;+}++void ConsoleReporter::printClosedHeader(std::string const& _name) {+ printOpenHeader(_name);+ stream << getLineOfChars<'.'>() << '\n';+}+void ConsoleReporter::printOpenHeader(std::string const& _name) {+ stream << getLineOfChars<'-'>() << '\n';+ {+ Colour colourGuard(Colour::Headers);+ printHeaderString(_name);+ }+}++// if string has a : in first line will set indent to follow it on+// subsequent lines+void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) {+ std::size_t i = _string.find(": ");+ if (i != std::string::npos)+ i += 2;+ else+ i = 0;+ stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n';+}++struct SummaryColumn {++ SummaryColumn( std::string _label, Colour::Code _colour )+ : label( std::move( _label ) ),+ colour( _colour ) {}+ SummaryColumn addRow( std::size_t count ) {+ ReusableStringStream rss;+ rss << count;+ std::string row = rss.str();+ for (auto& oldRow : rows) {+ while (oldRow.size() < row.size())+ oldRow = ' ' + oldRow;+ while (oldRow.size() > row.size())+ row = ' ' + row;+ }+ rows.push_back(row);+ return *this;+ }++ std::string label;+ Colour::Code colour;+ std::vector<std::string> rows;++};++void ConsoleReporter::printTotals( Totals const& totals ) {+ if (totals.testCases.total() == 0) {+ stream << Colour(Colour::Warning) << "No tests ran\n";+ } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) {+ stream << Colour(Colour::ResultSuccess) << "All tests passed";+ stream << " ("+ << pluralise(totals.assertions.passed, "assertion") << " in "+ << pluralise(totals.testCases.passed, "test case") << ')'+ << '\n';+ } else {++ std::vector<SummaryColumn> columns;+ columns.push_back(SummaryColumn("", Colour::None)+ .addRow(totals.testCases.total())+ .addRow(totals.assertions.total()));+ columns.push_back(SummaryColumn("passed", Colour::Success)+ .addRow(totals.testCases.passed)+ .addRow(totals.assertions.passed));+ columns.push_back(SummaryColumn("failed", Colour::ResultError)+ .addRow(totals.testCases.failed)+ .addRow(totals.assertions.failed));+ columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure)+ .addRow(totals.testCases.failedButOk)+ .addRow(totals.assertions.failedButOk));++ printSummaryRow("test cases", columns, 0);+ printSummaryRow("assertions", columns, 1);+ }+}+void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) {+ for (auto col : cols) {+ std::string value = col.rows[row];+ if (col.label.empty()) {+ stream << label << ": ";+ if (value != "0")+ stream << value;+ else+ stream << Colour(Colour::Warning) << "- none -";+ } else if (value != "0") {+ stream << Colour(Colour::LightGrey) << " | ";+ stream << Colour(col.colour)+ << value << ' ' << col.label;+ }+ }+ stream << '\n';+}++void ConsoleReporter::printTotalsDivider(Totals const& totals) {+ if (totals.testCases.total() > 0) {+ std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());+ std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());+ std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());+ while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)+ findMax(failedRatio, failedButOkRatio, passedRatio)++;+ while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)+ findMax(failedRatio, failedButOkRatio, passedRatio)--;++ stream << Colour(Colour::Error) << std::string(failedRatio, '=');+ stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '=');+ if (totals.testCases.allPassed())+ stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');+ else+ stream << Colour(Colour::Success) << std::string(passedRatio, '=');+ } else {+ stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');+ }+ stream << '\n';+}+void ConsoleReporter::printSummaryDivider() {+ stream << getLineOfChars<'-'>() << '\n';+}++void ConsoleReporter::printTestFilters() {+ if (m_config->testSpec().hasFilters()) {+ Colour guard(Colour::BrightYellow);+ stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n';+ }+}++CATCH_REGISTER_REPORTER("console", ConsoleReporter)++} // end namespace Catch++#if defined(_MSC_VER)+#pragma warning(pop)+#endif++#if defined(__clang__)+# pragma clang diagnostic pop+#endif+// end catch_reporter_console.cpp+// start catch_reporter_junit.cpp++#include <cassert>+#include <sstream>+#include <ctime>+#include <algorithm>+#include <iomanip>++namespace Catch {++ namespace {+ std::string getCurrentTimestamp() {+ // Beware, this is not reentrant because of backward compatibility issues+ // Also, UTC only, again because of backward compatibility (%z is C++11)+ time_t rawtime;+ std::time(&rawtime);+ auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");++#ifdef _MSC_VER+ std::tm timeInfo = {};+ gmtime_s(&timeInfo, &rawtime);+#else+ std::tm* timeInfo;+ timeInfo = std::gmtime(&rawtime);+#endif++ char timeStamp[timeStampSize];+ const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";++#ifdef _MSC_VER+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);+#else+ std::strftime(timeStamp, timeStampSize, fmt, timeInfo);+#endif+ return std::string(timeStamp, timeStampSize-1);+ }++ std::string fileNameTag(const std::vector<std::string> &tags) {+ auto it = std::find_if(begin(tags),+ end(tags),+ [] (std::string const& tag) {return tag.front() == '#'; });+ if (it != tags.end())+ return it->substr(1);+ return std::string();+ }++ // Formats the duration in seconds to 3 decimal places.+ // This is done because some genius defined Maven Surefire schema+ // in a way that only accepts 3 decimal places, and tools like+ // Jenkins use that schema for validation JUnit reporter output.+ std::string formatDuration( double seconds ) {+ ReusableStringStream rss;+ rss << std::fixed << std::setprecision( 3 ) << seconds;+ return rss.str();+ }++ } // anonymous namespace++ JunitReporter::JunitReporter( ReporterConfig const& _config )+ : CumulativeReporterBase( _config ),+ xml( _config.stream() )+ {+ m_reporterPrefs.shouldRedirectStdOut = true;+ m_reporterPrefs.shouldReportAllAssertions = true;+ }++ JunitReporter::~JunitReporter() {}++ std::string JunitReporter::getDescription() {+ return "Reports test results in an XML format that looks like Ant's junitreport target";+ }++ void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {}++ void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {+ CumulativeReporterBase::testRunStarting( runInfo );+ xml.startElement( "testsuites" );+ }++ void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) {+ suiteTimer.start();+ stdOutForSuite.clear();+ stdErrForSuite.clear();+ unexpectedExceptions = 0;+ CumulativeReporterBase::testGroupStarting( groupInfo );+ }++ void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) {+ m_okToFail = testCaseInfo.okToFail();+ }++ bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) {+ if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )+ unexpectedExceptions++;+ return CumulativeReporterBase::assertionEnded( assertionStats );+ }++ void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {+ stdOutForSuite += testCaseStats.stdOut;+ stdErrForSuite += testCaseStats.stdErr;+ CumulativeReporterBase::testCaseEnded( testCaseStats );+ }++ void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {+ double suiteTime = suiteTimer.getElapsedSeconds();+ CumulativeReporterBase::testGroupEnded( testGroupStats );+ writeGroup( *m_testGroups.back(), suiteTime );+ }++ void JunitReporter::testRunEndedCumulative() {+ xml.endElement();+ }++ void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) {+ XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );++ TestGroupStats const& stats = groupNode.value;+ xml.writeAttribute( "name", stats.groupInfo.name );+ xml.writeAttribute( "errors", unexpectedExceptions );+ xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );+ xml.writeAttribute( "tests", stats.totals.assertions.total() );+ xml.writeAttribute( "hostname", "tbd" ); // !TBD+ if( m_config->showDurations() == ShowDurations::Never )+ xml.writeAttribute( "time", "" );+ else+ xml.writeAttribute( "time", formatDuration( suiteTime ) );+ xml.writeAttribute( "timestamp", getCurrentTimestamp() );++ // Write properties if there are any+ if (m_config->hasTestFilters() || m_config->rngSeed() != 0) {+ auto properties = xml.scopedElement("properties");+ if (m_config->hasTestFilters()) {+ xml.scopedElement("property")+ .writeAttribute("name", "filters")+ .writeAttribute("value", serializeFilters(m_config->getTestsOrTags()));+ }+ if (m_config->rngSeed() != 0) {+ xml.scopedElement("property")+ .writeAttribute("name", "random-seed")+ .writeAttribute("value", m_config->rngSeed());+ }+ }++ // Write test cases+ for( auto const& child : groupNode.children )+ writeTestCase( *child );++ xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );+ xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );+ }++ void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {+ TestCaseStats const& stats = testCaseNode.value;++ // All test cases have exactly one section - which represents the+ // test case itself. That section may have 0-n nested sections+ assert( testCaseNode.children.size() == 1 );+ SectionNode const& rootSection = *testCaseNode.children.front();++ std::string className = stats.testInfo.className;++ if( className.empty() ) {+ className = fileNameTag(stats.testInfo.tags);+ if ( className.empty() )+ className = "global";+ }++ if ( !m_config->name().empty() )+ className = m_config->name() + "." + className;++ writeSection( className, "", rootSection, stats.testInfo.okToFail() );+ }++ void JunitReporter::writeSection( std::string const& className,+ std::string const& rootName,+ SectionNode const& sectionNode,+ bool testOkToFail) {+ std::string name = trim( sectionNode.stats.sectionInfo.name );+ if( !rootName.empty() )+ name = rootName + '/' + name;++ if( !sectionNode.assertions.empty() ||+ !sectionNode.stdOut.empty() ||+ !sectionNode.stdErr.empty() ) {+ XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );+ if( className.empty() ) {+ xml.writeAttribute( "classname", name );+ xml.writeAttribute( "name", "root" );+ }+ else {+ xml.writeAttribute( "classname", className );+ xml.writeAttribute( "name", name );+ }+ xml.writeAttribute( "time", formatDuration( sectionNode.stats.durationInSeconds ) );+ // This is not ideal, but it should be enough to mimic gtest's+ // junit output.+ // Ideally the JUnit reporter would also handle `skipTest`+ // events and write those out appropriately.+ xml.writeAttribute( "status", "run" );++ if (sectionNode.stats.assertions.failedButOk) {+ xml.scopedElement("skipped")+ .writeAttribute("message", "TEST_CASE tagged with !mayfail");+ }++ writeAssertions( sectionNode );++ if( !sectionNode.stdOut.empty() )+ xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );+ if( !sectionNode.stdErr.empty() )+ xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );+ }+ for( auto const& childNode : sectionNode.childSections )+ if( className.empty() )+ writeSection( name, "", *childNode, testOkToFail );+ else+ writeSection( className, name, *childNode, testOkToFail );+ }++ void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {+ for( auto const& assertion : sectionNode.assertions )+ writeAssertion( assertion );+ }++ void JunitReporter::writeAssertion( AssertionStats const& stats ) {+ AssertionResult const& result = stats.assertionResult;+ if( !result.isOk() ) {+ std::string elementName;+ switch( result.getResultType() ) {+ case ResultWas::ThrewException:+ case ResultWas::FatalErrorCondition:+ elementName = "error";+ break;+ case ResultWas::ExplicitFailure:+ case ResultWas::ExpressionFailed:+ case ResultWas::DidntThrowException:+ elementName = "failure";+ break;++ // We should never see these here:+ case ResultWas::Info:+ case ResultWas::Warning:+ case ResultWas::Ok:+ case ResultWas::Unknown:+ case ResultWas::FailureBit:+ case ResultWas::Exception:+ elementName = "internalError";+ break;+ }++ XmlWriter::ScopedElement e = xml.scopedElement( elementName );++ xml.writeAttribute( "message", result.getExpression() );+ xml.writeAttribute( "type", result.getTestMacroName() );++ ReusableStringStream rss;+ if (stats.totals.assertions.total() > 0) {+ rss << "FAILED" << ":\n";+ if (result.hasExpression()) {+ rss << " ";+ rss << result.getExpressionInMacro();+ rss << '\n';+ }+ if (result.hasExpandedExpression()) {+ rss << "with expansion:\n";+ rss << Column(result.getExpandedExpression()).indent(2) << '\n';+ }+ } else {+ rss << '\n';+ }++ if( !result.getMessage().empty() )+ rss << result.getMessage() << '\n';+ for( auto const& msg : stats.infoMessages )+ if( msg.type == ResultWas::Info )+ rss << msg.message << '\n';++ rss << "at " << result.getSourceInfo();+ xml.writeText( rss.str(), XmlFormatting::Newline );+ }+ }++ CATCH_REGISTER_REPORTER( "junit", JunitReporter )++} // end namespace Catch+// end catch_reporter_junit.cpp+// start catch_reporter_listening.cpp++#include <cassert>++namespace Catch {++ ListeningReporter::ListeningReporter() {+ // We will assume that listeners will always want all assertions+ m_preferences.shouldReportAllAssertions = true;+ }++ void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) {+ m_listeners.push_back( std::move( listener ) );+ }++ void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) {+ assert(!m_reporter && "Listening reporter can wrap only 1 real reporter");+ m_reporter = std::move( reporter );+ m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut;+ }++ ReporterPreferences ListeningReporter::getPreferences() const {+ return m_preferences;+ }++ std::set<Verbosity> ListeningReporter::getSupportedVerbosities() {+ return std::set<Verbosity>{ };+ }++ void ListeningReporter::noMatchingTestCases( std::string const& spec ) {+ for ( auto const& listener : m_listeners ) {+ listener->noMatchingTestCases( spec );+ }+ m_reporter->noMatchingTestCases( spec );+ }++ void ListeningReporter::reportInvalidArguments(std::string const&arg){+ for ( auto const& listener : m_listeners ) {+ listener->reportInvalidArguments( arg );+ }+ m_reporter->reportInvalidArguments( arg );+ }++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+ void ListeningReporter::benchmarkPreparing( std::string const& name ) {+ for (auto const& listener : m_listeners) {+ listener->benchmarkPreparing(name);+ }+ m_reporter->benchmarkPreparing(name);+ }+ void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {+ for ( auto const& listener : m_listeners ) {+ listener->benchmarkStarting( benchmarkInfo );+ }+ m_reporter->benchmarkStarting( benchmarkInfo );+ }+ void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) {+ for ( auto const& listener : m_listeners ) {+ listener->benchmarkEnded( benchmarkStats );+ }+ m_reporter->benchmarkEnded( benchmarkStats );+ }++ void ListeningReporter::benchmarkFailed( std::string const& error ) {+ for (auto const& listener : m_listeners) {+ listener->benchmarkFailed(error);+ }+ m_reporter->benchmarkFailed(error);+ }+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++ void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {+ for ( auto const& listener : m_listeners ) {+ listener->testRunStarting( testRunInfo );+ }+ m_reporter->testRunStarting( testRunInfo );+ }++ void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) {+ for ( auto const& listener : m_listeners ) {+ listener->testGroupStarting( groupInfo );+ }+ m_reporter->testGroupStarting( groupInfo );+ }++ void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) {+ for ( auto const& listener : m_listeners ) {+ listener->testCaseStarting( testInfo );+ }+ m_reporter->testCaseStarting( testInfo );+ }++ void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) {+ for ( auto const& listener : m_listeners ) {+ listener->sectionStarting( sectionInfo );+ }+ m_reporter->sectionStarting( sectionInfo );+ }++ void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) {+ for ( auto const& listener : m_listeners ) {+ listener->assertionStarting( assertionInfo );+ }+ m_reporter->assertionStarting( assertionInfo );+ }++ // The return value indicates if the messages buffer should be cleared:+ bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) {+ for( auto const& listener : m_listeners ) {+ static_cast<void>( listener->assertionEnded( assertionStats ) );+ }+ return m_reporter->assertionEnded( assertionStats );+ }++ void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) {+ for ( auto const& listener : m_listeners ) {+ listener->sectionEnded( sectionStats );+ }+ m_reporter->sectionEnded( sectionStats );+ }++ void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {+ for ( auto const& listener : m_listeners ) {+ listener->testCaseEnded( testCaseStats );+ }+ m_reporter->testCaseEnded( testCaseStats );+ }++ void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {+ for ( auto const& listener : m_listeners ) {+ listener->testGroupEnded( testGroupStats );+ }+ m_reporter->testGroupEnded( testGroupStats );+ }++ void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) {+ for ( auto const& listener : m_listeners ) {+ listener->testRunEnded( testRunStats );+ }+ m_reporter->testRunEnded( testRunStats );+ }++ void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) {+ for ( auto const& listener : m_listeners ) {+ listener->skipTest( testInfo );+ }+ m_reporter->skipTest( testInfo );+ }++ bool ListeningReporter::isMulti() const {+ return true;+ }++} // end namespace Catch+// end catch_reporter_listening.cpp+// start catch_reporter_xml.cpp++#if defined(_MSC_VER)+#pragma warning(push)+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch+ // Note that 4062 (not all labels are handled+ // and default is missing) is enabled+#endif++namespace Catch {+ XmlReporter::XmlReporter( ReporterConfig const& _config )+ : StreamingReporterBase( _config ),+ m_xml(_config.stream())+ {+ m_reporterPrefs.shouldRedirectStdOut = true;+ m_reporterPrefs.shouldReportAllAssertions = true;+ }++ XmlReporter::~XmlReporter() = default;++ std::string XmlReporter::getDescription() {+ return "Reports test results as an XML document";+ }++ std::string XmlReporter::getStylesheetRef() const {+ return std::string();+ }++ void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) {+ m_xml+ .writeAttribute( "filename", sourceInfo.file )+ .writeAttribute( "line", sourceInfo.line );+ }++ void XmlReporter::noMatchingTestCases( std::string const& s ) {+ StreamingReporterBase::noMatchingTestCases( s );+ }++ void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) {+ StreamingReporterBase::testRunStarting( testInfo );+ std::string stylesheetRef = getStylesheetRef();+ if( !stylesheetRef.empty() )+ m_xml.writeStylesheetRef( stylesheetRef );+ m_xml.startElement( "Catch" );+ if( !m_config->name().empty() )+ m_xml.writeAttribute( "name", m_config->name() );+ if (m_config->testSpec().hasFilters())+ m_xml.writeAttribute( "filters", serializeFilters( m_config->getTestsOrTags() ) );+ if( m_config->rngSeed() != 0 )+ m_xml.scopedElement( "Randomness" )+ .writeAttribute( "seed", m_config->rngSeed() );+ }++ void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) {+ StreamingReporterBase::testGroupStarting( groupInfo );+ m_xml.startElement( "Group" )+ .writeAttribute( "name", groupInfo.name );+ }++ void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {+ StreamingReporterBase::testCaseStarting(testInfo);+ m_xml.startElement( "TestCase" )+ .writeAttribute( "name", trim( testInfo.name ) )+ .writeAttribute( "description", testInfo.description )+ .writeAttribute( "tags", testInfo.tagsAsString() );++ writeSourceInfo( testInfo.lineInfo );++ if ( m_config->showDurations() == ShowDurations::Always )+ m_testCaseTimer.start();+ m_xml.ensureTagClosed();+ }++ void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) {+ StreamingReporterBase::sectionStarting( sectionInfo );+ if( m_sectionDepth++ > 0 ) {+ m_xml.startElement( "Section" )+ .writeAttribute( "name", trim( sectionInfo.name ) );+ writeSourceInfo( sectionInfo.lineInfo );+ m_xml.ensureTagClosed();+ }+ }++ void XmlReporter::assertionStarting( AssertionInfo const& ) { }++ bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) {++ AssertionResult const& result = assertionStats.assertionResult;++ bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();++ if( includeResults || result.getResultType() == ResultWas::Warning ) {+ // Print any info messages in <Info> tags.+ for( auto const& msg : assertionStats.infoMessages ) {+ if( msg.type == ResultWas::Info && includeResults ) {+ m_xml.scopedElement( "Info" )+ .writeText( msg.message );+ } else if ( msg.type == ResultWas::Warning ) {+ m_xml.scopedElement( "Warning" )+ .writeText( msg.message );+ }+ }+ }++ // Drop out if result was successful but we're not printing them.+ if( !includeResults && result.getResultType() != ResultWas::Warning )+ return true;++ // Print the expression if there is one.+ if( result.hasExpression() ) {+ m_xml.startElement( "Expression" )+ .writeAttribute( "success", result.succeeded() )+ .writeAttribute( "type", result.getTestMacroName() );++ writeSourceInfo( result.getSourceInfo() );++ m_xml.scopedElement( "Original" )+ .writeText( result.getExpression() );+ m_xml.scopedElement( "Expanded" )+ .writeText( result.getExpandedExpression() );+ }++ // And... Print a result applicable to each result type.+ switch( result.getResultType() ) {+ case ResultWas::ThrewException:+ m_xml.startElement( "Exception" );+ writeSourceInfo( result.getSourceInfo() );+ m_xml.writeText( result.getMessage() );+ m_xml.endElement();+ break;+ case ResultWas::FatalErrorCondition:+ m_xml.startElement( "FatalErrorCondition" );+ writeSourceInfo( result.getSourceInfo() );+ m_xml.writeText( result.getMessage() );+ m_xml.endElement();+ break;+ case ResultWas::Info:+ m_xml.scopedElement( "Info" )+ .writeText( result.getMessage() );+ break;+ case ResultWas::Warning:+ // Warning will already have been written+ break;+ case ResultWas::ExplicitFailure:+ m_xml.startElement( "Failure" );+ writeSourceInfo( result.getSourceInfo() );+ m_xml.writeText( result.getMessage() );+ m_xml.endElement();+ break;+ default:+ break;+ }++ if( result.hasExpression() )+ m_xml.endElement();++ return true;+ }++ void XmlReporter::sectionEnded( SectionStats const& sectionStats ) {+ StreamingReporterBase::sectionEnded( sectionStats );+ if( --m_sectionDepth > 0 ) {+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );+ e.writeAttribute( "successes", sectionStats.assertions.passed );+ e.writeAttribute( "failures", sectionStats.assertions.failed );+ e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );++ if ( m_config->showDurations() == ShowDurations::Always )+ e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );++ m_xml.endElement();+ }+ }++ void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {+ StreamingReporterBase::testCaseEnded( testCaseStats );+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );+ e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );++ if ( m_config->showDurations() == ShowDurations::Always )+ e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );++ if( !testCaseStats.stdOut.empty() )+ m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );+ if( !testCaseStats.stdErr.empty() )+ m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );++ m_xml.endElement();+ }++ void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {+ StreamingReporterBase::testGroupEnded( testGroupStats );+ // TODO: Check testGroupStats.aborting and act accordingly.+ m_xml.scopedElement( "OverallResults" )+ .writeAttribute( "successes", testGroupStats.totals.assertions.passed )+ .writeAttribute( "failures", testGroupStats.totals.assertions.failed )+ .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );+ m_xml.scopedElement( "OverallResultsCases")+ .writeAttribute( "successes", testGroupStats.totals.testCases.passed )+ .writeAttribute( "failures", testGroupStats.totals.testCases.failed )+ .writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk );+ m_xml.endElement();+ }++ void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) {+ StreamingReporterBase::testRunEnded( testRunStats );+ m_xml.scopedElement( "OverallResults" )+ .writeAttribute( "successes", testRunStats.totals.assertions.passed )+ .writeAttribute( "failures", testRunStats.totals.assertions.failed )+ .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );+ m_xml.scopedElement( "OverallResultsCases")+ .writeAttribute( "successes", testRunStats.totals.testCases.passed )+ .writeAttribute( "failures", testRunStats.totals.testCases.failed )+ .writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk );+ m_xml.endElement();+ }++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+ void XmlReporter::benchmarkPreparing(std::string const& name) {+ m_xml.startElement("BenchmarkResults")+ .writeAttribute("name", name);+ }++ void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {+ m_xml.writeAttribute("samples", info.samples)+ .writeAttribute("resamples", info.resamples)+ .writeAttribute("iterations", info.iterations)+ .writeAttribute("clockResolution", info.clockResolution)+ .writeAttribute("estimatedDuration", info.estimatedDuration)+ .writeComment("All values in nano seconds");+ }++ void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {+ m_xml.startElement("mean")+ .writeAttribute("value", benchmarkStats.mean.point.count())+ .writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count())+ .writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count())+ .writeAttribute("ci", benchmarkStats.mean.confidence_interval);+ m_xml.endElement();+ m_xml.startElement("standardDeviation")+ .writeAttribute("value", benchmarkStats.standardDeviation.point.count())+ .writeAttribute("lowerBound", benchmarkStats.standardDeviation.lower_bound.count())+ .writeAttribute("upperBound", benchmarkStats.standardDeviation.upper_bound.count())+ .writeAttribute("ci", benchmarkStats.standardDeviation.confidence_interval);+ m_xml.endElement();+ m_xml.startElement("outliers")+ .writeAttribute("variance", benchmarkStats.outlierVariance)+ .writeAttribute("lowMild", benchmarkStats.outliers.low_mild)+ .writeAttribute("lowSevere", benchmarkStats.outliers.low_severe)+ .writeAttribute("highMild", benchmarkStats.outliers.high_mild)+ .writeAttribute("highSevere", benchmarkStats.outliers.high_severe);+ m_xml.endElement();+ m_xml.endElement();+ }++ void XmlReporter::benchmarkFailed(std::string const &error) {+ m_xml.scopedElement("failed").+ writeAttribute("message", error);+ m_xml.endElement();+ }+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++ CATCH_REGISTER_REPORTER( "xml", XmlReporter )++} // end namespace Catch++#if defined(_MSC_VER)+#pragma warning(pop)+#endif+// end catch_reporter_xml.cpp++namespace Catch {+ LeakDetector leakDetector;+}++#ifdef __clang__+#pragma clang diagnostic pop+#endif++// end catch_impl.hpp+#endif++#ifdef CATCH_CONFIG_MAIN+// start catch_default_main.hpp++#ifndef __OBJC__++#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)+// Standard C/C++ Win32 Unicode wmain entry point+extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {+#else+// Standard C/C++ main entry point+int main (int argc, char * argv[]) {+#endif++ return Catch::Session().run( argc, argv );+}++#else // __OBJC__++// Objective-C entry point+int main (int argc, char * const argv[]) {+#if !CATCH_ARC_ENABLED+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];+#endif++ Catch::registerTestMethods();+ int result = Catch::Session().run( argc, (char**)argv );++#if !CATCH_ARC_ENABLED+ [pool drain];+#endif++ return result;+}++#endif // __OBJC__++// end catch_default_main.hpp+#endif++#if !defined(CATCH_CONFIG_IMPL_ONLY)++#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED+# undef CLARA_CONFIG_MAIN+#endif++#if !defined(CATCH_CONFIG_DISABLE)+//////+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_+#ifdef CATCH_CONFIG_PREFIX_ALL++#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )+#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )++#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )+#endif// CATCH_CONFIG_DISABLE_MATCHERS+#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )++#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )+#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )+#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )+#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )+#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )++#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )+#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )+#endif // CATCH_CONFIG_DISABLE_MATCHERS+#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )++#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )++#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )+#endif // CATCH_CONFIG_DISABLE_MATCHERS++#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )+#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )+#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )+#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )++#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )+#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )+#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )+#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )+#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )+#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )+#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )+#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )+#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )++#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )+#else+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )+#endif++#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)+#define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )+#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )+#else+#define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ )+#define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )+#endif++// "BDD-style" convenience wrappers+#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )+#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )+#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )+#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )+#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )+#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )+#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+#define CATCH_BENCHMARK(...) \+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))+#define CATCH_BENCHMARK_ADVANCED(name) \+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required+#else++#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )+#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )++#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )+#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )+#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )+#endif // CATCH_CONFIG_DISABLE_MATCHERS+#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )++#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )+#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )+#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )+#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )+#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )++#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )+#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )+#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )+#endif // CATCH_CONFIG_DISABLE_MATCHERS+#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )++#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )++#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )+#endif // CATCH_CONFIG_DISABLE_MATCHERS++#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )+#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )+#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )+#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )++#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )+#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )+#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )+#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )+#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )+#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )+#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )+#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )+#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )+#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)+#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )+#else+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )+#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )+#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )+#endif++#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)+#define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )+#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )+#else+#define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ )+#define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )+#endif++#endif++#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )++// "BDD-style" convenience wrappers+#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )++#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )+#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )+#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )+#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )+#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )+#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )++#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)+#define BENCHMARK(...) \+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))+#define BENCHMARK_ADVANCED(name) \+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)+#endif // CATCH_CONFIG_ENABLE_BENCHMARKING++using Catch::Detail::Approx;++#else // CATCH_CONFIG_DISABLE++//////+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_+#ifdef CATCH_CONFIG_PREFIX_ALL++#define CATCH_REQUIRE( ... ) (void)(0)+#define CATCH_REQUIRE_FALSE( ... ) (void)(0)++#define CATCH_REQUIRE_THROWS( ... ) (void)(0)+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)+#endif// CATCH_CONFIG_DISABLE_MATCHERS+#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0)++#define CATCH_CHECK( ... ) (void)(0)+#define CATCH_CHECK_FALSE( ... ) (void)(0)+#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__)+#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__))+#define CATCH_CHECK_NOFAIL( ... ) (void)(0)++#define CATCH_CHECK_THROWS( ... ) (void)(0)+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0)+#define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0)+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)+#endif // CATCH_CONFIG_DISABLE_MATCHERS+#define CATCH_CHECK_NOTHROW( ... ) (void)(0)++#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define CATCH_CHECK_THAT( arg, matcher ) (void)(0)++#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)+#endif // CATCH_CONFIG_DISABLE_MATCHERS++#define CATCH_INFO( msg ) (void)(0)+#define CATCH_UNSCOPED_INFO( msg ) (void)(0)+#define CATCH_WARN( msg ) (void)(0)+#define CATCH_CAPTURE( msg ) (void)(0)++#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))+#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))+#define CATCH_METHOD_AS_TEST_CASE( method, ... )+#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)+#define CATCH_SECTION( ... )+#define CATCH_DYNAMIC_SECTION( ... )+#define CATCH_FAIL( ... ) (void)(0)+#define CATCH_FAIL_CHECK( ... ) (void)(0)+#define CATCH_SUCCEED( ... ) (void)(0)++#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )+#else+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )+#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )+#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )+#endif++// "BDD-style" convenience wrappers+#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )+#define CATCH_GIVEN( desc )+#define CATCH_AND_GIVEN( desc )+#define CATCH_WHEN( desc )+#define CATCH_AND_WHEN( desc )+#define CATCH_THEN( desc )+#define CATCH_AND_THEN( desc )++#define CATCH_STATIC_REQUIRE( ... ) (void)(0)+#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)++// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required+#else++#define REQUIRE( ... ) (void)(0)+#define REQUIRE_FALSE( ... ) (void)(0)++#define REQUIRE_THROWS( ... ) (void)(0)+#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)+#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)+#endif // CATCH_CONFIG_DISABLE_MATCHERS+#define REQUIRE_NOTHROW( ... ) (void)(0)++#define CHECK( ... ) (void)(0)+#define CHECK_FALSE( ... ) (void)(0)+#define CHECKED_IF( ... ) if (__VA_ARGS__)+#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__))+#define CHECK_NOFAIL( ... ) (void)(0)++#define CHECK_THROWS( ... ) (void)(0)+#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0)+#define CHECK_THROWS_WITH( expr, matcher ) (void)(0)+#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)+#endif // CATCH_CONFIG_DISABLE_MATCHERS+#define CHECK_NOTHROW( ... ) (void)(0)++#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)+#define CHECK_THAT( arg, matcher ) (void)(0)++#define REQUIRE_THAT( arg, matcher ) (void)(0)+#endif // CATCH_CONFIG_DISABLE_MATCHERS++#define INFO( msg ) (void)(0)+#define UNSCOPED_INFO( msg ) (void)(0)+#define WARN( msg ) (void)(0)+#define CAPTURE( msg ) (void)(0)++#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))+#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))+#define METHOD_AS_TEST_CASE( method, ... )+#define REGISTER_TEST_CASE( Function, ... ) (void)(0)+#define SECTION( ... )+#define DYNAMIC_SECTION( ... )+#define FAIL( ... ) (void)(0)+#define FAIL_CHECK( ... ) (void)(0)+#define SUCCEED( ... ) (void)(0)+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))++#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )+#else+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )+#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )+#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )+#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )+#endif++#define STATIC_REQUIRE( ... ) (void)(0)+#define STATIC_REQUIRE_FALSE( ... ) (void)(0)++#endif++#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )++// "BDD-style" convenience wrappers+#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) )+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )++#define GIVEN( desc )+#define AND_GIVEN( desc )+#define WHEN( desc )+#define AND_WHEN( desc )+#define THEN( desc )+#define AND_THEN( desc )++using Catch::Detail::Approx;++#endif++#endif // ! CATCH_CONFIG_IMPL_ONLY++// start catch_reenable_warnings.h+++#ifdef __clang__+# ifdef __ICC // icpc defines the __clang__ macro+# pragma warning(pop)+# else+# pragma clang diagnostic pop+# endif+#elif defined __GNUC__+# pragma GCC diagnostic pop+#endif++// end catch_reenable_warnings.h+// end catch.hpp+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED+
+ src/hs/Main.hs view
@@ -0,0 +1,6 @@+module Main where++import Sound.Tidal.Link (hello)++main :: IO ()+main = hello
+ src/hs/Sound/Tidal/Link.hsc view
@@ -0,0 +1,139 @@+{-# LANGUAGE ForeignFunctionInterface #-}++module Sound.Tidal.Link where++#include "abl_link.h"++import Foreign+import Foreign.C.Types+import Data.Int()++data AbletonLinkImpl+data SessionStateImpl++newtype AbletonLink = AbletonLink (Ptr AbletonLinkImpl)+newtype SessionState = SessionState (Ptr SessionStateImpl)++instance Show AbletonLink where+ show _ = "-unshowable-"++instance Show SessionState where+ show _ = "-unshowable-"++type Beat = CDouble+type BPM = CDouble+type Micros = Int64+type Quantum = CDouble++instance Storable AbletonLink where+ alignment _ = #{alignment abl_link}+ sizeOf _ = #{size abl_link}+ peek ptr = do+ impl <- #{peek abl_link,impl} ptr+ return (AbletonLink impl)+ poke ptr (AbletonLink impl) = do+ #{poke abl_link,impl} ptr impl++instance Storable SessionState where+ alignment _ = #{alignment abl_link_session_state}+ sizeOf _ = #{size abl_link_session_state}+ peek ptr = do+ impl <- #{peek abl_link_session_state,impl} ptr+ return (SessionState impl)+ poke ptr (SessionState impl) = do+ #{poke abl_link_session_state,impl} ptr impl++foreign import ccall "abl_link.h abl_link_create"+ create :: BPM -> IO AbletonLink++foreign import ccall "abl_link.h abl_link_enable"+ abl_link_enable :: AbletonLink -> CBool -> IO ()++setEnabled :: Bool -> AbletonLink -> IO ()+setEnabled True al = abl_link_enable al (CBool 1)+setEnabled False al = abl_link_enable al (CBool 0)++enable :: AbletonLink -> IO ()+enable = setEnabled True++disable :: AbletonLink -> IO ()+disable = setEnabled False++foreign import ccall "abl_link.h abl_link_create_session_state"+ createSessionState :: IO SessionState++foreign import ccall "abl_link.h abl_link_capture_app_session_state"+ captureAppSessionState :: AbletonLink -> SessionState -> IO ()++createAndCaptureAppSessionState :: AbletonLink -> IO SessionState+createAndCaptureAppSessionState al = do+ sessionState <- createSessionState+ captureAppSessionState al sessionState+ return sessionState++foreign import ccall "abl_link.h abl_link_commit_app_session_state"+ commitAppSessionState :: AbletonLink -> SessionState -> IO ()++foreign import ccall "abl_link.h abl_link_destroy_session_state"+ destroySessionState :: SessionState -> IO ()++commitAndDestroyAppSessionState :: AbletonLink -> SessionState -> IO ()+commitAndDestroyAppSessionState al ss = do+ commitAppSessionState al ss+ destroySessionState ss++foreign import ccall "abl_link.h abl_link_clock_micros"+ clock :: AbletonLink -> IO Micros++foreign import ccall "abl_link.h abl_link_beat_at_time"+ beatAtTime :: SessionState -> Micros -> Quantum -> IO Beat++foreign import ccall "abl_link.h abl_link_time_at_beat"+ timeAtBeat :: SessionState -> Beat -> Quantum -> IO Micros++foreign import ccall "abl_link.h abl_link_tempo"+ getTempo :: SessionState -> IO BPM++foreign import ccall "abl_link.h abl_link_set_tempo"+ setTempo :: SessionState -> BPM -> Micros -> IO ()++foreign import ccall "abl_link.h abl_link_request_beat_at_time"+ requestBeatAtTime :: SessionState -> Beat -> Micros -> Quantum -> IO ()++foreign import ccall "abl_link.h abl_link_force_beat_at_time"+ forceBeatAtTime :: SessionState -> Beat -> Micros -> Quantum -> IO ()++-- |Test+hello :: IO ()+hello = do+ print "hello"+ link <- create 88+ print "Created link"+ _ <- getLine+ print "gotline"+ now <- clock link+ print $ "Now: " ++ show now+ print "gotline"+ enable link+ print "Link enabled"+ _ <- getLine+ print "gotline"+ sessionState <- createSessionState+ print "Created sessionState"+ _ <- getLine+ print "gotline"+ captureAppSessionState link sessionState+ _line_1 <- getLine+ print "gotline"+ setTempo sessionState 130 now+ beat <- beatAtTime sessionState now 1+ print $ "beat: " ++ show beat+ _line_2 <- getLine+ print "gotline"+ now' <- clock link+ print $ "Now': " ++ show now'+ beat' <- beatAtTime sessionState now' 1+ print $ "beat': " ++ show beat'+ commitAndDestroyAppSessionState link sessionState+ _line_3 <- getLine+ print $ "done"
+ tidal-link.cabal view
@@ -0,0 +1,87 @@+cabal-version: 2.4+name: tidal-link+version: 1.0+synopsis: Ableton Link integration for Tidal+-- description:+homepage: http://tidalcycles.org/+license: GPL-3.0-only+license-file: LICENSE+author: Pierre Krafft+maintainer: Pierre Krafft <kpierre@outlook.com>, Alex McLean <alex@slab.org>+Stability: Experimental+Copyright: (c) Pierre Krafft and contributors, 2021+category: Sound+build-type: Simple+tested-with: GHC == 9.2.4++extra-source-files:+ README.md+ link/**/*.hpp+ link/**/*.ipp+ link/**/*.h++description: Ableton Link integration for Tidal, to let Tidal sync with external clocks++library+ ghc-options: -Wall+ hs-source-dirs: src/hs++ default-language: Haskell2010++ Exposed-modules: Sound.Tidal.Link++ Build-depends:+ base >=4.8 && <5++ if os(windows)+ if impl(ghc >= 9.4.0)+ extra-libraries:+ c+++ iphlpapi+ winmm+ ws2_32+ else+ extra-libraries:+ stdc+++ iphlpapi+ winmm+ ws2_32+ cxx-options:+ -DLINK_PLATFORM_WINDOWS=1 -Wno-multichar -Wno-subobject-linkage+ cxx-sources: link/extensions/abl_link/src/abl_link.cpp+ elif os(darwin)+ extra-libraries:+ stdc+++ cxx-options:+ -DLINK_PLATFORM_MACOSX=1 -std=c++14 -Wno-multichar -Wno-subobject-linkage+ cxx-sources: link/extensions/abl_link/src/abl_link.cpp+ else+ extra-libraries:+ stdc+++ cxx-options:+ -DLINK_PLATFORM_LINUX=1 -std=c++14 -Wno-multichar -Wno-subobject-linkage+ cxx-sources: link/extensions/abl_link/src/abl_link.cpp++ Build-depends:+ base >=4.8 && <5++ include-dirs:+ link/include+ link/modules/asio-standalone/asio/include+ link/extensions/abl_link/include++source-repository head+ type: git+ location: https://github.com/tidalcycles/Tidal++executable linktest+ ghc-options: -Wall+ hs-source-dirs:+ src/hs+ main-is: Main.hs++ default-language: Haskell2010++ Build-depends:+ base >=4.8 && <5,+ tidal-link