diff --git a/Import/GacUI.UnitTest.h b/Import/GacUI.UnitTest.h index b868db6e..dbc99bc7 100644 --- a/Import/GacUI.UnitTest.h +++ b/Import/GacUI.UnitTest.h @@ -1494,7 +1494,9 @@ UnitTestRemoteProtocol UnitTestRemoteProtocol_IOCommands >::Type; - class UnitTestRemoteProtocol : public UnitTestRemoteProtocolFeatures + class UnitTestRemoteProtocol + : public UnitTestRemoteProtocolFeatures + , protected virtual IGuiRemoteEventProcessor { using EventPair = collections::Pair, Func>; protected: @@ -1551,6 +1553,8 @@ IGuiRemoteProtocol // TODO: Failure injection to disconnected } + protected: + void ProcessRemoteEvents() override { #define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol::ProcessRemoteEvents()#" @@ -1574,6 +1578,13 @@ IGuiRemoteProtocol } #undef ERROR_MESSAGE_PREFIX } + + public: + + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override + { + return this; + } }; } diff --git a/Import/GacUI.cpp b/Import/GacUI.cpp index 9dfc664e..3e4267f5 100644 --- a/Import/GacUI.cpp +++ b/Import/GacUI.cpp @@ -38512,7 +38512,10 @@ GuiRemoteController::INativeWindowService { if (!connectionStopped) { - remoteProtocol->ProcessRemoteEvents(); + if (auto processor = remoteProtocol->GetRemoteEventProcessor()) + { + processor->ProcessRemoteEvents(); + } bool disconnected = false; remoteMessages.Submit(disconnected); if (timerEnabled && !disconnected) @@ -40838,9 +40841,9 @@ GuiRemoteProtocolFromJsonChannel channel->Submit(disconnected); } - void GuiRemoteProtocolFromJsonChannel::ProcessRemoteEvents() + IGuiRemoteEventProcessor* GuiRemoteProtocolFromJsonChannel::GetRemoteEventProcessor() { - channel->ProcessRemoteEvents(); + return channel->GetRemoteEventProcessor(); } /*********************************************************************** @@ -40989,9 +40992,9 @@ GuiRemoteJsonChannelFromProtocol protocol->Submit(disconnected); } - void GuiRemoteJsonChannelFromProtocol::ProcessRemoteEvents() + IGuiRemoteEventProcessor* GuiRemoteJsonChannelFromProtocol::GetRemoteEventProcessor() { - protocol->ProcessRemoteEvents(); + return protocol->GetRemoteEventProcessor(); } /*********************************************************************** @@ -44614,9 +44617,9 @@ namespace vl::presentation::remote_renderer CHECK_FAIL(L"This function should not be called!"); } - void GuiRemoteRendererSingle::ProcessRemoteEvents() + IGuiRemoteEventProcessor* GuiRemoteRendererSingle::GetRemoteEventProcessor() { - CHECK_FAIL(L"This function should not be called!"); + return nullptr; } } diff --git a/Import/GacUI.h b/Import/GacUI.h index 69408863..9c56cd30 100644 --- a/Import/GacUI.h +++ b/Import/GacUI.h @@ -23304,6 +23304,16 @@ IGuiRemoteProtocolConfig virtual WString GetExecutablePath() = 0; }; +/*********************************************************************** +IGuiRemoteEventProcessor +***********************************************************************/ + + class IGuiRemoteEventProcessor : public virtual Interface + { + public: + virtual void ProcessRemoteEvents() = 0; + }; + /*********************************************************************** IGuiRemoteProtocol ***********************************************************************/ @@ -23313,9 +23323,9 @@ IGuiRemoteProtocol , public virtual IGuiRemoteProtocolMessages { public: - virtual void Initialize(IGuiRemoteProtocolEvents* events) = 0; - virtual void Submit(bool& disconnected) = 0; - virtual void ProcessRemoteEvents() = 0; + virtual void Initialize(IGuiRemoteProtocolEvents* events) = 0; + virtual void Submit(bool& disconnected) = 0; + virtual IGuiRemoteEventProcessor* GetRemoteEventProcessor() = 0; }; class GuiRemoteEventCombinator : public Object, public virtual IGuiRemoteProtocolEvents @@ -23359,9 +23369,9 @@ IGuiRemoteProtocol targetProtocol->Submit(disconnected); } - void ProcessRemoteEvents() override + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override { - targetProtocol->ProcessRemoteEvents(); + return targetProtocol->GetRemoteEventProcessor(); } }; @@ -23396,9 +23406,9 @@ IGuiRemoteProtocol targetProtocol->Submit(disconnected); } - void ProcessRemoteEvents() override + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override { - targetProtocol->ProcessRemoteEvents(); + return targetProtocol->GetRemoteEventProcessor(); } }; @@ -23491,7 +23501,7 @@ IGuiRemoteProtocolChannel virtual void Write(const TPackage& package) = 0; virtual WString GetExecutablePath() = 0; virtual void Submit(bool& disconnected) = 0; - virtual void ProcessRemoteEvents() = 0; + virtual IGuiRemoteEventProcessor* GetRemoteEventProcessor() = 0; }; /*********************************************************************** @@ -23535,9 +23545,9 @@ Serialization channel->Submit(disconnected); } - void ProcessRemoteEvents() override + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override { - channel->ProcessRemoteEvents(); + return channel->GetRemoteEventProcessor(); } }; @@ -23719,11 +23729,18 @@ void ChannelPackageSemanticUnpack( ~GuiRemoteProtocolAsyncChannelSerializerBase(); }; +#ifdef _DEBUG +#define ENSURE_THREAD_ID(ID) CHECK_ERROR(ID == Thread::GetCurrentThreadId(), L"Expected to be called in thread: " ## #ID) +#else +#define ENSURE_THREAD_ID(ID) ((void)0) +#endif + template class GuiRemoteProtocolAsyncChannelSerializer : public GuiRemoteProtocolAsyncChannelSerializerBase , public virtual IGuiRemoteProtocolChannel , protected virtual IGuiRemoteProtocolChannelReceiver + , protected virtual IGuiRemoteEventProcessor { static_assert( std::is_same_v requestIds; }; + vint threadIdUI = -1; + vint threadIdChannel = -1; + IGuiRemoteProtocolChannel* channel = nullptr; IGuiRemoteProtocolChannelReceiver* receiver = nullptr; TUIMainProc uiMainProc; @@ -23775,6 +23795,7 @@ void ChannelPackageSemanticUnpack( void UIThreadProc() { + threadIdUI = Thread::GetCurrentThreadId(); uiMainProc(this); uiMainProc = {}; @@ -23800,6 +23821,7 @@ void ChannelPackageSemanticUnpack( // So that the implementation does not need to care about thread safety // The thread stopped after receiving a signal from UIThreadProc + threadIdChannel = Thread::GetCurrentThreadId(); while (!stopping) { eventAutoChannelTaskQueued.Wait(); @@ -23871,6 +23893,7 @@ void ChannelPackageSemanticUnpack( void Write(const TPackage& package) override { // Called from UI thread + ENSURE_THREAD_ID(threadIdUI); uiPendingPackages.Add(package); } @@ -23879,6 +23902,7 @@ void ChannelPackageSemanticUnpack( // Called from UI thread #define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolAsyncChannelSerializer::Submit(...)#" + ENSURE_THREAD_ID(threadIdUI); SPIN_LOCK(lockConnection) { if (!connectionAvailable) @@ -23910,14 +23934,15 @@ void ChannelPackageSemanticUnpack( QueueToChannelThread([this, requestGroup, packages = std::move(uiPendingPackages)]() { + ENSURE_THREAD_ID(threadIdChannel); for (auto&& package : packages) { channel->Write(package); } - bool disconnected = false; + bool disconnected = false; channel->Submit(disconnected); - if (disconnected) - { + if (disconnected) + { SPIN_LOCK(lockConnection) { if (requestGroup->connectionCounter == connectionCounter) @@ -23967,13 +23992,20 @@ void ChannelPackageSemanticUnpack( #undef ERROR_MESSAGE_PREFIX } + protected: + void ProcessRemoteEvents() override { // Called from UI thread - QueueToChannelThread([this]() + ENSURE_THREAD_ID(threadIdUI); + if (channel->GetRemoteEventProcessor()) { - channel->ProcessRemoteEvents(); - }, &eventAutoChannelTaskQueued); + QueueToChannelThread([this]() + { + ENSURE_THREAD_ID(threadIdChannel); + channel->GetRemoteEventProcessor()->ProcessRemoteEvents(); + }, &eventAutoChannelTaskQueued); + } FetchAndExecuteUITasks(); @@ -24003,6 +24035,13 @@ void ChannelPackageSemanticUnpack( } } + public: + + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override + { + return this; + } + public: /// @@ -24091,9 +24130,11 @@ void ChannelPackageSemanticUnpack( void Initialize(IGuiRemoteProtocolChannelReceiver* _receiver) override { // Called from UI thread + ENSURE_THREAD_ID(threadIdUI); receiver = _receiver; QueueToChannelThreadAndWait([this]() { + ENSURE_THREAD_ID(threadIdChannel); channel->Initialize(this); }, &eventAutoChannelTaskQueued); } @@ -24101,16 +24142,19 @@ void ChannelPackageSemanticUnpack( IGuiRemoteProtocolChannelReceiver* GetReceiver() override { // Called from UI thread + ENSURE_THREAD_ID(threadIdUI); return receiver; } WString GetExecutablePath() override { // Called from UI thread + ENSURE_THREAD_ID(threadIdUI); if (!executablePath) { QueueToChannelThreadAndWait([this]() { + ENSURE_THREAD_ID(threadIdChannel); executablePath = channel->GetExecutablePath(); }, &eventAutoChannelTaskQueued); } @@ -24119,6 +24163,8 @@ void ChannelPackageSemanticUnpack( }; } +#undef ENSURE_THREAD_ID + #endif /*********************************************************************** @@ -24211,7 +24257,7 @@ GuiRemoteProtocolFromJsonChannel void Initialize(IGuiRemoteProtocolEvents* _events) override; WString GetExecutablePath() override; void Submit(bool& disconnected) override; - void ProcessRemoteEvents() override; + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override; }; /*********************************************************************** @@ -24274,7 +24320,7 @@ GuiRemoteJsonChannelFromProtocol void Write(const Ptr& package) override; WString GetExecutablePath() override; void Submit(bool& disconnected) override; - void ProcessRemoteEvents() override; + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override; }; /*********************************************************************** @@ -24799,14 +24845,14 @@ namespace vl::presentation::remote_renderer GuiRemoteRendererSingle(); ~GuiRemoteRendererSingle(); - void RegisterMainWindow(INativeWindow* _window); - void UnregisterMainWindow(); - void ForceExitByFatelError(); + void RegisterMainWindow(INativeWindow* _window); + void UnregisterMainWindow(); + void ForceExitByFatelError(); - WString GetExecutablePath() override; - void Initialize(IGuiRemoteProtocolEvents* _events) override; - void Submit(bool& disconnected) override; - void ProcessRemoteEvents() override; + WString GetExecutablePath() override; + void Initialize(IGuiRemoteProtocolEvents* _events) override; + void Submit(bool& disconnected) override; + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override; #define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE) void Request ## NAME() override; diff --git a/Import/Vlpp.cpp b/Import/Vlpp.cpp index d4eca21d..426aab90 100644 --- a/Import/Vlpp.cpp +++ b/Import/Vlpp.cpp @@ -1511,6 +1511,9 @@ UnitTest int UnitTest::RunAndDisposeTests(const collections::Array& options) { +#ifdef VCZH_MSVC + _set_abort_behavior(0, _WRITE_ABORT_MSG); +#endif bool unrecognized = false; bool _D = false; bool _R = false; diff --git a/Import/Vlpp.h b/Import/Vlpp.h index ea0e079e..16b7a370 100644 --- a/Import/Vlpp.h +++ b/Import/Vlpp.h @@ -6075,6 +6075,115 @@ Range-Based For-Loop Iterator with Index { return {}; } + +/*********************************************************************** +Optimized Range-Based For-Loop Iterator for ArrayBase +***********************************************************************/ + + template + struct RangeBasedForLoopIteratorForList + { + protected: + const ArrayBase& arrayBase; + vint index; + + public: + RangeBasedForLoopIteratorForList(const ArrayBase& _arrayBase) + : arrayBase(_arrayBase) + , index(0) + { + } + + void operator++() + { + ++index; + } + + const T& operator*() const + { + return arrayBase.Get(index); + } + + bool operator==(const RangeBasedForLoopEnding&) const + { + return index >= arrayBase.Count(); + } + + bool operator!=(const RangeBasedForLoopEnding&) const + { + return index < arrayBase.Count(); + } + + friend bool operator==(const RangeBasedForLoopEnding&, const RangeBasedForLoopIteratorForList& iterator) + { + return iterator.index >= iterator.arrayBase.Count(); + } + + friend bool operator!=(const RangeBasedForLoopEnding&, const RangeBasedForLoopIteratorForList& iterator) + { + return iterator.index < iterator.arrayBase.Count(); + } + }; + + template + RangeBasedForLoopIteratorForList begin(const ArrayBase& arrayBase) + { + return { arrayBase }; + } + + template + RangeBasedForLoopEnding end(const ArrayBase& arrayBase) + { + return {}; + } + +/*********************************************************************** +Optimized Range-Based For-Loop Iterator for ArrayBase with Index +***********************************************************************/ + + template + struct RangeBasedForLoopIteratorWithIndexForList : public RangeBasedForLoopIteratorForList + { + public: + RangeBasedForLoopIteratorWithIndexForList(const ArrayBase& arrayBase) + : RangeBasedForLoopIteratorForList(arrayBase) + { + } + + Tuple operator*() const + { + return { this->arrayBase.Get(this->index), this->index }; + } + }; + + template + struct ArrayBaseWithIndex + { + const ArrayBase& arrayBase; + + ArrayBaseWithIndex(const ArrayBase& _arrayBase) + : arrayBase(_arrayBase) + { + } + }; + + template + ArrayBaseWithIndex indexed(const ArrayBase& arrayBase) + { + return { arrayBase }; + } + + template + RangeBasedForLoopIteratorWithIndexForList begin(const ArrayBaseWithIndex& wrapper) + { + return { wrapper.arrayBase }; + } + + template + RangeBasedForLoopEnding end(const ArrayBaseWithIndex& wrapper) + { + return {}; + } } } diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 index 0689a045..9144057e 100644 Binary files a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 and b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 differ diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 index 95cd254a..09ac03ec 100644 Binary files a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 and b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 differ