#include <ableton/test/serial_io/SchedulerTree.hpp>
#include <algorithm>
namespace ableton
{
namespace test
{
namespace serial_io
{
void SchedulerTree::run()
{
while (handlePending())
{
}
}
std::shared_ptr<SchedulerTree> SchedulerTree::makeChild()
{
auto newChild = std::make_shared<SchedulerTree>();
mChildren.push_back(newChild);
return newChild;
}
void SchedulerTree::cancelTimer(const TimerId timerId)
{
const auto it = std::find_if(begin(mTimers),
end(mTimers),
[timerId](const TimerMap::value_type& timer)
{ return timer.first.second == timerId; });
if (it != end(mTimers))
{
auto handler = std::move(it->second);
mPendingHandlers.emplace_back(
[handler]()
{
handler(1); });
mTimers.erase(it);
}
}
SchedulerTree::TimePoint SchedulerTree::nextTimerExpiration()
{
auto nextTimePoint = TimePoint::max();
withChildren(
[&nextTimePoint](SchedulerTree& child)
{ nextTimePoint = (std::min)(nextTimePoint, child.nextOwnTimerExpiration()); });
return (std::min)(nextTimePoint, nextOwnTimerExpiration());
}
void SchedulerTree::triggerTimersUntil(const TimePoint t)
{
using namespace std;
withChildren([t](SchedulerTree& child) { child.triggerTimersUntil(t); });
const auto it = mTimers.upper_bound(make_pair(t, numeric_limits<TimerId>::max()));
for_each(begin(mTimers),
it,
[this](const TimerMap::value_type& timer)
{
mPendingHandlers.emplace_back(
[timer]()
{
timer.second(0); });
});
mTimers.erase(begin(mTimers), it);
}
bool SchedulerTree::handlePending()
{
bool subtreeWorked = false;
withChildren([&subtreeWorked](SchedulerTree& child)
{ subtreeWorked |= child.handlePending(); });
if (mPendingHandlers.empty())
{
return subtreeWorked;
}
else
{
mPendingHandlers.front()();
mPendingHandlers.pop_front();
return true;
}
}
SchedulerTree::TimePoint SchedulerTree::nextOwnTimerExpiration()
{
return mTimers.empty() ? TimePoint::max() : begin(mTimers)->first.first;
}
} } }