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

Change-Id: I82fdd94582a731c2238c6645e9ace21a2cacf2de
diff --git a/src/util/scheduler.cpp b/src/util/scheduler.cpp
index c2f5564..09a3f26 100644
--- a/src/util/scheduler.cpp
+++ b/src/util/scheduler.cpp
@@ -23,47 +23,28 @@
 
 #include "scheduler.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 {
 
-struct EventIdImpl
-{
-  EventIdImpl(const Scheduler::EventQueue::iterator& event)
-    : m_event(event)
-    , m_isValid(true)
-  {
-  }
-
-  void
-  invalidate()
-  {
-    m_isValid = false;
-  }
-
-  bool
-  isValid() const
-  {
-    return m_isValid;
-  }
-
-  operator const Scheduler::EventQueue::iterator&() const
-  {
-    return m_event;
-  }
-
-  void
-  reset(const Scheduler::EventQueue::iterator& newIterator)
-  {
-    m_event = newIterator;
-    m_isValid = true;
-  }
-
-private:
-  Scheduler::EventQueue::iterator m_event;
-  bool m_isValid;
-};
-
 Scheduler::EventInfo::EventInfo(const time::nanoseconds& after,
                                 const Event& event)
   : m_scheduledTime(time::steady_clock::now() + after)
@@ -92,111 +73,57 @@
 
 Scheduler::Scheduler(boost::asio::io_service& ioService)
   : m_scheduledEvent(m_events.end())
-  , m_deadlineTimer(ioService)
-  , m_isEventExecuting(false)
 {
 }
 
-EventId
-Scheduler::scheduleEvent(const time::nanoseconds& after,
-                         const Event& event)
+Scheduler::~Scheduler()
 {
-  EventQueue::iterator i = m_events.insert(EventInfo(after, event));
+  cancelAllEvents();
+}
 
-  // On OSX 10.9, boost, and C++03 the following doesn't work without ndn::
-  // because the argument-dependent lookup prefers STL to boost
-  i->m_eventId = ndn::make_shared<EventIdImpl>(i);
-
-  if (!m_isEventExecuting)
-    {
-      if (m_scheduledEvent == m_events.end() ||
-          *i < *m_scheduledEvent)
-        {
-          m_deadlineTimer.expires_from_now(after);
-          m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
-          m_scheduledEvent = i;
-        }
+EventId
+Scheduler::scheduleEvent(const time::nanoseconds& after, const Event& event)
+{
+  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
     }
+  };
 
-  return i->m_eventId;
+  ns3::EventId id = ns3::Simulator::Schedule(ns3::NanoSeconds(after.count()),
+                                             &std::function<void()>::operator(), eventWithCleanup);
+  *eventId = std::move(id);
+  m_events.insert(eventId);
+
+  return eventId;
 }
 
 void
 Scheduler::cancelEvent(const EventId& eventId)
 {
-  if (!static_cast<bool>(eventId) || !eventId->isValid())
-    return; // event already fired or cancelled
-
-  if (static_cast<EventQueue::iterator>(*eventId) != m_scheduledEvent) {
-    m_events.erase(*eventId);
-    eventId->invalidate();
-    return;
+  if (eventId != nullptr) {
+    ns3::Simulator::Remove(*eventId);
+    const_cast<EventId&>(eventId).reset();
+    m_events.erase(eventId);
   }
-
-  m_deadlineTimer.cancel();
-  m_events.erase(static_cast<EventQueue::iterator>(*eventId));
-  eventId->invalidate();
-
-  if (!m_isEventExecuting)
-    {
-      if (!m_events.empty())
-        {
-          m_deadlineTimer.expires_from_now(m_events.begin()->expiresFromNow());
-          m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
-          m_scheduledEvent = m_events.begin();
-        }
-      else
-        {
-          m_scheduledEvent = m_events.end();
-        }
-    }
 }
 
 void
 Scheduler::cancelAllEvents()
 {
+  for (auto i = m_events.begin(); i != m_events.end(); i++) {
+    if ((*i) != nullptr) {
+      ns3::Simulator::Remove((**i));
+      const_cast<EventId&>(*i).reset();
+    }
+  }
   m_events.clear();
-  m_deadlineTimer.cancel();
 }
 
-void
-Scheduler::onEvent(const boost::system::error_code& error)
-{
-  if (error) // e.g., cancelled
-    {
-      return;
-    }
-
-  m_isEventExecuting = true;
-
-  // process all expired events
-  time::steady_clock::TimePoint now = time::steady_clock::now();
-  while(!m_events.empty() && m_events.begin()->m_scheduledTime <= now)
-    {
-      EventQueue::iterator head = m_events.begin();
-
-      Event event = head->m_event;
-      head->m_eventId->invalidate();
-      m_events.erase(head);
-
-      event();
-    }
-
-  if (!m_events.empty())
-    {
-      m_deadlineTimer.expires_from_now(m_events.begin()->m_scheduledTime - now);
-      m_deadlineTimer.async_wait(bind(&Scheduler::onEvent, this, _1));
-      m_scheduledEvent = m_events.begin();
-    }
-  else
-    {
-      m_scheduledEvent = m_events.end();
-    }
-
-  m_isEventExecuting = false;
-}
-
-
 } // namespace scheduler
 } // namespace util
 } // namespace ndn