From 26a6bbc514cd776bc748239563f35fbfbcbcb7f2 Mon Sep 17 00:00:00 2001 From: schlenkibus Date: Sun, 23 Feb 2025 00:31:05 +0100 Subject: [PATCH] replaces vector with priority queue for pending deferrables. --- include/reactive/Deferrer.h | 16 ++++++++++++++-- src/ComputationsImpl.cpp | 25 ++++++++++++++++++------ src/Deferrer.cpp | 28 +++++++-------------------- tests/ReactiveTests.cpp | 38 ++++++++++++++++++++++++++++++++++--- 4 files changed, 75 insertions(+), 32 deletions(-) diff --git a/include/reactive/Deferrer.h b/include/reactive/Deferrer.h index 70dc5f4..c25f2c0 100644 --- a/include/reactive/Deferrer.h +++ b/include/reactive/Deferrer.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace Reactive @@ -13,10 +14,21 @@ namespace Reactive Deferrer(); ~Deferrer(); - static void add(std::shared_ptr pending); + static void add(const std::shared_ptr& pending); private: - std::vector> m_pending; + using tDepth = int; + using tPendingEntry = std::pair>; + + struct Comperator + { + bool operator()(const tPendingEntry& lhs, const tPendingEntry& rhs) const + { + return lhs.first > rhs.first; + } + }; + + std::priority_queue, Comperator> m_pending; friend struct DeferrerTester; }; diff --git a/src/ComputationsImpl.cpp b/src/ComputationsImpl.cpp index aff43af..c45fa26 100644 --- a/src/ComputationsImpl.cpp +++ b/src/ComputationsImpl.cpp @@ -50,11 +50,24 @@ namespace Reactive Computation *ComputationsImpl::getLowest(Computation *lowestSoFar) const { - for(auto it = m_pending.begin(); it != m_pending.end(); it++) - if(!lowestSoFar) - lowestSoFar = it->get(); - else if((*it)->getDepth() < lowestSoFar->getDepth()) - lowestSoFar = it->get(); - return lowestSoFar; + if(m_pending.empty()) + { + return lowestSoFar; + } + + if(!lowestSoFar) + { + return m_pending.front().get(); + } + + Computation *lowest = m_pending.front().get(); + for(const auto &comp : m_pending) + { + if(comp->getDepth() < lowest->getDepth()) + { + lowest = comp.get(); + } + } + return lowest; } } diff --git a/src/Deferrer.cpp b/src/Deferrer.cpp index 7383c3d..2dace33 100644 --- a/src/Deferrer.cpp +++ b/src/Deferrer.cpp @@ -22,38 +22,24 @@ namespace Reactive if(tl_deferrer == this) { tl_deferrer = nullptr; - - auto cp = std::move(m_pending); - - - while(true) + while(!m_pending.empty()) { - std::pair lowestDepth = { nullptr, nullptr }; + auto [depth, weak_ptr] = m_pending.top(); + m_pending.pop(); - for(auto &w : cp) + if(const auto s = weak_ptr.lock()) { - if(auto s = w.lock()) - { - auto newLowestDepth = s->getLowest(lowestDepth.second); - - if(newLowestDepth != lowestDepth.second) - lowestDepth = {s.get(), newLowestDepth}; - } + s->doDeferred(s->getLowest(nullptr)); } - - if(lowestDepth.first && lowestDepth.second) - lowestDepth.first->doDeferred(lowestDepth.second); - else - break; } } } - void Deferrer::add(std::shared_ptr pending) + void Deferrer::add(const std::shared_ptr &pending) { if(!tl_deferrer) pending->doDeferred(pending->getLowest(nullptr)); else - tl_deferrer->m_pending.push_back(pending); + tl_deferrer->m_pending.push(tPendingEntry { pending->getLowest(nullptr)->getDepth(), pending }); } } \ No newline at end of file diff --git a/tests/ReactiveTests.cpp b/tests/ReactiveTests.cpp index 0c79b25..5a89a42 100644 --- a/tests/ReactiveTests.cpp +++ b/tests/ReactiveTests.cpp @@ -6,16 +6,48 @@ using namespace Reactive; +namespace std +{ + template <> struct hash> + { + size_t operator()(const std::weak_ptr &w) const noexcept + { + return std::hash()(w.lock().get()); + } + }; + +} + namespace Reactive { struct DeferrerTester { static bool areElementsInPendingUnique(Deferrer &p) { - for(auto &c : p.m_pending) - if(std::count_if(p.m_pending.begin(), p.m_pending.end(), [&](auto &a) { return a.lock() == c.lock(); }) > 1) - return false; + using tWeak = std::weak_ptr; + + struct Equal + { + bool operator()(const tWeak &a, const tWeak &b) const + { + return a.lock().get() == b.lock().get(); + } + }; + + std::unordered_set, Equal> seen {}; + + auto tempQueue = p.m_pending; + while(!tempQueue.empty()) + { + auto w = tempQueue.top().second; + tempQueue.pop(); + if(seen.contains(w)) + { + return false; + } + seen.insert(w); + } return true; } };