diff options
Diffstat (limited to '3rdparty/asio/src/examples/cpp11/invocation')
-rw-r--r-- | 3rdparty/asio/src/examples/cpp11/invocation/prioritised_handlers.cpp | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/3rdparty/asio/src/examples/cpp11/invocation/prioritised_handlers.cpp b/3rdparty/asio/src/examples/cpp11/invocation/prioritised_handlers.cpp new file mode 100644 index 00000000000..533bfd06861 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp11/invocation/prioritised_handlers.cpp @@ -0,0 +1,202 @@ +// +// prioritised_handlers.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "asio.hpp" +#include <iostream> +#include <memory> +#include <queue> + +using asio::ip::tcp; + +class handler_priority_queue : public asio::execution_context +{ +public: + template <typename Function> + void add(int priority, Function function) + { + std::unique_ptr<queued_handler_base> handler( + new queued_handler<Function>( + priority, std::move(function))); + + handlers_.push(std::move(handler)); + } + + void execute_all() + { + while (!handlers_.empty()) + { + handlers_.top()->execute(); + handlers_.pop(); + } + } + + class executor + { + public: + executor(handler_priority_queue& q, int p) + : context_(q), priority_(p) + { + } + + handler_priority_queue& context() const noexcept + { + return context_; + } + + template <typename Function, typename Allocator> + void dispatch(Function f, const Allocator&) const + { + context_.add(priority_, std::move(f)); + } + + template <typename Function, typename Allocator> + void post(Function f, const Allocator&) const + { + context_.add(priority_, std::move(f)); + } + + template <typename Function, typename Allocator> + void defer(Function f, const Allocator&) const + { + context_.add(priority_, std::move(f)); + } + + void on_work_started() const noexcept {} + void on_work_finished() const noexcept {} + + bool operator==(const executor& other) const noexcept + { + return &context_ == &other.context_ && priority_ == other.priority_; + } + + bool operator!=(const executor& other) const noexcept + { + return !operator==(other); + } + + private: + handler_priority_queue& context_; + int priority_; + }; + + template <typename Handler> + asio::executor_binder<Handler, executor> + wrap(int priority, Handler handler) + { + return asio::bind_executor( + executor(*this, priority), std::move(handler)); + } + +private: + class queued_handler_base + { + public: + queued_handler_base(int p) + : priority_(p) + { + } + + virtual ~queued_handler_base() + { + } + + virtual void execute() = 0; + + friend bool operator<(const std::unique_ptr<queued_handler_base>& a, + const std::unique_ptr<queued_handler_base>& b) noexcept + { + return a->priority_ < b->priority_; + } + + private: + int priority_; + }; + + template <typename Function> + class queued_handler : public queued_handler_base + { + public: + queued_handler(int p, Function f) + : queued_handler_base(p), function_(std::move(f)) + { + } + + void execute() override + { + function_(); + } + + private: + Function function_; + }; + + std::priority_queue<std::unique_ptr<queued_handler_base>> handlers_; +}; + +//---------------------------------------------------------------------- + +void high_priority_handler(const std::error_code& /*ec*/, + tcp::socket /*socket*/) +{ + std::cout << "High priority handler\n"; +} + +void middle_priority_handler(const std::error_code& /*ec*/) +{ + std::cout << "Middle priority handler\n"; +} + +struct low_priority_handler +{ + // Make the handler a move-only type. + low_priority_handler() = default; + low_priority_handler(const low_priority_handler&) = delete; + low_priority_handler(low_priority_handler&&) = default; + + void operator()() + { + std::cout << "Low priority handler\n"; + } +}; + +int main() +{ + asio::io_context io_context; + + handler_priority_queue pri_queue; + + // Post a completion handler to be run immediately. + asio::post(io_context, pri_queue.wrap(0, low_priority_handler())); + + // Start an asynchronous accept that will complete immediately. + tcp::endpoint endpoint(asio::ip::address_v4::loopback(), 0); + tcp::acceptor acceptor(io_context, endpoint); + tcp::socket server_socket(io_context); + acceptor.async_accept(pri_queue.wrap(100, high_priority_handler)); + tcp::socket client_socket(io_context); + client_socket.connect(acceptor.local_endpoint()); + + // Set a deadline timer to expire immediately. + asio::steady_timer timer(io_context); + timer.expires_at(asio::steady_timer::clock_type::time_point::min()); + timer.async_wait(pri_queue.wrap(42, middle_priority_handler)); + + while (io_context.run_one()) + { + // The custom invocation hook adds the handlers to the priority queue + // rather than executing them from within the poll_one() call. + while (io_context.poll_one()) + ; + + pri_queue.execute_all(); + } + + return 0; +} |