From f5eb38410d96b2a740fc9aa13f637b5ce9ca26ae Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 26 Dec 2024 14:52:19 +0100 Subject: [PATCH] Allow using move-only types with wxMessageQueue Add Post() overload taking r-value reference and a unit test showing that we can use it with a non-copyable type. --- include/wx/msgqueue.h | 21 +++++++++++++++++++-- interface/wx/msgqueue.h | 10 ++++++++++ tests/thread/queue.cpp | 24 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/include/wx/msgqueue.h b/include/wx/msgqueue.h index 8b8da87d18..570985d717 100644 --- a/include/wx/msgqueue.h +++ b/include/wx/msgqueue.h @@ -22,6 +22,7 @@ #include "wx/beforestd.h" #include +#include #include "wx/afterstd.h" enum wxMessageQueueError @@ -58,6 +59,8 @@ public: // Add a message to this queue and signal the threads waiting for messages. // // This method is safe to call from multiple threads in parallel. + // + // This overload relies on Message being copyable. wxMessageQueueError Post(const Message& msg) { wxMutexLocker locker(m_mutex); @@ -71,6 +74,20 @@ public: return wxMSGQUEUE_NO_ERROR; } + // Overload for move-only types. + wxMessageQueueError Post(Message&& msg) + { + wxMutexLocker locker(m_mutex); + + wxCHECK( locker.IsOk(), wxMSGQUEUE_MISC_ERROR ); + + m_messages.push(std::move(msg)); + + m_conditionNotEmpty.Signal(); + + return wxMSGQUEUE_NO_ERROR; + } + // Remove all messages from the queue. // // This method is meant to be called from the same thread(s) that call @@ -117,7 +134,7 @@ public: wxASSERT(timeout > 0); } - msg = m_messages.front(); + msg = std::move(m_messages.front()); m_messages.pop(); return wxMSGQUEUE_NO_ERROR; @@ -140,7 +157,7 @@ public: wxCHECK( result == wxCOND_NO_ERROR, wxMSGQUEUE_MISC_ERROR ); } - msg = m_messages.front(); + msg = std::move(m_messages.front()); m_messages.pop(); return wxMSGQUEUE_NO_ERROR; diff --git a/interface/wx/msgqueue.h b/interface/wx/msgqueue.h index 8caf29c7e8..4a152818f8 100644 --- a/interface/wx/msgqueue.h +++ b/interface/wx/msgqueue.h @@ -86,6 +86,16 @@ public: */ wxMessageQueueError Post(T const& msg); + /** + Post a message of move-only type. + + This function has the same semantics as the other overload but can be + used for non-copyable (but movable) types. + + @since 3.3.0 + */ + wxMessageQueueError Post(T&& msg); + /** Block until a message becomes available in the queue. Waits indefinitely long or until an error occurs. diff --git a/tests/thread/queue.cpp b/tests/thread/queue.cpp index 780ce59797..0f8a2972e6 100644 --- a/tests/thread/queue.cpp +++ b/tests/thread/queue.cpp @@ -191,3 +191,27 @@ void *MyThread::Entry() return (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR; } + +TEST_CASE("wxMessageQueue::NonCopyable", "[msgqueue]") +{ + struct NonCopyable + { + explicit NonCopyable(int n) : m_n(new int(n)) { } + + NonCopyable(NonCopyable&& other) = default; + NonCopyable& operator=(NonCopyable&& other) = default; + + std::unique_ptr m_n; + }; + + wxMessageQueue queue; + + NonCopyable nc(17); + CHECK( queue.Post(std::move(nc)) == wxMSGQUEUE_NO_ERROR ); + + NonCopyable nc2(0); + CHECK( queue.Receive(nc2) == wxMSGQUEUE_NO_ERROR ); + CHECK( *nc2.m_n == 17 ); + + CHECK( queue.ReceiveTimeout(0, nc2) == wxMSGQUEUE_TIMEOUT ); +}