Last active
April 16, 2017 08:01
-
-
Save microcai/90eb272830586f73bbdab639b7f98005 to your computer and use it in GitHub Desktop.
新的 smart_timer 来啦!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <tuple> | |
#include <mutex> | |
#include <boost/asio.hpp> | |
#include <boost/bind.hpp> | |
#include <boost/function.hpp> | |
#include <boost/shared_ptr.hpp> | |
#include <boost/weak_ptr.hpp> | |
namespace smart_timer { | |
namespace errc { | |
/// HTTP error codes. | |
/** | |
* The enumerators of type @c errc_t are implicitly convertible to objects of | |
* type @c boost::system::error_code. | |
* | |
* @par Requirements | |
* @e Header: @c <error_codec.hpp> @n | |
* @e Namespace: @c avhttp::errc | |
*/ | |
enum errc_t | |
{ | |
/// wake_up called | |
timer_wakup = 1, | |
}; | |
} // namespace errc | |
namespace detail { | |
class error_category_impl | |
: public boost::system::error_category | |
{ | |
virtual const char* name() const BOOST_SYSTEM_NOEXCEPT | |
{ | |
return "HTTP"; | |
} | |
virtual std::string message(int e) const | |
{ | |
switch (e) | |
{ | |
case errc::timer_wakup: | |
return "wakeup called "; | |
default: | |
return "Unknown smart_timer error"; | |
} | |
} | |
}; | |
} | |
template<class error_category> | |
const boost::system::error_category& error_category_single() | |
{ | |
static error_category error_category_instance; | |
return reinterpret_cast<const boost::system::error_category&>(error_category_instance); | |
} | |
inline const boost::system::error_category& error_category() | |
{ | |
return error_category_single<detail::error_category_impl>(); | |
} | |
namespace errc | |
{ | |
/// Converts a value of type @c errc_t to a corresponding object of type | |
/// @c boost::system::error_code. | |
/** | |
* @par Requirements | |
* @e Header: @c <error_codec.hpp> @n | |
* @e Namespace: @c avhttp::errc | |
*/ | |
inline boost::system::error_code make_error_code(errc_t e) | |
{ | |
return boost::system::error_code(static_cast<int>(e), smart_timer::error_category()); | |
} | |
} | |
template<typename TimerType, typename T> | |
class smart_timer | |
{ | |
struct timer_handler_op_base | |
{ | |
bool volatile no_handler = false; | |
virtual void handle_wait(boost::system::error_code) = 0; | |
virtual void handle_waitup(boost::system::error_code ec, T arg) = 0; | |
}; | |
template<typename Handler> | |
struct timer_handler_op : public timer_handler_op_base | |
{ | |
timer_handler_op(Handler handler) | |
: m_handler(handler) | |
{ | |
} | |
virtual void handle_wait(boost::system::error_code ec) override | |
{ | |
if (ec == boost::asio::error::operation_aborted) | |
{ | |
if (timer_handler_op_base::no_handler) | |
return; | |
else | |
{ | |
// std::cerr << "123123123 = is = " << timer_handler_op_base::no_handler << std::endl; | |
// return; | |
} | |
} | |
m_handler(ec, T()); | |
} | |
virtual void handle_waitup(boost::system::error_code ec, T arg) override | |
{ | |
m_handler(ec, arg); | |
} | |
Handler m_handler; | |
}; | |
struct timer_handler_op_wrap | |
{ | |
typedef void result_type; | |
boost::shared_ptr<timer_handler_op_base> m_op; | |
timer_handler_op_wrap(boost::shared_ptr<timer_handler_op_base> _op) | |
: m_op(_op) | |
{ | |
} | |
void operator()(boost::system::error_code ec) | |
{ | |
m_op->handle_wait(ec); | |
} | |
void operator()(boost::system::error_code ec, T arg) | |
{ | |
m_op->handle_waitup(ec, arg); | |
} | |
}; | |
public: | |
explicit smart_timer(boost::asio::io_service& io) | |
: io(io) | |
, m_timer(io) | |
{} | |
template<typename... TT> | |
void expires_from_now(TT... arg) | |
{ | |
m_timer.expires_from_now(arg...); | |
} | |
template<typename Handler> | |
void async_wait(BOOST_ASIO_MOVE_ARG(Handler) handler) | |
{ | |
boost::shared_ptr<timer_handler_op_base> _handler_op; | |
std::unique_lock<std::mutex> l(m); | |
_handler_op.reset(new timer_handler_op<Handler>(handler)); | |
m_handler = _handler_op; | |
m_timer.async_wait(timer_handler_op_wrap(_handler_op)); | |
} | |
void wake_up(T arg) | |
{ | |
std::unique_lock<std::mutex> l(m); | |
auto handler = m_handler.lock(); | |
if (handler) | |
{ | |
handler->no_handler = true; | |
io.post(boost::asio::detail::bind_handler(timer_handler_op_wrap(handler), errc::make_error_code(errc::timer_wakup), arg)); | |
boost::system::error_code ignore; | |
m_timer.cancel(ignore); | |
} | |
} | |
void cancel() | |
{ | |
m_timer.cancel(); | |
} | |
template<typename... TT> | |
void cancel(TT... arg) | |
{ | |
m_timer.cancel(arg...); | |
} | |
private: | |
boost::asio::io_service& io; | |
TimerType m_timer; | |
boost::weak_ptr<timer_handler_op_base> m_handler; | |
std::mutex m; | |
}; | |
} // namespace smart_timer | |
namespace boost { | |
namespace system { | |
template<> struct is_error_code_enum<smart_timer::errc::errc_t> | |
{ | |
static const bool value = true; | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment