⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 custom_event_handler.hpp

📁 用STL的方式封装了WindowsAPI、COM调用、ACE、ATL、MFC、WTL等多种组件
💻 HPP
📖 第 1 页 / 共 2 页
字号:
        {
            return m_ceh->handle_callback_timeout(current_time, const_cast<void*>(arg));
        }

    private:
        custom_event_handler    *const  m_ceh;

    private:
        callback_hook(callback_hook const &);
        callback_hook &operator =(callback_hook const &);
    };

    friend class callback_hook;

    // Each entry consists of the notification code and the actual arg
    struct event_info
    {
        long        code;   //!< The event code
        void        *arg;   //!< The custom event argument
        event_id    id;     //!< The id of the event registered in the reactor

        event_info(long code_, void *arg_)
            : code(code_)
            , arg(arg_)
            , id(NULL)
        {}
    };

    typedef ::stlsoft::shared_ptr<event_info>    info_ptr;

    // receiver of the callback hook's handle_timeout call,
    int handle_callback_timeout(ACE_Time_Value const    &current_time
                            ,   void                    *arg);

    // This is used to avoid compiler warnings about using 'this' in member
    // initialiser lists
    class_type *get_this_()
    {
        return this;
    }

    // Invariant
    as_bool_t   is_valid() const;

    //
    event_id    schedule_event_(event_info *entry, ACE_Time_Value const &delay);
    as_int_t    cancel_event_(event_id );

// Members
private:
    // There are two maps.
    //
    // 1. The long=>event_info* map is used for registration/deregistration. Because
    // it owns the entries it uses the associative_container_veneer
    //
    // 2. The event_info*=>long map is used

    typedef ::std::map<event_id, info_ptr>      event_map_type;
    typedef ::std::map<long, event_map_type>    event_code_map_type;

    callback_hook       m_callbackHook;
    event_code_map_type m_entries;

// Not to be implemented
private:
    custom_event_handler(class_type const &);
    class_type &operator =(class_type const &);
};

////////////////////////////////////////////////////////////////////////////

/// @} // acestl_messaging_library

////////////////////////////////////////////////////////////////////////////
// Unit-testing

#ifdef STLSOFT_UNITTEST
# include "./unittest/custom_event_handler_unittest_.h"
#endif /* STLSOFT_UNITTEST */

/* /////////////////////////////////////////////////////////////////////////
 * Implementation
 */

#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION

#ifdef STLSOFT_COMPILER_IS_MSVC
# if _MSC_VER >= 1200
#  pragma warning(push)
# endif /* compiler */
# pragma warning(disable : 4702)
#endif /* compiler */

inline custom_event_handler::event_id custom_event_handler::schedule_event_(event_info *entry, ACE_Time_Value const &delay)
{
    long    timerId =   m_callbackHook.reactor()->schedule_timer(&m_callbackHook, entry, delay);

    ACESTL_MESSAGE_ASSERT("Unexpected negative value", timerId >= -1 || -1 == timerId);

    return (-1 == timerId) ? NULL : reinterpret_cast<event_id>(static_cast<as_size_t>(1 + timerId));
}

inline as_int_t custom_event_handler::cancel_event_(custom_event_handler::event_id id)
{
    ACESTL_ASSERT(NULL != id);

    return m_callbackHook.reactor()->cancel_timer(static_cast<long>(reinterpret_cast<as_size_t>(id - 1)));
}

inline as_bool_t custom_event_handler::is_valid() const
{
    return true;
}

inline custom_event_handler::custom_event_handler(  ACE_Reactor *reactor    /* =   ACE_Reactor::instance() */
                                                ,   int         priority    /* =   ACE_Event_Handler::LO_PRIORITY */)
    : parent_class_type(reactor, priority)
    , m_callbackHook(get_this_(), reactor, priority)
{
    ACESTL_ASSERT(NULL != reactor);
    ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());
}

inline custom_event_handler::~custom_event_handler() stlsoft_throw_0()
{
    ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

    ACESTL_MESSAGE_ASSERT("Custom event handler destroyed with outstanding entries: derived classes should cancel all notifications", m_entries.empty());
}

inline custom_event_handler::event_id custom_event_handler::schedule_custom_event(long code, ACE_Time_Value const &delay, void *arg /* = 0 */)
{
    ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

    // Create an event, and then schedule it.

    event_info  *entry_;

    ACE_NEW_NORETURN(entry_, event_info(code, arg));

    if(NULL == entry_)
    {
        ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

        ACE_ERROR_RETURN(   (   LM_ALERT
                            ,   ACE_TEXT("(%P|%t) out of memory"))
                        ,   0);
    }
    else
    {
        info_ptr    entry(entry_);
        event_id    timerId =   schedule_event_(entry.get(), delay);

        if(NULL == timerId)
        {
            ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

            ACE_ERROR_RETURN(   (   LM_ALERT
                                ,   ACE_TEXT("(%P|%t) timer registration failed"))
                            ,   0);
        }
        else
        {
            entry->id = timerId;

            try
            {
                // Benign if leaves code but fails to add event
                m_entries[code][timerId] = entry;
            }
            catch(std::bad_alloc &) // This clause is fine, since if bad_alloc not thrown, no foul
            {
                cancel_event_(timerId);

                ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

                ACE_OS::last_error(ENOMEM);
                ACE_ERROR_RETURN(   (   LM_ALERT
                                    ,   ACE_TEXT("(%P|%t) out of memory"))
                                ,   0);
            }
            catch(std::exception &x)
            {
                cancel_event_(timerId);

                ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

                ACE_ERROR_RETURN(   (   LM_ALERT
                                    ,   ACE_TEXT("(%P|%t) event scheduling failed: %s")
                                    ,   x.what())
                                ,   0);
            }

            ACESTL_MESSAGE_ASSERT("event not in handler", this->has_custom_event(timerId));

            ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

            return timerId;
        }
    }
}

inline custom_event_handler::event_id custom_event_handler::schedule_custom_event(long code, void *arg /* = 0 */)
{
    ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

    return schedule_custom_event(code, ACE_Time_Value(0), arg);
}

inline int custom_event_handler::cancel_custom_events(long code, custom_event_handler::cancelled_event_code_fn pfn, void *param)
{
    ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

    event_code_map_type::iterator    it  =   m_entries.find(code);

    if(m_entries.end() == it)
    {
        ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

        return 0;
    }
    else
    {
        // Now need to cancel the timers for all the events in the code map
        event_map_type              &codes  =   (*it).second;
        event_map_type::iterator    begin   =   codes.begin();
        event_map_type::iterator    end     =   codes.end();
        as_int_t                    n;

        for(n = 0; begin != end; ++begin)
        {
            info_ptr    entry   =   (*begin).second;

            if(NULL != pfn)
            {
                (*pfn)(param, entry->code, entry->id, entry->arg);
            }

            if(cancel_event_(entry->id))
            {
                ++n;
            }
        }

        m_entries.erase(it);

        ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

        return n;
    }
}

inline int custom_event_handler::cancel_custom_events(long code)
{
    return cancel_custom_events(code, NULL, NULL);
}

inline int custom_event_handler::cancel_custom_event(custom_event_handler::event_id event, void **parg /* = NULL */)
{
    ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

    /// TODO: Maybe improve the performance of this later, perhaps by having a second map of id=>entry

    event_code_map_type::iterator    be  =   m_entries.begin();
    event_code_map_type::iterator    ee  =   m_entries.end();

    for(; be != ee; ++be)
    {
        event_map_type              &event_map  =   (*be).second;
        event_map_type::iterator    it          =   event_map.find(event);

        if(event_map.end() != it)
        {
            if(NULL != parg)
            {
                *parg = (*it).second->arg;
            }

            event_map.erase(it);

            return cancel_event_(event);
        }
    }

    return 0;
}

inline as_int_t custom_event_handler::has_custom_event(long code) const
{
    ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

    event_code_map_type::const_iterator  it  =   m_entries.find(code);

    return (m_entries.end() != it) ? static_cast<as_int_t>((*it).second.size()) : 0;
}

inline as_int_t custom_event_handler::has_custom_event(event_id event) const
{
    ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

    /// TODO: Maybe improve the performance of this later, perhaps by having a second map of id=>entry

    event_code_map_type::const_iterator  be      =   m_entries.begin();
    event_code_map_type::const_iterator  ee      =   m_entries.end();

    for(; be != ee; ++be)
    {
        event_map_type const            &event_map  =   (*be).second;
        event_map_type::const_iterator  it          =   event_map.find(event);

        if(event_map.end() != it)
        {
            return 1;
        }
    }

    return 0;
}

inline int custom_event_handler::handle_callback_timeout(ACE_Time_Value const &current_time, void *arg)
{
    ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

    event_info const                *entry  =   static_cast<event_info const*>(arg);
    event_code_map_type::iterator   itc     =   m_entries.find(entry->code);

    // Is it one of ours?
    if(m_entries.end() == itc)
    {
        ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

        ACE_ERROR_RETURN(   (   LM_ALERT
                            ,   ACE_TEXT("(%P|%t) could not locate callback entry for that code"))
                        ,   0); // NOTE: returns 0, so as not to cause the event handler to be de-registered
    }
    else
    {
        ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

        // Yes it is. So ...
        event_map_type              &event_map  =   (*itc).second;
        event_map_type::iterator    ite         =   event_map.find(entry->id);

        ACESTL_ASSERT(event_map.end() != ite);

        // ... keep the entry alive, and ...
        info_ptr    ep = (*ite).second;

        // ... we erase the entry, and ...
        event_map.erase(ite);

        // ... check whether we need to erase the entries map, and ...
        if(event_map.empty())
        {
            m_entries.erase(itc);
        }

        ACESTL_MESSAGE_ASSERT("invariant violation", is_valid());

        // ... then call the handler
        return this->handle_custom_event(current_time, entry->code, entry->arg);
    }
}

#ifdef STLSOFT_COMPILER_IS_MSVC
# if _MSC_VER >= 1200
#  pragma warning(push)
# else /* ? compiler */
#  pragma warning(default : 4702)
# endif /* _MSC_VER */
#endif /* compiler */

#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */

/* ////////////////////////////////////////////////////////////////////// */

#ifndef _ACESTL_NO_NAMESPACE
# if defined(_STLSOFT_NO_NAMESPACE) || \
     defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
} // namespace acestl
# else
} // namespace acestl_project
} // namespace stlsoft
# endif /* _STLSOFT_NO_NAMESPACE */
#endif /* !_ACESTL_NO_NAMESPACE */

/* ////////////////////////////////////////////////////////////////////// */

#endif /* ACESTL_INCL_ACESTL_HPP_CUSTOM_EVENT_HANDLER */

/* ////////////////////////////////////////////////////////////////////// */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -