optimize template class to reduce generated binary size
This commit is contained in:
parent
2dd9283782
commit
0ed51a7a21
@ -24,6 +24,9 @@ namespace nana
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
void events_operation_register(event_handle);
|
||||
void events_operation_cancel(event_handle);
|
||||
|
||||
class event_interface
|
||||
{
|
||||
public:
|
||||
@ -38,8 +41,50 @@ namespace nana
|
||||
virtual event_interface* get_event() const = 0;
|
||||
};
|
||||
|
||||
void events_operation_register(event_handle);
|
||||
void events_operation_cancel(event_handle);
|
||||
|
||||
struct docker_base
|
||||
: public docker_interface
|
||||
{
|
||||
event_interface * event_ptr;
|
||||
bool flag_deleted{ false };
|
||||
const bool unignorable;
|
||||
|
||||
docker_base(event_interface*, bool unignorable_flag);
|
||||
|
||||
detail::event_interface * get_event() const override;
|
||||
};
|
||||
|
||||
class event_base
|
||||
: public detail::event_interface
|
||||
{
|
||||
public:
|
||||
~event_base();
|
||||
|
||||
std::size_t length() const;
|
||||
void clear() noexcept;
|
||||
|
||||
void remove(event_handle evt) override;
|
||||
protected:
|
||||
//class emit_counter is a RAII helper for emitting count
|
||||
//It is used for avoiding a try{}catch block which is required for some finial works when
|
||||
//event handlers throw exceptions.
|
||||
class emit_counter
|
||||
{
|
||||
public:
|
||||
emit_counter(event_base*);
|
||||
~emit_counter();
|
||||
private:
|
||||
event_base * const evt_;
|
||||
};
|
||||
|
||||
//event_handle _m_emplace(::std::unique_ptr<detail::docker_interface>& docker_ptr, bool in_front);
|
||||
event_handle _m_emplace(detail::docker_interface*, bool in_front);
|
||||
protected:
|
||||
unsigned emitting_count_{ 0 };
|
||||
bool deleted_flags_{ false };
|
||||
//std::unique_ptr<std::vector<std::unique_ptr<detail::docker_interface>>> dockers_;
|
||||
std::vector<detail::docker_interface*> * dockers_{ nullptr };
|
||||
};
|
||||
}//end namespace detail
|
||||
|
||||
/// base clase for all event argument types
|
||||
@ -59,83 +104,32 @@ namespace nana
|
||||
|
||||
/// the type of the members of general_events
|
||||
template<typename Arg>
|
||||
class basic_event : public detail::event_interface
|
||||
class basic_event : public detail::event_base
|
||||
{
|
||||
public:
|
||||
using arg_reference = const typename std::remove_reference<Arg>::type &;
|
||||
private:
|
||||
struct docker
|
||||
: public detail::docker_interface
|
||||
: public detail::docker_base
|
||||
{
|
||||
basic_event * const event_ptr;
|
||||
std::function<void(arg_reference)> invoke;
|
||||
|
||||
bool flag_deleted{ false };
|
||||
bool unignorable{false};
|
||||
|
||||
docker(basic_event * s, std::function<void(arg_reference)> && ivk, bool unignorable_flag)
|
||||
: event_ptr(s), invoke(std::move(ivk)), unignorable(unignorable_flag)
|
||||
docker(basic_event * evt, std::function<void(arg_reference)> && ivk, bool unignorable_flag)
|
||||
: docker_base(evt, unignorable_flag), invoke(std::move(ivk))
|
||||
{}
|
||||
|
||||
docker(basic_event * s, const std::function<void(arg_reference)> & ivk, bool unignorable_flag)
|
||||
: event_ptr(s), invoke(ivk), unignorable(unignorable_flag)
|
||||
docker(basic_event * evt, const std::function<void(arg_reference)> & ivk, bool unignorable_flag)
|
||||
: docker_base(evt, unignorable_flag), invoke(ivk)
|
||||
{}
|
||||
|
||||
~docker()
|
||||
{
|
||||
detail::events_operation_cancel(reinterpret_cast<event_handle>(this));
|
||||
}
|
||||
|
||||
detail::event_interface * get_event() const override
|
||||
{
|
||||
return event_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
//class emit_counter is a RAII helper for emitting count
|
||||
//It is used for avoiding a try{}catch block which is required for some finial works when
|
||||
//event handlers throw exceptions.
|
||||
class emit_counter
|
||||
{
|
||||
public:
|
||||
emit_counter(basic_event* evt)
|
||||
: evt_{evt}
|
||||
{
|
||||
++evt->emitting_count_;
|
||||
}
|
||||
|
||||
~emit_counter()
|
||||
{
|
||||
if ((0 == --evt_->emitting_count_) && evt_->deleted_flags_)
|
||||
{
|
||||
evt_->deleted_flags_ = false;
|
||||
for (auto i = evt_->dockers_->begin(); i != evt_->dockers_->end();)
|
||||
{
|
||||
if (static_cast<docker*>(i->get())->flag_deleted)
|
||||
i = evt_->dockers_->erase(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
basic_event * const evt_;
|
||||
};
|
||||
public:
|
||||
/// It will get called firstly, because it is set at the beginning of the chain.
|
||||
/// Creates an event handler at the beginning of event chain
|
||||
template<typename Function>
|
||||
event_handle connect_front(Function && fn)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
if (nullptr == dockers_)
|
||||
dockers_.reset(new std::vector<std::unique_ptr<detail::docker_interface>>);
|
||||
|
||||
{
|
||||
using prototype = typename std::remove_reference<Function>::type;
|
||||
std::unique_ptr<detail::docker_interface> dck(new docker(this, factory<prototype, std::is_bind_expression<prototype>::value>::build(std::forward<Function>(fn)), false));
|
||||
auto evt = reinterpret_cast<event_handle>(dck.get());
|
||||
dockers_->emplace(dockers_->begin(), std::move(dck));
|
||||
detail::events_operation_register(evt);
|
||||
return evt;
|
||||
|
||||
return _m_emplace(new docker(this, factory<prototype, std::is_bind_expression<prototype>::value>::build(std::forward<Function>(fn)), false), true);
|
||||
}
|
||||
|
||||
event_handle connect(void (*fn)(arg_reference))
|
||||
@ -149,16 +143,9 @@ namespace nana
|
||||
template<typename Function>
|
||||
event_handle connect(Function && fn)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
if (nullptr == dockers_)
|
||||
dockers_.reset(new std::vector<std::unique_ptr<detail::docker_interface>>);
|
||||
|
||||
using prototype = typename std::remove_reference<Function>::type;
|
||||
std::unique_ptr<detail::docker_interface> dck(new docker(this, factory<prototype, std::is_bind_expression<prototype>::value>::build(std::forward<Function>(fn)), false));
|
||||
auto evt = reinterpret_cast<event_handle>(dck.get());
|
||||
dockers_->emplace_back(std::move(dck));
|
||||
detail::events_operation_register(evt);
|
||||
return evt;
|
||||
|
||||
return _m_emplace(new docker(this, factory<prototype, std::is_bind_expression<prototype>::value>::build(std::forward<Function>(fn)), false), false);
|
||||
}
|
||||
|
||||
/// It will not get called if stop_propagation() was called.
|
||||
@ -171,26 +158,10 @@ namespace nana
|
||||
/// It will get called because it is unignorable.
|
||||
template<typename Function>
|
||||
event_handle connect_unignorable(Function && fn, bool in_front = false)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
if (nullptr == dockers_)
|
||||
dockers_.reset(new std::vector<std::unique_ptr<detail::docker_interface>>);
|
||||
|
||||
{
|
||||
using prototype = typename std::remove_reference<Function>::type;
|
||||
std::unique_ptr<detail::docker_interface> dck(new docker(this, factory<prototype, std::is_bind_expression<prototype>::value>::build(std::forward<Function>(fn)), true));
|
||||
auto evt = reinterpret_cast<event_handle>(dck.get());
|
||||
if (in_front)
|
||||
dockers_->emplace(dockers_->begin(), std::move(dck));
|
||||
else
|
||||
dockers_->emplace_back(std::move(dck));
|
||||
detail::events_operation_register(evt);
|
||||
return evt;
|
||||
}
|
||||
|
||||
std::size_t length() const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
return (nullptr == dockers_ ? 0 : dockers_->size());
|
||||
return _m_emplace(new docker(this, factory<prototype, std::is_bind_expression<prototype>::value>::build(std::forward<Function>(fn)), true), in_front);
|
||||
}
|
||||
|
||||
void emit(arg_reference& arg)
|
||||
@ -202,13 +173,13 @@ namespace nana
|
||||
emit_counter ec(this);
|
||||
|
||||
auto& dockers = *dockers_;
|
||||
const auto dockers_len = dockers.size();
|
||||
const auto dockers_len = dockers_->size();
|
||||
|
||||
//The dockers may resize when a new event handler is created by a calling handler.
|
||||
//Traverses with position can avaid crash error which caused by a iterator which becomes invalid.
|
||||
for (std::size_t pos = 0; pos < dockers_len; ++pos)
|
||||
{
|
||||
auto docker_ptr = static_cast<docker*>(dockers[pos].get());
|
||||
auto docker_ptr = static_cast<docker*>(dockers[pos]);
|
||||
if (docker_ptr->flag_deleted)
|
||||
continue;
|
||||
|
||||
@ -217,7 +188,7 @@ namespace nana
|
||||
{
|
||||
for (++pos; pos < dockers_len; ++pos)
|
||||
{
|
||||
auto docker_ptr = static_cast<docker*>(dockers[pos].get());
|
||||
auto docker_ptr = static_cast<docker*>(dockers[pos]);
|
||||
if (!docker_ptr->unignorable || docker_ptr->flag_deleted)
|
||||
continue;
|
||||
|
||||
@ -227,36 +198,6 @@ namespace nana
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
if (dockers_)
|
||||
dockers_.reset();
|
||||
}
|
||||
|
||||
void remove(event_handle evt) override
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
if (dockers_)
|
||||
{
|
||||
for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i)
|
||||
{
|
||||
if (reinterpret_cast<detail::docker_interface*>(evt) == i->get())
|
||||
{
|
||||
//Checks whether this event is working now.
|
||||
if (emitting_count_ > 1)
|
||||
{
|
||||
static_cast<docker*>(i->get())->flag_deleted = true;
|
||||
deleted_flags_ = true;
|
||||
}
|
||||
else
|
||||
dockers_->erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
template<typename Fn, bool IsBind>
|
||||
struct factory
|
||||
@ -413,10 +354,6 @@ namespace nana
|
||||
};
|
||||
}
|
||||
};
|
||||
private:
|
||||
unsigned emitting_count_{ 0 };
|
||||
bool deleted_flags_{ false };
|
||||
std::unique_ptr<std::vector<std::unique_ptr<detail::docker_interface>>> dockers_;
|
||||
};
|
||||
|
||||
struct arg_mouse
|
||||
@ -427,12 +364,12 @@ namespace nana
|
||||
::nana::point pos; ///< cursor position in the event window
|
||||
::nana::mouse button; ///< indicates a button which triggers the event
|
||||
|
||||
bool left_button; ///< mouse left button is pressed?
|
||||
bool mid_button; ///< mouse middle button is pressed?
|
||||
bool right_button; ///< mouse right button is pressed?
|
||||
bool alt; ///< keyboard alt is pressed?
|
||||
bool shift; ///< keyboard Shift is pressed?
|
||||
bool ctrl; ///< keyboard Ctrl is pressed?
|
||||
bool left_button; ///< true if mouse left button is pressed
|
||||
bool mid_button; ///< true if mouse middle button is pressed
|
||||
bool right_button; ///< true if mouse right button is pressed
|
||||
bool alt; ///< true if keyboard alt is pressed
|
||||
bool shift; ///< true if keyboard Shift is pressed
|
||||
bool ctrl; ///< true if keyboard Ctrl is pressed
|
||||
|
||||
/// Checks if left button is operated,
|
||||
bool is_left_button() const
|
||||
@ -481,7 +418,7 @@ namespace nana
|
||||
event_code evt_code; ///< it is event_code::key_press in current event
|
||||
::nana::window window_handle; ///< A handle to the event window
|
||||
mutable wchar_t key; ///< the key corresponding to the key pressed
|
||||
mutable bool ignore; ///< this member is not used
|
||||
mutable bool ignore; ///< this member is only available for key_char event, set 'true' to ignore the input.
|
||||
bool ctrl; ///< keyboard Ctrl is pressed?
|
||||
bool shift; ///< keyboard Shift is pressed
|
||||
};
|
||||
|
||||
@ -42,5 +42,112 @@ namespace nana
|
||||
}
|
||||
}
|
||||
//end namespace events_operation
|
||||
|
||||
|
||||
//class docker_base
|
||||
docker_base::docker_base(event_interface* evt, bool unignorable_flag)
|
||||
: event_ptr(evt), unignorable(unignorable_flag)
|
||||
{}
|
||||
|
||||
detail::event_interface * docker_base::get_event() const
|
||||
{
|
||||
return event_ptr;
|
||||
}
|
||||
//end class docker_base
|
||||
|
||||
//class event_base
|
||||
event_base::~event_base()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
std::size_t event_base::length() const
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
return (nullptr == dockers_ ? 0 : dockers_->size());
|
||||
}
|
||||
|
||||
void event_base::clear() noexcept
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
if (dockers_)
|
||||
{
|
||||
for (auto p : *dockers_)
|
||||
{
|
||||
detail::events_operation_cancel(reinterpret_cast<event_handle>(p));
|
||||
delete p;
|
||||
}
|
||||
dockers_->clear();
|
||||
|
||||
delete dockers_;
|
||||
dockers_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void event_base::remove(event_handle evt)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
if (dockers_)
|
||||
{
|
||||
|
||||
for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i)
|
||||
{
|
||||
if (reinterpret_cast<detail::docker_interface*>(evt) == *i)
|
||||
{
|
||||
//Checks whether this event is working now.
|
||||
if (emitting_count_ > 1)
|
||||
{
|
||||
static_cast<docker_base*>(*i)->flag_deleted = true;
|
||||
deleted_flags_ = true;
|
||||
}
|
||||
else
|
||||
dockers_->erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event_handle event_base::_m_emplace(detail::docker_interface* docker_ptr, bool in_front)
|
||||
{
|
||||
internal_scope_guard lock;
|
||||
if (nullptr == dockers_)
|
||||
dockers_ = new std::vector<detail::docker_interface*>;
|
||||
|
||||
auto evt = reinterpret_cast<event_handle>(docker_ptr);
|
||||
|
||||
if (in_front)
|
||||
dockers_->emplace(dockers_->begin(), docker_ptr);
|
||||
else
|
||||
dockers_->emplace_back(docker_ptr);
|
||||
|
||||
detail::events_operation_register(evt);
|
||||
return evt;
|
||||
}
|
||||
|
||||
//class emit_counter
|
||||
event_base::emit_counter::emit_counter(event_base* evt)
|
||||
: evt_{ evt }
|
||||
{
|
||||
++evt->emitting_count_;
|
||||
}
|
||||
|
||||
event_base::emit_counter::~emit_counter()
|
||||
{
|
||||
if ((0 == --evt_->emitting_count_) && evt_->deleted_flags_)
|
||||
{
|
||||
evt_->deleted_flags_ = false;
|
||||
for (auto i = evt_->dockers_->begin(); i != evt_->dockers_->end();)
|
||||
{
|
||||
if (static_cast<docker_base*>(*i)->flag_deleted)
|
||||
i = evt_->dockers_->erase(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
//end class emit_counter
|
||||
//end class event_base
|
||||
|
||||
}//end namespace detail
|
||||
}//end namespace nana
|
||||
Loading…
x
Reference in New Issue
Block a user