mgmt: RibEntry equality operators and formatted output
This commit also changes the return type of getRoutes()
from std::list to std::vector, and adds setRoutes(),
hasExpirationPeriod() and unsetExpirationPeriod().
Change-Id: I53f0ea846067c9087fa72273fc131826884ce12f
Refs: #3903
diff --git a/src/mgmt/nfd/rib-entry.cpp b/src/mgmt/nfd/rib-entry.cpp
index ed7fd67..17b53d6 100644
--- a/src/mgmt/nfd/rib-entry.cpp
+++ b/src/mgmt/nfd/rib-entry.cpp
@@ -20,34 +20,24 @@
*/
#include "rib-entry.hpp"
-#include "encoding/tlv-nfd.hpp"
#include "encoding/block-helpers.hpp"
+#include "encoding/encoding-buffer.hpp"
+#include "encoding/tlv-nfd.hpp"
#include "util/concepts.hpp"
+#include <boost/range/adaptor/reversed.hpp>
+
namespace ndn {
namespace nfd {
-//BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Route>));
-BOOST_CONCEPT_ASSERT((WireEncodable<Route>));
-BOOST_CONCEPT_ASSERT((WireDecodable<Route>));
-static_assert(std::is_base_of<tlv::Error, Route::Error>::value,
- "Route::Error must inherit from tlv::Error");
-
-//BOOST_CONCEPT_ASSERT((boost::EqualityComparable<RibEntry>));
-BOOST_CONCEPT_ASSERT((WireEncodable<RibEntry>));
-BOOST_CONCEPT_ASSERT((WireDecodable<RibEntry>));
-static_assert(std::is_base_of<tlv::Error, RibEntry::Error>::value,
- "RibEntry::Error must inherit from tlv::Error");
-
-const time::milliseconds Route::INFINITE_EXPIRATION_PERIOD(time::milliseconds::max());
+BOOST_CONCEPT_ASSERT((StatusDatasetItem<Route>));
+BOOST_CONCEPT_ASSERT((StatusDatasetItem<RibEntry>));
Route::Route()
: m_faceId(INVALID_FACE_ID)
, m_origin(0)
, m_cost(0)
, m_flags(ROUTE_FLAG_CHILD_INHERIT)
- , m_expirationPeriod(INFINITE_EXPIRATION_PERIOD)
- , m_hasInfiniteExpirationPeriod(true)
{
}
@@ -91,8 +81,18 @@
Route&
Route::setExpirationPeriod(time::milliseconds expirationPeriod)
{
+ if (expirationPeriod == time::milliseconds::max())
+ return unsetExpirationPeriod();
+
m_expirationPeriod = expirationPeriod;
- m_hasInfiniteExpirationPeriod = m_expirationPeriod == INFINITE_EXPIRATION_PERIOD;
+ m_wire.reset();
+ return *this;
+}
+
+Route&
+Route::unsetExpirationPeriod()
+{
+ m_expirationPeriod = nullopt;
m_wire.reset();
return *this;
}
@@ -103,10 +103,9 @@
{
size_t totalLength = 0;
- // Absence of an ExpirationPeriod signifies non-expiration
- if (!m_hasInfiniteExpirationPeriod) {
+ if (m_expirationPeriod) {
totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::ExpirationPeriod,
- static_cast<uint64_t>(m_expirationPeriod.count()));
+ static_cast<uint64_t>(m_expirationPeriod->count()));
}
totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Flags, m_flags);
totalLength += prependNonNegativeIntegerBlock(block, ndn::tlv::nfd::Cost, m_cost);
@@ -141,25 +140,13 @@
}
void
-Route::wireDecode(const Block& wire)
+Route::wireDecode(const Block& block)
{
- m_faceId = 0;
- m_origin = 0;
- m_cost = 0;
- m_flags = 0;
- m_expirationPeriod = time::milliseconds::min();
-
- m_wire = wire;
-
- if (m_wire.type() != tlv::nfd::Route) {
- std::stringstream error;
- error << "Expected Route Block, but Block is of a different type: #"
- << m_wire.type();
- BOOST_THROW_EXCEPTION(Error(error.str()));
+ if (block.type() != tlv::nfd::Route) {
+ BOOST_THROW_EXCEPTION(Error("expecting Route, but Block has type " + to_string(block.type())));
}
-
+ m_wire = block;
m_wire.parse();
-
Block::element_const_iterator val = m_wire.elements_begin();
if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) {
@@ -167,7 +154,7 @@
++val;
}
else {
- BOOST_THROW_EXCEPTION(Error("Missing required FaceId field"));
+ BOOST_THROW_EXCEPTION(Error("missing required FaceId field"));
}
if (val != m_wire.elements_end() && val->type() == tlv::nfd::Origin) {
@@ -175,7 +162,7 @@
++val;
}
else {
- BOOST_THROW_EXCEPTION(Error("Missing required Origin field"));
+ BOOST_THROW_EXCEPTION(Error("missing required Origin field"));
}
if (val != m_wire.elements_end() && val->type() == tlv::nfd::Cost) {
@@ -183,7 +170,7 @@
++val;
}
else {
- BOOST_THROW_EXCEPTION(Error("Missing required Cost field"));
+ BOOST_THROW_EXCEPTION(Error("missing required Cost field"));
}
if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) {
@@ -191,38 +178,50 @@
++val;
}
else {
- BOOST_THROW_EXCEPTION(Error("Missing required Flags field"));
+ BOOST_THROW_EXCEPTION(Error("missing required Flags field"));
}
if (val != m_wire.elements_end() && val->type() == tlv::nfd::ExpirationPeriod) {
- m_expirationPeriod = time::milliseconds(readNonNegativeInteger(*val));
- m_hasInfiniteExpirationPeriod = false;
+ m_expirationPeriod.emplace(readNonNegativeInteger(*val));
+ ++val;
}
else {
- m_expirationPeriod = INFINITE_EXPIRATION_PERIOD;
- m_hasInfiniteExpirationPeriod = true;
+ m_expirationPeriod = nullopt;
}
}
+bool
+operator==(const Route& a, const Route& b)
+{
+ return a.getFaceId() == b.getFaceId() &&
+ a.getOrigin() == b.getOrigin() &&
+ a.getCost() == b.getCost() &&
+ a.getFlags() == b.getFlags() &&
+ a.getExpirationPeriod() == b.getExpirationPeriod();
+}
+
std::ostream&
operator<<(std::ostream& os, const Route& route)
{
os << "Route("
<< "FaceId: " << route.getFaceId() << ", "
<< "Origin: " << route.getOrigin() << ", "
- << "Cost: " << route.getCost() << ", "
- << "Flags: " << route.getFlags() << ", ";
+ << "Cost: " << route.getCost() << ", ";
- if (!route.hasInfiniteExpirationPeriod()) {
+ auto osFlags = os.flags();
+ // std::showbase doesn't work with number 0
+ os << "Flags: 0x" << std::noshowbase << std::noshowpos << std::nouppercase
+ << std::hex << route.getFlags() << ", ";
+ os.flags(osFlags);
+
+ if (route.hasExpirationPeriod()) {
os << "ExpirationPeriod: " << route.getExpirationPeriod();
}
else {
- os << "ExpirationPeriod: Infinity";
+ os << "ExpirationPeriod: infinite";
}
- os << ")";
-
- return os;
+ return os << ")";
}
////////////////////
@@ -264,12 +263,9 @@
{
size_t totalLength = 0;
- for (std::list<Route>::const_reverse_iterator it = m_routes.rbegin();
- it != m_routes.rend(); ++it)
- {
- totalLength += it->wireEncode(block);
- }
-
+ for (const auto& route : m_routes | boost::adaptors::reversed) {
+ totalLength += route.wireEncode(block);
+ }
totalLength += m_prefix.wireEncode(block);
totalLength += block.prependVarNumber(totalLength);
@@ -300,59 +296,72 @@
}
void
-RibEntry::wireDecode(const Block& wire)
+RibEntry::wireDecode(const Block& block)
{
- m_prefix.clear();
- m_routes.clear();
-
- m_wire = wire;
-
- if (m_wire.type() != tlv::nfd::RibEntry) {
- std::stringstream error;
- error << "Expected RibEntry Block, but Block is of a different type: #"
- << m_wire.type();
- BOOST_THROW_EXCEPTION(Error(error.str()));
+ if (block.type() != tlv::nfd::RibEntry) {
+ BOOST_THROW_EXCEPTION(Error("expecting RibEntry, but Block has type " + to_string(block.type())));
}
-
+ m_wire = block;
m_wire.parse();
-
Block::element_const_iterator val = m_wire.elements_begin();
- if (val != m_wire.elements_end() && val->type() == tlv::Name) {
- m_prefix.wireDecode(*val);
- ++val;
+ if (val == m_wire.elements_end()) {
+ BOOST_THROW_EXCEPTION(Error("unexpected end of RibEntry"));
}
- else {
- BOOST_THROW_EXCEPTION(Error("Missing required Name field"));
+ else if (val->type() != tlv::Name) {
+ BOOST_THROW_EXCEPTION(Error("expecting Name, but Block has type " + to_string(val->type())));
}
+ m_prefix.wireDecode(*val);
+ ++val;
+ m_routes.clear();
for (; val != m_wire.elements_end(); ++val) {
-
- if (val->type() == tlv::nfd::Route) {
- m_routes.push_back(Route(*val));
+ if (val->type() != tlv::nfd::Route) {
+ BOOST_THROW_EXCEPTION(Error("expecting Route, but Block has type " + to_string(val->type())));
}
- else {
- std::stringstream error;
- error << "Expected Route Block, but Block is of a different type: #"
- << m_wire.type();
- BOOST_THROW_EXCEPTION(Error(error.str()));
- }
+ m_routes.emplace_back(*val);
}
}
+bool
+operator==(const RibEntry& a, const RibEntry& b)
+{
+ const auto& aRoutes = a.getRoutes();
+ const auto& bRoutes = b.getRoutes();
+
+ if (a.getName() != b.getName() ||
+ aRoutes.size() != bRoutes.size())
+ return false;
+
+ std::vector<bool> matched(bRoutes.size(), false);
+ return std::all_of(aRoutes.begin(), aRoutes.end(),
+ [&] (const Route& route) {
+ for (size_t i = 0; i < bRoutes.size(); ++i) {
+ if (!matched[i] && bRoutes[i] == route) {
+ matched[i] = true;
+ return true;
+ }
+ }
+ return false;
+ });
+}
+
std::ostream&
operator<<(std::ostream& os, const RibEntry& entry)
{
- os << "RibEntry{\n"
- << " Name: " << entry.getName() << "\n";
+ os << "RibEntry(Prefix: " << entry.getName() << ",\n"
+ << " Routes: [";
- for (RibEntry::iterator it = entry.begin(); it != entry.end(); ++it) {
- os << " " << *it << "\n";
+ bool isFirst = true;
+ for (const auto& route : entry.getRoutes()) {
+ if (!isFirst)
+ os << ",\n ";
+ isFirst = false;
+ os << route;
}
+ os << "]\n";
- os << "}";
-
- return os;
+ return os << " )";
}
} // namespace nfd
diff --git a/src/mgmt/nfd/rib-entry.hpp b/src/mgmt/nfd/rib-entry.hpp
index b0d7289..0c2071d 100644
--- a/src/mgmt/nfd/rib-entry.hpp
+++ b/src/mgmt/nfd/rib-entry.hpp
@@ -23,30 +23,21 @@
#define NDN_MGMT_NFD_RIB_ENTRY_HPP
#include "rib-flags.hpp"
+#include "../../encoding/block.hpp"
#include "../../name.hpp"
#include "../../util/time.hpp"
-#include <list>
-
namespace ndn {
namespace nfd {
/**
- * @ingroup management
- *
- * @brief Data abstraction for Route
+ * \ingroup management
+ * \brief represents a route in a RibEntry
*
* A route indicates the availability of content via a certain face and
* provides meta-information about the face.
*
- * Route := ROUTE-TYPE TLV-LENGTH
- * FaceId
- * Origin
- * Cost
- * Flags
- * ExpirationPeriod?
- *
- * @sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt
+ * \sa https://redmine.named-data.net/projects/nfd/wiki/RibMgmt#Route
*/
class Route : public RibFlagsTraits<Route>
{
@@ -108,22 +99,23 @@
Route&
setFlags(uint64_t flags);
- static const time::milliseconds INFINITE_EXPIRATION_PERIOD;
+ bool
+ hasExpirationPeriod() const
+ {
+ return !!m_expirationPeriod;
+ }
time::milliseconds
getExpirationPeriod() const
{
- return m_expirationPeriod;
+ return m_expirationPeriod ? *m_expirationPeriod : time::milliseconds::max();
}
Route&
setExpirationPeriod(time::milliseconds expirationPeriod);
- bool
- hasInfiniteExpirationPeriod() const
- {
- return m_hasInfiniteExpirationPeriod;
- }
+ Route&
+ unsetExpirationPeriod();
template<encoding::Tag TAG>
size_t
@@ -133,34 +125,38 @@
wireEncode() const;
void
- wireDecode(const Block& wire);
+ wireDecode(const Block& block);
private:
uint64_t m_faceId;
uint64_t m_origin;
uint64_t m_cost;
uint64_t m_flags;
- time::milliseconds m_expirationPeriod;
- bool m_hasInfiniteExpirationPeriod;
+ optional<time::milliseconds> m_expirationPeriod;
mutable Block m_wire;
};
+bool
+operator==(const Route& a, const Route& b);
+
+inline bool
+operator!=(const Route& a, const Route& b)
+{
+ return !(a == b);
+}
+
std::ostream&
operator<<(std::ostream& os, const Route& route);
+
/**
- * @ingroup management
+ * \ingroup management
+ * \brief represents an item in NFD RIB dataset
*
- * @brief Data abstraction for RIB entry
+ * A RIB entry contains one or more routes for a name prefix
*
- * A RIB entry contains one or more routes for the name prefix
- *
- * RibEntry := RIB-ENTRY-TYPE TLV-LENGTH
- * Name
- * Route+
- *
- * @sa http://redmine.named-data.net/projects/nfd/wiki/RibMgmt
+ * \sa https://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset
*/
class RibEntry
{
@@ -175,9 +171,6 @@
}
};
- typedef std::list<Route> RouteList;
- typedef RouteList::const_iterator iterator;
-
RibEntry();
explicit
@@ -192,12 +185,21 @@
RibEntry&
setName(const Name& prefix);
- const std::list<Route>&
+ const std::vector<Route>&
getRoutes() const
{
return m_routes;
}
+ template<typename InputIt>
+ RibEntry&
+ setRoutes(InputIt first, InputIt last)
+ {
+ m_routes.assign(first, last);
+ m_wire.reset();
+ return *this;
+ }
+
RibEntry&
addRoute(const Route& route);
@@ -212,31 +214,22 @@
wireEncode() const;
void
- wireDecode(const Block& wire);
-
- iterator
- begin() const;
-
- iterator
- end() const;
+ wireDecode(const Block& block);
private:
Name m_prefix;
- RouteList m_routes;
+ std::vector<Route> m_routes;
mutable Block m_wire;
};
-inline RibEntry::iterator
-RibEntry::begin() const
-{
- return m_routes.begin();
-}
+bool
+operator==(const RibEntry& a, const RibEntry& b);
-inline RibEntry::iterator
-RibEntry::end() const
+inline bool
+operator!=(const RibEntry& a, const RibEntry& b)
{
- return m_routes.end();
+ return !(a == b);
}
std::ostream&
diff --git a/src/mgmt/nfd/rib-flags.hpp b/src/mgmt/nfd/rib-flags.hpp
index 158048f..ebc2b9e 100644
--- a/src/mgmt/nfd/rib-flags.hpp
+++ b/src/mgmt/nfd/rib-flags.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2013-2016 Regents of the University of California.
+ * Copyright (c) 2013-2017 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -29,10 +29,10 @@
/**
* \ingroup management
- * \brief implements getters to each RIB flag
+ * \brief defines getters for each route inheritance flag
*
- * \tparam T class containing a RibFlags field and implements
- * `RibFlags getFlags() const` method
+ * \tparam T class containing a RouteFlags field and implementing
+ * a `RouteFlags getFlags() const` member function
*/
template<typename T>
class RibFlagsTraits
@@ -49,6 +49,9 @@
{
return static_cast<const T*>(this)->getFlags() & ROUTE_FLAG_CAPTURE;
}
+
+protected:
+ RibFlagsTraits() = default;
};
} // namespace nfd