mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-19 04:31:10 +00:00
Compare commits
1 Commits
main
...
dev/lhecke
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ace5a2ffb |
@@ -86,6 +86,177 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
}
|
||||
winrt::event<winrt::Windows::Foundation::TypedEventHandler<SenderT, ArgsT>> _handlers;
|
||||
};
|
||||
|
||||
// Unlike winrt::event, this event will only call handlers once at most.
|
||||
// It's otherwise a copy of winrt::event's implementation.
|
||||
template<typename ArgsT>
|
||||
struct fused_event
|
||||
{
|
||||
using delegate_type = ArgsT;
|
||||
using delegate_array = winrt::com_ptr<winrt::impl::event_array<delegate_type>>;
|
||||
|
||||
fused_event() = default;
|
||||
fused_event(const fused_event&) = delete;
|
||||
fused_event& operator=(const fused_event&) = delete;
|
||||
|
||||
fused_event(fused_event&& other)
|
||||
{
|
||||
const winrt::slim_lock_guard change_guard{ other.m_change };
|
||||
if (!other.m_targets)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const winrt::slim_lock_guard swap_guard{ other.m_swap };
|
||||
m_targets = std::move(other.m_targets);
|
||||
}
|
||||
|
||||
fused_event& operator=(fused_event&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
const winrt::slim_lock_guard other_change_guard{ other.m_change };
|
||||
const winrt::slim_lock_guard other_swap_guard{ other.m_swap };
|
||||
const winrt::slim_lock_guard self_change_guard{ m_change };
|
||||
const winrt::slim_lock_guard self_swap_guard{ m_swap };
|
||||
m_targets = std::move(other.m_targets);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return m_targets != nullptr;
|
||||
}
|
||||
|
||||
winrt::event_token operator()(const delegate_type& delegate)
|
||||
{
|
||||
return add_agile(winrt::impl::make_agile_delegate(delegate));
|
||||
}
|
||||
|
||||
void operator()(const winrt::event_token token)
|
||||
{
|
||||
// Extends life of old targets array to release delegates outside of lock.
|
||||
delegate_array temp_targets;
|
||||
|
||||
{
|
||||
const winrt::slim_lock_guard change_guard{ m_change };
|
||||
|
||||
if (!m_targets)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t available_slots = m_targets->size() - 1;
|
||||
delegate_array new_targets;
|
||||
bool removed = false;
|
||||
|
||||
if (available_slots == 0)
|
||||
{
|
||||
if (get_token(*m_targets->begin()) == token)
|
||||
{
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_targets = winrt::impl::make_event_array<delegate_type>(available_slots);
|
||||
auto new_iterator = new_targets->begin();
|
||||
|
||||
for (delegate_type const& element : *m_targets)
|
||||
{
|
||||
if (!removed && token == get_token(element))
|
||||
{
|
||||
removed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (available_slots == 0)
|
||||
{
|
||||
WINRT_ASSERT(!removed);
|
||||
break;
|
||||
}
|
||||
|
||||
*new_iterator = element;
|
||||
++new_iterator;
|
||||
--available_slots;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed)
|
||||
{
|
||||
const winrt::slim_lock_guard swap_guard{ m_swap };
|
||||
temp_targets = std::exchange(m_targets, std::move(new_targets));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Arg>
|
||||
void raise(const Arg&... args)
|
||||
{
|
||||
delegate_array temp_targets;
|
||||
|
||||
{
|
||||
const winrt::slim_lock_guard change_guard{ m_change };
|
||||
|
||||
if (!m_targets)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const winrt::slim_lock_guard swap_guard{ m_swap };
|
||||
temp_targets = std::move(m_targets);
|
||||
}
|
||||
|
||||
if (temp_targets)
|
||||
{
|
||||
for (const auto& element : *temp_targets)
|
||||
{
|
||||
if (!winrt::impl::invoke(element, args...))
|
||||
{
|
||||
operator()(get_token(element));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
WINRT_IMPL_NOINLINE winrt::event_token add_agile(delegate_type delegate)
|
||||
{
|
||||
winrt::event_token token;
|
||||
|
||||
// Extends life of old targets array to release delegates outside of lock.
|
||||
delegate_array temp_targets;
|
||||
|
||||
{
|
||||
const winrt::slim_lock_guard change_guard{ m_change };
|
||||
const auto size = !m_targets ? 0 : m_targets->size();
|
||||
auto new_targets = winrt::impl::make_event_array<delegate_type>(size + 1);
|
||||
|
||||
if (m_targets)
|
||||
{
|
||||
std::copy_n(m_targets->begin(), m_targets->size(), new_targets->begin());
|
||||
}
|
||||
|
||||
new_targets->back() = std::move(delegate);
|
||||
token = get_token(new_targets->back());
|
||||
|
||||
const winrt::slim_lock_guard swap_guard{ m_swap };
|
||||
temp_targets = std::exchange(m_targets, std::move(new_targets));
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
winrt::event_token get_token(delegate_type const& delegate) const noexcept
|
||||
{
|
||||
return winrt::event_token{ reinterpret_cast<int64_t>(WINRT_IMPL_EncodePointer(winrt::get_abi(delegate))) };
|
||||
}
|
||||
|
||||
delegate_array m_targets;
|
||||
winrt::slim_mutex m_swap;
|
||||
winrt::slim_mutex m_change;
|
||||
};
|
||||
|
||||
#endif
|
||||
#ifdef WINRT_Windows_UI_Xaml_Data_H
|
||||
|
||||
|
||||
Reference in New Issue
Block a user