rib: simplify Route class

Route::expires is changed to an optional, with nullopt representing
"never expires". This avoids an integer overflow.

RouteFlags accessors are now provided by ndn::nfd::RouteFlagsTraits.

Stream insertion operator is improved.

refs #3502

Change-Id: Ia912eab771fb00020385bf84d486955feae6aafa
diff --git a/rib/fib-updater.cpp b/rib/fib-updater.cpp
index a430c68..bce3a5d 100644
--- a/rib/fib-updater.cpp
+++ b/rib/fib-updater.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2016,  Regents of the University of California,
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -71,9 +71,8 @@
   NFD_LOG_DEBUG("Computing updates for batch with faceID: " << batch.getFaceId());
 
   // Compute updates and add to m_fibUpdates
-  for (const RibUpdate& update : batch)
-    {
-      switch(update.getAction()) {
+  for (const RibUpdate& update : batch) {
+    switch (update.getAction()) {
       case RibUpdate::REGISTER:
         computeUpdatesForRegistration(update);
         break;
@@ -87,8 +86,8 @@
         // since they will be rejected by the FIB
         m_updatesForBatchFaceId.clear();
         break;
-      }
     }
+  }
 }
 
 void
@@ -108,7 +107,7 @@
     // Route will be new
     if (existingRoute == entry->end()) {
       // Will the new route change the namespace's capture flag?
-      bool willCaptureBeTurnedOn = (entry->hasCapture() == false && route.isCapture());
+      bool willCaptureBeTurnedOn = (entry->hasCapture() == false && route.isRibCapture());
 
       createFibUpdatesForNewRoute(*entry, route, willCaptureBeTurnedOn);
     }
@@ -383,11 +382,11 @@
   addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
 
   // No flags are set
-  if (!route.isChildInherit() && !route.isCapture()) {
+  if (!route.isChildInherit() && !route.isRibCapture()) {
     // Add ancestor routes to self
     addInheritedRoutes(name, m_rib.getAncestorRoutes(name), route);
   }
-  else if (route.isChildInherit() && route.isCapture()) {
+  else if (route.isChildInherit() && route.isRibCapture()) {
     // Add route to children
     Rib::RouteSet routesToAdd;
     routesToAdd.insert(route);
@@ -416,7 +415,7 @@
     // Add ancestor routes to children
     modifyChildrensInheritedRoutes(children, ancestorRoutes, Rib::RouteSet());
   }
-  else if (route.isCapture()) {
+  else if (route.isRibCapture()) {
     // Remove routes blocked by capture
     modifyChildrensInheritedRoutes(children, Rib::RouteSet(), m_rib.getAncestorRoutes(name));
   }
@@ -540,7 +539,7 @@
   }
 
   // Capture was turned on
-  if (!existingRoute.isCapture() && route.isCapture()) {
+  if (!existingRoute.isRibCapture() && route.isRibCapture()) {
     Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
 
     // Remove ancestor routes from self
@@ -549,7 +548,7 @@
     // Remove ancestor routes from children
     modifyChildrensInheritedRoutes(entry.getChildren(), Rib::RouteSet(), ancestorRoutes);
   }  // Capture was turned off
-  else if (existingRoute.isCapture() && !route.isCapture()) {
+  else if (existingRoute.isRibCapture() && !route.isRibCapture()) {
     Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
 
     // Add ancestor routes to self
@@ -566,7 +565,7 @@
 {
   addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
 
-  if (route.isChildInherit() && route.isCapture()) {
+  if (route.isChildInherit() && route.isRibCapture()) {
     // Remove self from children
     Rib::RouteSet routesToRemove;
     routesToRemove.insert(route);
@@ -597,7 +596,7 @@
     // Add ancestor routes to children
     modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
   }
-  else if (route.isCapture()) {
+  else if (route.isRibCapture()) {
     // If capture is turned off for the route and another route is installed in the RibEntry,
     // add ancestors to self
     Rib::RouteSet routesToAdd;
diff --git a/rib/rib-entry.cpp b/rib/rib-entry.cpp
index a33e113..e26e6d6 100644
--- a/rib/rib-entry.cpp
+++ b/rib/rib-entry.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2016,  Regents of the University of California,
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -249,10 +249,10 @@
 operator<<(std::ostream& os, const RibEntry& entry)
 {
   os << "RibEntry {\n";
-  os << "\tName: " << entry.getName() << "\n";
+  os << "  Name: " << entry.getName() << "\n";
 
   for (const Route& route : entry) {
-    os << "\t" << route << "\n";
+    os << "  " << route << "\n";
   }
 
   os << "}";
diff --git a/rib/rib-manager.cpp b/rib/rib-manager.cpp
index 46819bd..71a7cf3 100644
--- a/rib/rib-manager.cpp
+++ b/rib/rib-manager.cpp
@@ -33,13 +33,11 @@
 
 #include <ndn-cxx/lp/tags.hpp>
 #include <ndn-cxx/mgmt/nfd/control-command.hpp>
-#include <ndn-cxx/mgmt/nfd/control-response.hpp>
 #include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
+#include <ndn-cxx/mgmt/nfd/control-response.hpp>
 #include <ndn-cxx/mgmt/nfd/face-status.hpp>
 #include <ndn-cxx/mgmt/nfd/rib-entry.hpp>
 
-#include <boost/range/adaptor/transformed.hpp>
-
 namespace nfd {
 namespace rib {
 
@@ -219,14 +217,14 @@
     scheduler::EventId eventId = scheduler::schedule(parameters.getExpirationPeriod(),
       bind(&Rib::onRouteExpiration, &m_rib, parameters.getName(), route));
 
-    NFD_LOG_TRACE("Scheduled unregistration at: " << route.expires <<
+    NFD_LOG_TRACE("Scheduled unregistration at: " << *route.expires <<
                   " with EventId: " << eventId);
 
     // Set the  NewEventId of this entry
     route.setExpirationEvent(eventId);
   }
   else {
-    route.expires = time::steady_clock::TimePoint::max();
+    route.expires = ndn::nullopt;
   }
 
   NFD_LOG_INFO("Adding route " << parameters.getName() << " nexthop=" << route.faceId
@@ -276,25 +274,23 @@
 RibManager::listEntries(const Name& topPrefix, const Interest& interest,
                         ndn::mgmt::StatusDatasetContext& context)
 {
-  for (const auto& ribTableEntry : m_rib) {
-    const auto& ribEntry = *ribTableEntry.second;
-    const auto& routes = ribEntry.getRoutes() |
-                         boost::adaptors::transformed([] (const Route& route) {
-                           auto r = ndn::nfd::Route()
-                                    .setFaceId(route.faceId)
-                                    .setOrigin(route.origin)
-                                    .setCost(route.cost)
-                                    .setFlags(route.flags);
-                           if (route.expires < time::steady_clock::TimePoint::max()) {
-                             r.setExpirationPeriod(time::duration_cast<time::milliseconds>(
-                                                     route.expires - time::steady_clock::now()));
-                           }
-                           return r;
-                         });
-    context.append(ndn::nfd::RibEntry()
-                   .setName(ribEntry.getName())
-                   .setRoutes(std::begin(routes), std::end(routes))
-                   .wireEncode());
+  auto now = time::steady_clock::now();
+  for (const auto& kv : m_rib) {
+    const RibEntry& entry = *kv.second;
+    ndn::nfd::RibEntry item;
+    item.setName(entry.getName());
+    for (const Route& route : entry.getRoutes()) {
+      ndn::nfd::Route r;
+      r.setFaceId(route.faceId);
+      r.setOrigin(route.origin);
+      r.setCost(route.cost);
+      r.setFlags(route.flags);
+      if (route.expires) {
+        r.setExpirationPeriod(time::duration_cast<time::milliseconds>(*route.expires - now));
+      }
+      item.addRoute(r);
+    }
+    context.append(item.wireEncode());
   }
   context.end();
 }
@@ -409,7 +405,7 @@
   Route route;
   route.faceId = result.getFaceId();
   route.origin = ndn::nfd::ROUTE_ORIGIN_APP;
-  route.expires = time::steady_clock::TimePoint::max();
+  route.expires = ndn::nullopt;
   route.flags = ndn::nfd::ROUTE_FLAG_CHILD_INHERIT;
 
   m_rib.insert(prefix, route);
diff --git a/rib/route.cpp b/rib/route.cpp
index 7ee9353..08e469b 100644
--- a/rib/route.cpp
+++ b/rib/route.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,18 +24,27 @@
  */
 
 #include "route.hpp"
+#include <ndn-cxx/util/string-helper.hpp>
 
 namespace nfd {
 namespace rib {
 
-bool
-Route::operator==(const Route& other) const
+Route::Route()
+  : faceId(0)
+  , origin(ndn::nfd::ROUTE_ORIGIN_APP)
+  , cost(0)
+  , flags(ndn::nfd::ROUTE_FLAGS_NONE)
 {
-  return (this->faceId == other.faceId &&
-          this->origin == other.origin &&
-          this->flags == other.flags &&
-          this->cost == other.cost &&
-          this->expires == other.expires);
+}
+
+bool
+operator==(const Route& lhs, const Route& rhs)
+{
+  return lhs.faceId == rhs.faceId &&
+         lhs.origin == rhs.origin &&
+         lhs.flags == rhs.flags &&
+         lhs.cost == rhs.cost &&
+         lhs.expires == rhs.expires;
 }
 
 std::ostream&
@@ -45,9 +54,9 @@
      << "faceid: " << route.faceId
      << ", origin: " << route.origin
      << ", cost: " << route.cost
-     << ", flags: " << route.flags;
-  if (route.expires != time::steady_clock::TimePoint::max()) {
-    os << ", expires in: " << (route.expires - time::steady_clock::now());
+     << ", flags: " << ndn::AsHex{route.flags};
+  if (route.expires) {
+    os << ", expires in: " << time::duration_cast<time::milliseconds>(*route.expires - time::steady_clock::now());
   }
   else {
     os << ", never expires";
diff --git a/rib/route.hpp b/rib/route.hpp
index f739741..2dfeabb 100644
--- a/rib/route.hpp
+++ b/rib/route.hpp
@@ -27,30 +27,20 @@
 #define NFD_RIB_ROUTE_HPP
 
 #include "core/scheduler.hpp"
-
 #include <ndn-cxx/encoding/nfd-constants.hpp>
+#include <ndn-cxx/mgmt/nfd/route-flags-traits.hpp>
+#include <type_traits>
 
 namespace nfd {
 namespace rib {
 
 /** \brief represents a route for a name prefix
  */
-class Route
+class Route : public ndn::nfd::RouteFlagsTraits<Route>
 {
 public:
-  Route()
-    : faceId(0)
-    , origin(ndn::nfd::ROUTE_ORIGIN_APP)
-    , flags(0)
-    , cost(0)
-    , expires(time::steady_clock::TimePoint::min())
-  {
-  }
+  Route();
 
-  bool
-  operator==(const Route& other) const;
-
-public:
   void
   setExpirationEvent(const scheduler::EventId eid)
   {
@@ -63,29 +53,32 @@
     return m_expirationEvent;
   }
 
-  bool
-  isChildInherit() const
+  std::underlying_type<ndn::nfd::RouteFlags>::type
+  getFlags() const
   {
-    return flags & ndn::nfd::ROUTE_FLAG_CHILD_INHERIT;
-  }
-
-  bool
-  isCapture() const
-  {
-    return flags & ndn::nfd::ROUTE_FLAG_CAPTURE;
+    return flags;
   }
 
 public:
   uint64_t faceId;
   ndn::nfd::RouteOrigin origin;
-  uint64_t flags;
   uint64_t cost;
-  time::steady_clock::TimePoint expires;
+  std::underlying_type<ndn::nfd::RouteFlags>::type flags;
+  ndn::optional<time::steady_clock::TimePoint> expires;
 
 private:
   scheduler::EventId m_expirationEvent;
 };
 
+bool
+operator==(const Route& lhs, const Route& rhs);
+
+inline bool
+operator!=(const Route& lhs, const Route& rhs)
+{
+  return !(lhs == rhs);
+}
+
 inline bool
 compareFaceIdAndOrigin(const Route& lhs, const Route& rhs)
 {