[ndnSIM] util: Redirecting the scheduler of ndn-cxx to the scheduler of NS3

Change-Id: I82fdd94582a731c2238c6645e9ace21a2cacf2de
Refs: #4509
diff --git a/src/util/scheduler.cpp b/src/util/scheduler.cpp
index 167b6e0..513348f 100644
--- a/src/util/scheduler.cpp
+++ b/src/util/scheduler.cpp
@@ -24,142 +24,82 @@
 
 #include <boost/scope_exit.hpp>
 
+namespace ns3 {
+
+/// @cond include_hidden
+
+template<>
+struct EventMemberImplObjTraits<std::function<void()>> {
+  typedef std::function<void()> T;
+  static T&
+  GetReference(T& p)
+  {
+    return p;
+  }
+};
+
+/// @endcond
+
+} // namespace ns3
+
 namespace ndn {
 namespace util {
 namespace scheduler {
 
-class EventInfo : noncopyable
-{
-public:
-  EventInfo(time::nanoseconds after, const EventCallback& callback)
-    : expireTime(time::steady_clock::now() + after)
-    , isExpired(false)
-    , callback(callback)
-  {
-  }
-
-  time::nanoseconds
-  expiresFromNow() const
-  {
-    return std::max(expireTime - time::steady_clock::now(), time::nanoseconds::zero());
-  }
-
-public:
-  time::steady_clock::TimePoint expireTime;
-  bool isExpired;
-  EventCallback callback;
-  EventQueue::const_iterator queueIt;
-};
-
-EventId::operator bool() const
-{
-  return !m_info.expired() && !m_info.lock()->isExpired;
-}
-
-bool
-EventId::operator==(const EventId& other) const
-{
-  return (!(*this) && !other) ||
-         !(m_info.owner_before(other.m_info) || other.m_info.owner_before(m_info));
-}
-
-std::ostream&
-operator<<(std::ostream& os, const EventId& eventId)
-{
-  return os << eventId.m_info.lock();
-}
-
-bool
-EventQueueCompare::operator()(const shared_ptr<EventInfo>& a, const shared_ptr<EventInfo>& b) const
-{
-  return a->expireTime < b->expireTime;
-}
-
 Scheduler::Scheduler(boost::asio::io_service& ioService)
-  : m_timer(make_unique<detail::SteadyTimer>(ioService))
-  , m_isEventExecuting(false)
+  : m_scheduledEvent(m_events.end())
 {
 }
 
-Scheduler::~Scheduler() = default;
+Scheduler::~Scheduler()
+{
+  cancelAllEvents();
+}
 
 EventId
-Scheduler::scheduleEvent(time::nanoseconds after, const EventCallback& callback)
+Scheduler::scheduleEvent(const time::nanoseconds& after, const Event& event)
 {
-  BOOST_ASSERT(callback != nullptr);
+  EventId eventId = std::make_shared<ns3::EventId>();
+  weak_ptr<ns3::EventId> eventWeak = eventId;
+  std::function<void()> eventWithCleanup = [this, event, eventWeak] () {
+    event();
+    shared_ptr<ns3::EventId> eventId = eventWeak.lock();
+    if (eventId != nullptr) {
+      this->m_events.erase(eventId); // remove the event from the set after it is executed
+    }
+  };
 
-  EventQueue::iterator i = m_queue.insert(make_shared<EventInfo>(after, callback));
-  (*i)->queueIt = i;
+  ns3::EventId id = ns3::Simulator::Schedule(ns3::NanoSeconds(after.count()),
+                                             &std::function<void()>::operator(), eventWithCleanup);
+  *eventId = std::move(id);
+  m_events.insert(eventId);
 
-  if (!m_isEventExecuting && i == m_queue.begin()) {
-    // the new event is the first one to expire
-    this->scheduleNext();
-  }
-
-  return EventId(*i);
+  return eventId;
 }
 
 void
 Scheduler::cancelEvent(const EventId& eventId)
 {
-  shared_ptr<EventInfo> info = eventId.m_info.lock();
-  if (info == nullptr || info->isExpired) {
-    return; // event already expired or cancelled
-  }
-
-  if (info->queueIt == m_queue.begin()) {
-    m_timer->cancel();
-  }
-  m_queue.erase(info->queueIt);
-
-  if (!m_isEventExecuting) {
-    this->scheduleNext();
+  if (eventId != nullptr) {
+    ns3::Simulator::Remove(*eventId);
+    m_events.erase(eventId);
+    const_cast<EventId&>(eventId).reset();
   }
 }
 
 void
 Scheduler::cancelAllEvents()
 {
-  m_queue.clear();
-  m_timer->cancel();
-}
-
-void
-Scheduler::scheduleNext()
-{
-  if (!m_queue.empty()) {
-    m_timer->expires_from_now((*m_queue.begin())->expiresFromNow());
-    m_timer->async_wait(bind(&Scheduler::executeEvent, this, _1));
-  }
-}
-
-void
-Scheduler::executeEvent(const boost::system::error_code& error)
-{
-  if (error) { // e.g., cancelled
-    return;
-  }
-
-  m_isEventExecuting = true;
-
-  BOOST_SCOPE_EXIT(this_) {
-    this_->m_isEventExecuting = false;
-    this_->scheduleNext();
-  } BOOST_SCOPE_EXIT_END
-
-  // process all expired events
-  auto now = time::steady_clock::now();
-  while (!m_queue.empty()) {
-    auto head = m_queue.begin();
-    shared_ptr<EventInfo> info = *head;
-    if (info->expireTime > now) {
-      break;
+  for (auto i = m_events.begin(); i != m_events.end(); ) {
+    auto next = i;
+    ++next; // ns3::Simulator::Remove can call cancelEvent
+    if ((*i) != nullptr) {
+      ns3::Simulator::Remove((**i));
+      const_cast<EventId&>(*i).reset();
     }
-
-    m_queue.erase(head);
-    info->isExpired = true;
-    info->callback();
+    i = next;
   }
+  m_events.clear();
 }
 
 } // namespace scheduler