lsa: cleanup operator<<

Delete .toString() virtual function in favor of ostream output.

Delete Lsa::getOriginRouterCopy() in favor of a custom Boost.Multi-Index
key extractor.

Mark single-parameter constructor as 'explicit'.

Rewrite class-level Doxygen with ABNF syntax.

refs #5308

Change-Id: I3c43395ce86f9a1a52da186fcf8c5a15cf35fe40
diff --git a/src/lsa/adj-lsa.cpp b/src/lsa/adj-lsa.cpp
index ac583e4..f143499 100644
--- a/src/lsa/adj-lsa.cpp
+++ b/src/lsa/adj-lsa.cpp
@@ -112,23 +112,18 @@
   m_adl = adl;
 }
 
-std::string
-AdjLsa::toString() const
+void
+AdjLsa::print(std::ostream& os) const
 {
-  std::ostringstream os;
-  os << getString();
   os << "      Adjacent(s):\n";
 
   int adjacencyIndex = 0;
-
   for (const auto& adjacency : m_adl) {
     os << "        Adjacent " << adjacencyIndex++
        << ": (name=" << adjacency.getName()
        << ", uri="   << adjacency.getFaceUri()
        << ", cost="  << adjacency.getLinkCost() << ")\n";
   }
-
-  return os.str();
 }
 
 std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
@@ -145,10 +140,4 @@
   return {false, std::list<ndn::Name>{}, std::list<ndn::Name>{}};
 }
 
-std::ostream&
-operator<<(std::ostream& os, const AdjLsa& lsa)
-{
-  return os << lsa.toString();
-}
-
 } // namespace nlsr
diff --git a/src/lsa/adj-lsa.hpp b/src/lsa/adj-lsa.hpp
index 133e95c..8c6354d 100644
--- a/src/lsa/adj-lsa.hpp
+++ b/src/lsa/adj-lsa.hpp
@@ -30,23 +30,27 @@
 
 namespace nlsr {
 
-/*!
-   \brief Data abstraction for AdjLsa
-   AdjacencyLsa := ADJACENCY-LSA-TYPE TLV-LENGTH
-                     Lsa
-                     Adjacency*
-
+/**
+ * @brief Represents an LSA of adjacencies of the origin router in link-state mode.
+ *
+ * AdjLsa is encoded as:
+ * @code{.abnf}
+ * AdjLsa = ADJACENCY-LSA-TYPE TLV-LENGTH
+ *            Lsa
+ *            *Adjacency
+ * @endcode
  */
 class AdjLsa : public Lsa, private boost::equality_comparable<AdjLsa>
 {
 public:
-  typedef AdjacencyList::const_iterator const_iterator;
+  using const_iterator = AdjacencyList::const_iterator;
 
   AdjLsa() = default;
 
   AdjLsa(const ndn::Name& originR, uint64_t seqNo,
          const ndn::time::system_clock::time_point& timepoint, AdjacencyList& adl);
 
+  explicit
   AdjLsa(const ndn::Block& block);
 
   Lsa::Type
@@ -103,12 +107,13 @@
   void
   wireDecode(const ndn::Block& wire);
 
-  std::string
-  toString() const override;
-
   std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
   update(const std::shared_ptr<Lsa>& lsa) override;
 
+private:
+  void
+  print(std::ostream& os) const override;
+
 private: // non-member operators
   // NOTE: the following "hidden friend" operators are available via
   //       argument-dependent lookup only and must be defined inline.
@@ -126,9 +131,6 @@
 
 NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(AdjLsa);
 
-std::ostream&
-operator<<(std::ostream& os, const AdjLsa& lsa);
-
 } // namespace nlsr
 
 #endif // NLSR_LSA_ADJ_LSA_HPP
diff --git a/src/lsa/coordinate-lsa.cpp b/src/lsa/coordinate-lsa.cpp
index be42d9e..11428f8 100644
--- a/src/lsa/coordinate-lsa.cpp
+++ b/src/lsa/coordinate-lsa.cpp
@@ -119,18 +119,14 @@
   m_hyperbolicAngles = angles;
 }
 
-std::string
-CoordinateLsa::toString() const
+void
+CoordinateLsa::print(std::ostream& os) const
 {
-  std::ostringstream os;
-  os << getString();
   os << "      Hyperbolic Radius  : " << m_hyperbolicRadius << "\n";
   int i = 0;
   for (const auto& value : m_hyperbolicAngles) {
     os << "      Hyperbolic Theta " << i++ << " : " << value << "\n";
   }
-
-  return os.str();
 }
 
 std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
@@ -148,10 +144,4 @@
   return {false, std::list<ndn::Name>{}, std::list<ndn::Name>{}};
 }
 
-std::ostream&
-operator<<(std::ostream& os, const CoordinateLsa& lsa)
-{
-  return os << lsa.toString();
-}
-
 } // namespace nlsr
diff --git a/src/lsa/coordinate-lsa.hpp b/src/lsa/coordinate-lsa.hpp
index c9e3904..3e7f0a1 100644
--- a/src/lsa/coordinate-lsa.hpp
+++ b/src/lsa/coordinate-lsa.hpp
@@ -29,12 +29,22 @@
 
 namespace nlsr {
 
-/*!
-   \brief Data abstraction for CoordinateLsa
-   CoordinateLsa := COORDINATE-LSA-TYPE TLV-LENGTH
-                      Lsa
-                      HyperbolicRadius
-                      HyperbolicAngle+
+/**
+ * @brief Represents an LSA of hyperbolic coordinates of the origin router.
+ *
+ * CoordinateLsa is encoded as:
+ * @code{.abnf}
+ * CoordinateLsa = COORDINATE-LSA-TYPE TLV-LENGTH
+ *                   Lsa
+ *                   HyperbolicRadius
+ *                   1*HyperbolicAngle ; theta
+ *
+ * HyperbolicRadius = HYPERBOLIC-RADIUS-TYPE TLV-LENGTH
+ *                      Double ; IEEE754 double precision
+ *
+ * HyperbolicAngle = HYPERBOLIC-ANGLE-TYPE TLV-LENGTH
+ *                     Double ; IEEE754 double precision
+ * @endcode
  */
 class CoordinateLsa : public Lsa, private boost::equality_comparable<CoordinateLsa>
 {
@@ -45,6 +55,7 @@
                 const ndn::time::system_clock::time_point& timepoint,
                 double radius, std::vector<double> angles);
 
+  explicit
   CoordinateLsa(const ndn::Block& block);
 
   Lsa::Type
@@ -95,12 +106,13 @@
   void
   wireDecode(const ndn::Block& wire);
 
-  std::string
-  toString() const override;
-
   std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
   update(const std::shared_ptr<Lsa>& lsa) override;
 
+private:
+  void
+  print(std::ostream& os) const override;
+
 private: // non-member operators
   // NOTE: the following "hidden friend" operators are available via
   //       argument-dependent lookup only and must be defined inline.
@@ -122,9 +134,6 @@
 
 NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(CoordinateLsa);
 
-std::ostream&
-operator<<(std::ostream& os, const CoordinateLsa& lsa);
-
 } // namespace nlsr
 
 #endif // NLSR_LSA_COORDINATE_LSA_HPP
diff --git a/src/lsa/lsa.cpp b/src/lsa/lsa.cpp
index 26fdad3..8d5a3dc 100644
--- a/src/lsa/lsa.cpp
+++ b/src/lsa/lsa.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2023,  The University of Memphis,
+ * Copyright (c) 2014-2024,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -98,6 +98,19 @@
 }
 
 std::ostream&
+operator<<(std::ostream& os, const Lsa& lsa)
+{
+  auto duration = lsa.m_expirationTimePoint - ndn::time::system_clock::now();
+  os << "    " << lsa.getType() << " LSA:\n"
+     << "      Origin Router      : " << lsa.m_originRouter << "\n"
+     << "      Sequence Number    : " << lsa.m_seqNo << "\n"
+     << "      Expires in         : " << ndn::time::duration_cast<ndn::time::milliseconds>(duration)
+     << "\n";
+  lsa.print(os);
+  return os;
+}
+
+std::ostream&
 operator<<(std::ostream& os, const Lsa::Type& type)
 {
   switch (type) {
@@ -137,17 +150,4 @@
   return is;
 }
 
-std::string
-Lsa::getString() const
-{
-  std::ostringstream os;
-  auto duration = m_expirationTimePoint - ndn::time::system_clock::now();
-  os << "    " << getType() << " LSA:\n"
-     << "      Origin Router      : " << m_originRouter << "\n"
-     << "      Sequence Number    : " << m_seqNo << "\n"
-     << "      Expires in         : " << ndn::time::duration_cast<ndn::time::milliseconds>(duration)
-     << "\n";
-  return os.str();
-}
-
 } // namespace nlsr
diff --git a/src/lsa/lsa.hpp b/src/lsa/lsa.hpp
index 8404355..e482a92 100644
--- a/src/lsa/lsa.hpp
+++ b/src/lsa/lsa.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2023,  The University of Memphis,
+ * Copyright (c) 2014-2024,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -31,12 +31,16 @@
 
 namespace nlsr {
 
-/*!
-   \brief Data abstraction for Lsa
-   Lsa := LSA-TYPE TLV-LENGTH
-            Name
-            SequenceNumber
-            ExpirationTimePoint
+/**
+ * @brief Represents a Link State Announcement (LSA).
+ *
+ * The base level LSA is encoded as:
+ * @code{.abnf}
+ * Lsa = LSA-TYPE TLV-LENGTH
+ *         Name ; origin router
+ *         SequenceNumber
+ *         ExpirationTime
+ * @endcode
  */
 class Lsa
 {
@@ -55,11 +59,12 @@
   };
 
 protected:
+  Lsa() = default;
+
   Lsa(const ndn::Name& originRouter, uint64_t seqNo,
       ndn::time::system_clock::time_point expirationTimePoint);
 
-  Lsa() = default;
-
+  explicit
   Lsa(const Lsa& lsa);
 
 public:
@@ -88,12 +93,6 @@
     return m_originRouter;
   }
 
-  ndn::Name
-  getOriginRouterCopy() const
-  {
-    return m_originRouter;
-  }
-
   const ndn::time::system_clock::time_point&
   getExpirationTimePoint() const
   {
@@ -113,11 +112,6 @@
     m_expiringEventId = eid;
   }
 
-  /*! Get data common to all LSA types for printing purposes.
-   */
-  virtual std::string
-  toString() const = 0;
-
   virtual std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
   update(const std::shared_ptr<Lsa>& lsa) = 0;
 
@@ -132,8 +126,12 @@
   void
   wireDecode(const ndn::Block& wire);
 
-  std::string
-  getString() const;
+private:
+  virtual void
+  print(std::ostream& os) const = 0;
+
+  friend std::ostream&
+  operator<<(std::ostream& os, const Lsa& lsa);
 
 PUBLIC_WITH_TESTS_ELSE_PROTECTED:
   ndn::Name m_originRouter;
diff --git a/src/lsa/name-lsa.cpp b/src/lsa/name-lsa.cpp
index ce743a3..7867b68 100644
--- a/src/lsa/name-lsa.cpp
+++ b/src/lsa/name-lsa.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2023,  The University of Memphis,
+ * Copyright (c) 2014-2024,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -112,18 +112,14 @@
   m_npl = npl;
 }
 
-std::string
-NameLsa::toString() const
+void
+NameLsa::print(std::ostream& os) const
 {
-  std::ostringstream os;
-  os << getString();
   os << "      Names:\n";
   int i = 0;
   for (const auto& name : m_npl.getNames()) {
     os << "        Name " << i++ << ": " << name << "\n";
   }
-
-  return os.str();
 }
 
 std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
@@ -156,10 +152,4 @@
   return {updated, namesToAdd, namesToRemove};
 }
 
-std::ostream&
-operator<<(std::ostream& os, const NameLsa& lsa)
-{
-  return os << lsa.toString();
-}
-
 } // namespace nlsr
diff --git a/src/lsa/name-lsa.hpp b/src/lsa/name-lsa.hpp
index 7c82b90..625bbb7 100644
--- a/src/lsa/name-lsa.hpp
+++ b/src/lsa/name-lsa.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2023,  The University of Memphis,
+ * Copyright (c) 2014-2024,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -29,11 +29,15 @@
 
 namespace nlsr {
 
-/*!
-   \brief Data abstraction for NameLsa
-   NameLsa := NAME-LSA-TYPE TLV-LENGTH
-                Lsa
-                Name+
+/**
+ * @brief Represents an LSA of name prefixes announced by the origin router.
+ *
+ * NameLsa is encoded as:
+ * @code{.abnf}
+ * NameLsa = NAME-LSA-TYPE TLV-LENGTH
+ *             Lsa
+ *             1*Name
+ * @endcode
  */
 class NameLsa : public Lsa, private boost::equality_comparable<NameLsa>
 {
@@ -44,6 +48,7 @@
           const ndn::time::system_clock::time_point& timepoint,
           const NamePrefixList& npl);
 
+  explicit
   NameLsa(const ndn::Block& block);
 
   Lsa::Type
@@ -94,12 +99,13 @@
   void
   wireDecode(const ndn::Block& wire);
 
-  std::string
-  toString() const override;
-
   std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
   update(const std::shared_ptr<Lsa>& lsa) override;
 
+private:
+  void
+  print(std::ostream& os) const override;
+
 private: // non-member operators
   // NOTE: the following "hidden friend" operators are available via
   //       argument-dependent lookup only and must be defined inline.
@@ -117,9 +123,6 @@
 
 NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(NameLsa);
 
-std::ostream&
-operator<<(std::ostream& os, const NameLsa& lsa);
-
 } // namespace nlsr
 
 #endif // NLSR_LSA_NAME_LSA_HPP
diff --git a/src/lsdb.cpp b/src/lsdb.cpp
index 844de22..77d2de6 100644
--- a/src/lsdb.cpp
+++ b/src/lsdb.cpp
@@ -142,8 +142,7 @@
 void
 Lsdb::writeLog() const
 {
-  static const Lsa::Type types[] = {Lsa::Type::COORDINATE, Lsa::Type::NAME, Lsa::Type::ADJACENCY};
-  for (const auto& type : types) {
+  for (auto type : {Lsa::Type::COORDINATE, Lsa::Type::NAME, Lsa::Type::ADJACENCY}) {
     if ((type == Lsa::Type::COORDINATE &&
          m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_OFF) ||
         (type == Lsa::Type::ADJACENCY &&
@@ -154,7 +153,7 @@
     NLSR_LOG_DEBUG("---------------" << type << " LSDB-------------------");
     auto lsaRange = m_lsdb.get<byType>().equal_range(type);
     for (auto lsaIt = lsaRange.first; lsaIt != lsaRange.second; ++lsaIt) {
-      NLSR_LOG_DEBUG((*lsaIt)->toString());
+      NLSR_LOG_DEBUG(**lsaIt);
     }
   }
 }
@@ -263,7 +262,7 @@
 
   auto chkLsa = findLsa(lsa->getOriginRouter(), lsa->getType());
   if (chkLsa == nullptr) {
-    NLSR_LOG_DEBUG("Adding LSA:\n" << lsa->toString());
+    NLSR_LOG_DEBUG("Adding LSA:\n" << *lsa);
 
     m_lsdb.emplace(lsa);
     onLsdbModified(lsa, LsdbUpdate::INSTALLED, {}, {});
@@ -272,7 +271,7 @@
   }
   // Else this is a known name LSA, so we are updating it.
   else if (chkLsa->getSeqNo() < lsa->getSeqNo()) {
-    NLSR_LOG_DEBUG("Updating LSA:\n" << chkLsa->toString());
+    NLSR_LOG_DEBUG("Updating LSA:\n" << *chkLsa);
     chkLsa->setSeqNo(lsa->getSeqNo());
     chkLsa->setExpirationTimePoint(lsa->getExpirationTimePoint());
 
@@ -282,7 +281,7 @@
     }
 
     chkLsa->setExpiringEventId(scheduleLsaExpiration(chkLsa, timeToExpire));
-    NLSR_LOG_DEBUG("Updated LSA:\n" << chkLsa->toString());
+    NLSR_LOG_DEBUG("Updated LSA:\n" << *chkLsa);
   }
 }
 
@@ -291,7 +290,7 @@
 {
   if (lsaIt != m_lsdb.end()) {
     auto lsaPtr = *lsaIt;
-    NLSR_LOG_DEBUG("Removing LSA:\n" << lsaPtr->toString());
+    NLSR_LOG_DEBUG("Removing LSA:\n" << *lsaPtr);
     m_lsdb.erase(lsaIt);
     onLsdbModified(lsaPtr, LsdbUpdate::REMOVED, {}, {});
   }
@@ -380,17 +379,17 @@
   // If this name LSA exists in the LSDB
   if (lsaIt != m_lsdb.end()) {
     auto lsaPtr = *lsaIt;
-    NLSR_LOG_DEBUG(lsaPtr->toString());
+    NLSR_LOG_DEBUG(*lsaPtr);
     NLSR_LOG_DEBUG("LSA Exists with seq no: " << lsaPtr->getSeqNo());
     // If its seq no is the one we are expecting.
     if (lsaPtr->getSeqNo() == lsa->getSeqNo()) {
       if (lsaPtr->getOriginRouter() == m_thisRouterPrefix) {
         NLSR_LOG_DEBUG("Own " << lsaPtr->getType() << " LSA, so refreshing it");
-        NLSR_LOG_DEBUG("Current LSA:\n" << lsaPtr->toString());
+        NLSR_LOG_DEBUG("Current LSA:\n" << *lsaPtr);
         lsaPtr->setSeqNo(lsaPtr->getSeqNo() + 1);
         m_sequencingManager.setLsaSeq(lsaPtr->getSeqNo(), lsaPtr->getType());
         lsaPtr->setExpirationTimePoint(getLsaExpirationTimePoint());
-        NLSR_LOG_DEBUG("Updated LSA:\n" << lsaPtr->toString());
+        NLSR_LOG_DEBUG("Updated LSA:\n" << *lsaPtr);
         // schedule refreshing event again
         lsaPtr->setExpiringEventId(scheduleLsaExpiration(lsaPtr, m_lsaRefreshTime));
         m_sequencingManager.writeSeqNoToFile();
diff --git a/src/lsdb.hpp b/src/lsdb.hpp
index 93e1ad9..7e1d9ad 100644
--- a/src/lsdb.hpp
+++ b/src/lsdb.hpp
@@ -118,6 +118,17 @@
     return std::static_pointer_cast<T>(findLsa(router, T::type()));
   }
 
+  struct ExtractOriginRouter
+  {
+    using result_type = ndn::Name;
+
+    ndn::Name
+    operator()(const Lsa& lsa) const
+    {
+      return lsa.getOriginRouter();
+    }
+  };
+
   struct name_hash {
     int
     operator()(const ndn::Name& name) const {
@@ -143,7 +154,7 @@
         bmi::tag<byName>,
         bmi::composite_key<
           Lsa,
-          bmi::const_mem_fun<Lsa, ndn::Name, &Lsa::getOriginRouterCopy>,
+          ExtractOriginRouter,
           bmi::const_mem_fun<Lsa, Lsa::Type, &Lsa::getType>
         >,
         bmi::composite_key_hash<name_hash, enum_class_hash>