route: simplify Map with boost::bimap

refs #5308

Change-Id: I920cc1fc484b3fbee9a8f1f73c81db0cbce40b45
diff --git a/src/route/map.cpp b/src/route/map.cpp
index a1828af..17b7113 100644
--- a/src/route/map.cpp
+++ b/src/route/map.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  The University of Memphis,
+ * Copyright (c) 2014-2024,  The University of Memphis,
  *                           Regents of the University of California
  *
  * This file is part of NLSR (Named-data Link State Routing).
@@ -23,51 +23,45 @@
 #include "adjacent.hpp"
 #include "lsa/lsa.hpp"
 #include "lsdb.hpp"
-#include "logger.hpp"
 
 namespace nlsr {
 
-INIT_LOGGER(route.Map);
-
 void
 Map::addEntry(const ndn::Name& rtrName)
 {
-  MapEntry me {rtrName, m_mappingIndex};
-  if (addEntry(me)) {
-    m_mappingIndex++;
-  }
-}
-
-bool
-Map::addEntry(MapEntry& mpe)
-{
-  return m_entries.insert(mpe).second;
+  int32_t mappingNo = static_cast<int32_t>(m_bimap.size());
+  m_bimap.by<ndn::Name>().insert({rtrName, mappingNo});
 }
 
 std::optional<ndn::Name>
 Map::getRouterNameByMappingNo(int32_t mn) const
 {
-  auto&& mappingNumberView = m_entries.get<detail::byMappingNumber>();
-  auto it = mappingNumberView.find(mn);
-  return it == mappingNumberView.end() ? std::nullopt : std::optional(it->router);
+  auto it = m_bimap.by<MappingNo>().find(mn);
+  if (it == m_bimap.by<MappingNo>().end()) {
+    return std::nullopt;
+  }
+  return it->get<ndn::Name>();
 }
 
 std::optional<int32_t>
 Map::getMappingNoByRouterName(const ndn::Name& rName)
 {
-  auto&& routerNameView = m_entries.get<detail::byRouterName>();
-  auto it = routerNameView.find(rName);
-  return it == routerNameView.end() ? std::nullopt : std::optional(it->mappingNumber);
+  auto it = m_bimap.by<ndn::Name>().find(rName);
+  if (it == m_bimap.by<ndn::Name>().end()) {
+    return std::nullopt;
+  }
+  return it->get<Map::MappingNo>();
 }
 
-void
-Map::writeLog()
+std::ostream&
+operator<<(std::ostream& os, const Map& map)
 {
-  NLSR_LOG_DEBUG("---------------Map----------------------");
-  for (const auto& entry : m_entries.get<detail::byRouterName>()) {
-    NLSR_LOG_DEBUG("MapEntry: ( Router: " << entry.router << " Mapping No: " <<
-                   entry.mappingNumber << " )");
+  os << "---------------Map----------------------";
+  for (const auto& entry : map.m_bimap) {
+    os << "\nMapEntry: ( Router: " << entry.get<ndn::Name>()
+       << " Mapping No: " << entry.get<Map::MappingNo>() << " )";
   }
+  return os;
 }
 
 } // namespace nlsr
diff --git a/src/route/map.hpp b/src/route/map.hpp
index f2e8eae..c43a777 100644
--- a/src/route/map.hpp
+++ b/src/route/map.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  The University of Memphis,
+ * Copyright (c) 2014-2024,  The University of Memphis,
  *                           Regents of the University of California
  *
  * This file is part of NLSR (Named-data Link State Routing).
@@ -24,48 +24,16 @@
 #include "common.hpp"
 #include "lsa/adj-lsa.hpp"
 
-#include <boost/multi_index_container.hpp>
-#include <boost/multi_index/hashed_index.hpp>
-#include <boost/multi_index/member.hpp>
-#include <boost/multi_index/tag.hpp>
+#include <boost/bimap.hpp>
+#include <boost/bimap/unordered_set_of.hpp>
 
 #include <optional>
 
 namespace nlsr {
 
-struct MapEntry
-{
-  ndn::Name router;
-  int32_t mappingNumber = -1;
-};
-
-namespace detail {
-
-  using namespace boost::multi_index;
-  // Define tags so that we can search by different indices.
-  struct byRouterName {};
-  struct byMappingNumber{};
-  using entryContainer = multi_index_container<
-    MapEntry,
-    indexed_by<
-      hashed_unique<tag<byRouterName>,
-                    member<MapEntry, ndn::Name, &MapEntry::router>,
-                    std::hash<ndn::Name>>,
-      hashed_unique<tag<byMappingNumber>,
-                    member<MapEntry, int32_t, &MapEntry::mappingNumber>>
-      >
-    >;
-
-} // namespace detail
-
 class Map
 {
 public:
-  Map()
-    : m_mappingIndex(0)
-  {
-  }
-
   /*! \brief Add a map entry to this map.
     \param rtrName The name of the router.
 
@@ -114,22 +82,30 @@
   getMappingNoByRouterName(const ndn::Name& rName);
 
   size_t
-  getMapSize() const
+  size() const
   {
-    return m_entries.size();
+    return m_bimap.size();
   }
 
-  void
-  writeLog();
-
 private:
-  bool
-  addEntry(MapEntry& mpe);
+  struct MappingNo;
+  boost::bimap<
+    boost::bimaps::unordered_set_of<
+      boost::bimaps::tagged<ndn::Name, ndn::Name>,
+      std::hash<ndn::Name>
+    >,
+    boost::bimaps::unordered_set_of<
+      boost::bimaps::tagged<int32_t, MappingNo>
+    >
+  > m_bimap;
 
-  int32_t m_mappingIndex;
-  detail::entryContainer m_entries;
+  friend std::ostream&
+  operator<<(std::ostream& os, const Map& map);
 };
 
+std::ostream&
+operator<<(std::ostream& os, const Map& map);
+
 } // namespace nlsr
 
 #endif // NLSR_MAP_HPP
diff --git a/src/route/routing-table.cpp b/src/route/routing-table.cpp
index 7fd8a7a..fa7dee7 100644
--- a/src/route/routing-table.cpp
+++ b/src/route/routing-table.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  The University of Memphis,
+ * Copyright (c) 2014-2024,  The University of Memphis,
  *                           Regents of the University of California
  *
  * This file is part of NLSR (Named-data Link State Routing).
@@ -130,9 +130,9 @@
   Map map;
   auto lsaRange = m_lsdb.getLsdbIterator<AdjLsa>();
   map.createFromAdjLsdb(lsaRange.first, lsaRange.second);
-  map.writeLog();
+  NLSR_LOG_DEBUG(map);
 
-  size_t nRouters = map.getMapSize();
+  size_t nRouters = map.size();
 
   LinkStateRoutingTableCalculator calculator(nRouters);
 
@@ -156,9 +156,9 @@
   Map map;
   auto lsaRange = m_lsdb.getLsdbIterator<CoordinateLsa>();
   map.createFromCoordinateLsdb(lsaRange.first, lsaRange.second);
-  map.writeLog();
+  NLSR_LOG_DEBUG(map);
 
-  size_t nRouters = map.getMapSize();
+  size_t nRouters = map.size();
 
   HyperbolicRoutingCalculator calculator(nRouters, isDryRun, m_confParam.getRouterPrefix());
 
diff --git a/tests/route/test-hyperbolic-calculator.cpp b/tests/route/test-hyperbolic-calculator.cpp
index bbb7930..d2df482 100644
--- a/tests/route/test-hyperbolic-calculator.cpp
+++ b/tests/route/test-hyperbolic-calculator.cpp
@@ -109,7 +109,7 @@
 
   void runTest(const double& expectedCost)
   {
-    HyperbolicRoutingCalculator calculator(map.getMapSize(), false, ROUTER_A_NAME);
+    HyperbolicRoutingCalculator calculator(map.size(), false, ROUTER_A_NAME);
     calculator.calculatePath(map, routingTable, lsdb, adjacencies);
 
     RoutingTableEntry* entryB = routingTable.findRoutingTableEntry(ROUTER_B_NAME);
diff --git a/tests/route/test-link-state-calculator.cpp b/tests/route/test-link-state-calculator.cpp
index 366aa7e..877f204 100644
--- a/tests/route/test-link-state-calculator.cpp
+++ b/tests/route/test-link-state-calculator.cpp
@@ -118,7 +118,7 @@
 
 BOOST_AUTO_TEST_CASE(Basic)
 {
-  LinkStateRoutingTableCalculator calculator(map.getMapSize());
+  LinkStateRoutingTableCalculator calculator(map.size());
   calculator.calculatePath(map, routingTable, conf, lsdb);
 
   RoutingTableEntry* entryB = routingTable.findRoutingTableEntry(ROUTER_B_NAME);
@@ -166,7 +166,7 @@
   c->setLinkCost(higherLinkCost);
 
   // Calculation should consider the link between B and C as having cost = higherLinkCost
-  LinkStateRoutingTableCalculator calculator(map.getMapSize());
+  LinkStateRoutingTableCalculator calculator(map.size());
   calculator.calculatePath(map, routingTable, conf, lsdb);
 
   RoutingTableEntry* entryB = routingTable.findRoutingTableEntry(ROUTER_B_NAME);
@@ -214,7 +214,7 @@
   c->setLinkCost(Adjacent::NON_ADJACENT_COST);
 
   // Calculation should consider the link between B and C as down
-  LinkStateRoutingTableCalculator calculator(map.getMapSize());
+  LinkStateRoutingTableCalculator calculator(map.size());
   calculator.calculatePath(map, routingTable, conf, lsdb);
 
   // Router A should be able to get to B through B but not through C
@@ -268,7 +268,7 @@
   b->setLinkCost(0);
 
   // Calculation should consider 0 link-cost between B and C
-  LinkStateRoutingTableCalculator calculator(map.getMapSize());
+  LinkStateRoutingTableCalculator calculator(map.size());
   calculator.calculatePath(map, routingTable, conf, lsdb);
 
   // Router A should be able to get to B through B and C
diff --git a/tests/route/test-map.cpp b/tests/route/test-map.cpp
index 0564377..424c551 100644
--- a/tests/route/test-map.cpp
+++ b/tests/route/test-map.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2019,  The University of Memphis,
+/*
+ * Copyright (c) 2014-2024,  The University of Memphis,
  *                           Regents of the University of California
  *
  * This file is part of NLSR (Named-data Link State Routing).
@@ -23,25 +23,38 @@
 #include "route/map.hpp"
 #include "tests/boost-test.hpp"
 
-namespace nlsr {
-namespace test {
+namespace nlsr::test {
 
 BOOST_AUTO_TEST_SUITE(TestMap)
 
-BOOST_AUTO_TEST_CASE(MapAddElementAndSize)
+BOOST_AUTO_TEST_CASE(Basic)
 {
   Map map1;
 
-  std::string router1 = "r1";
-  std::string router2 = "r2";
+  ndn::Name name1("/r1");
+  ndn::Name name2("/r2");
+  ndn::Name name3("/r3");
 
-  map1.addEntry(router1);
-  map1.addEntry(router2);
+  map1.addEntry(name1);
+  map1.addEntry(name2);
+  BOOST_CHECK_EQUAL(map1.size(), 2);
 
-  BOOST_CHECK_EQUAL(map1.getMapSize(), 2);
+  std::optional<int32_t> mn1 = map1.getMappingNoByRouterName(name1);
+  std::optional<int32_t> mn2 = map1.getMappingNoByRouterName(name2);
+  BOOST_REQUIRE(mn1.has_value());
+  BOOST_REQUIRE(mn2.has_value());
+  BOOST_CHECK_NE(*mn1, *mn2);
+  BOOST_CHECK_EQUAL(map1.getMappingNoByRouterName(name3).has_value(), false);
+
+  BOOST_CHECK_EQUAL(map1.getRouterNameByMappingNo(*mn1).value_or(ndn::Name()), name1);
+  BOOST_CHECK_EQUAL(map1.getRouterNameByMappingNo(*mn2).value_or(ndn::Name()), name2);
+
+  int32_t mn3 = 3333;
+  BOOST_CHECK_NE(mn3, *mn1);
+  BOOST_CHECK_NE(mn3, *mn2);
+  BOOST_CHECK_EQUAL(map1.getRouterNameByMappingNo(mn3).has_value(), false);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
 
-} // namespace test
-} // namespace nlsr
+} // namespace nlsr::test