.. _program_listing_file_stream-client_detail_timed_base.hpp: Program Listing for File timed_base.hpp ======================================= |exhale_lsh| :ref:`Return to documentation for file ` (``stream-client/detail/timed_base.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #pragma once #include #include #include #include namespace stream_client { namespace detail { template class timed_base { public: using clock_type = Clock; using time_duration_type = typename clock_type::duration; using time_point_type = typename clock_type::time_point; using timer_type = typename boost::asio::basic_waitable_timer; static constexpr time_duration_type kInfiniteDuration = time_duration_type::max(); static constexpr time_duration_type kZeroDuration = time_duration_type(0); static constexpr time_duration_type kDurationResolution = time_duration_type(1000); // 1us static constexpr time_duration_type kMinTimeout = 2 * kDurationResolution; class expiration final { public: expiration(timer_type* timer = nullptr) : timer_(timer) { } expiration(timer_type* timer, const time_duration_type& duration) : expiration(timer) { if (duration < kDurationResolution) { throw boost::system::system_error{boost::asio::error::timed_out}; } if (duration == kInfiniteDuration) { timer_ = nullptr; return; } if (timer_) { timer_->expires_from_now(duration); } } expiration(timer_type* timer, const time_point_type& deadline) : expiration(timer) { if (timer_) { timer_->expires_at(deadline); } } // copy ctor expiration(const expiration& other) = default; // move ctor expiration(expiration&& other) noexcept { *this = std::move(other); } // copy assignment inline expiration& operator=(const expiration& other) = default; // move assignment inline expiration& operator=(expiration&& other) noexcept { timer_ = std::exchange(other.timer_, nullptr); return *this; } ~expiration() { if (timer_) { timer_->expires_from_now(kInfiniteDuration); } } private: timer_type* timer_; }; timed_base() : deadline_fired_(false) , io_service_(std::make_unique()) , timer_(std::make_unique(*io_service_)) { // No deadline is required until the first operation is started. We // set the deadline to positive infinity so the actor takes no action // until a specific deadline is set. timer_->expires_from_now(kInfiniteDuration); post_deadline(); } timed_base(const timed_base& other) = delete; timed_base& operator=(const timed_base& other) = delete; timed_base(timed_base&& other) = default; timed_base& operator=(timed_base&& other) = default; virtual ~timed_base() { if (io_service_) { io_service_->stop(); } } inline boost::asio::io_service& get_io_service() { return *io_service_; } inline const boost::asio::io_service& get_io_service() const { return *io_service_; } template expiration scope_expire(const Time& timeout_or_deadline) { deadline_fired_ = false; return expiration(timer_.get(), timeout_or_deadline); } protected: virtual void deadline_actor() = 0; bool deadline_fired_; private: inline void post_deadline() { timer_->async_wait([this](const boost::system::error_code& ec) { this->check_deadline(ec); }); } void check_deadline(const boost::system::error_code& /*ec*/) { if (timer_->expires_at() <= clock_type::now()) { deadline_actor(); deadline_fired_ = true; timer_->expires_from_now(kInfiniteDuration); } // if deadline fired or reset to new one, check_deadline() gets reposted post_deadline(); } std::unique_ptr io_service_; std::unique_ptr timer_; }; template constexpr typename timed_base::time_duration_type timed_base::kInfiniteDuration; template constexpr typename timed_base::time_duration_type timed_base::kZeroDuration; template constexpr typename timed_base::time_duration_type timed_base::kDurationResolution; template constexpr typename timed_base::time_duration_type timed_base::kMinTimeout; using system_timed_base = timed_base; using steady_timed_base = timed_base; using high_resolution_timed_base = timed_base; } // namespace detail } // namespace stream_client