lsa: define CoordinateLsa operator==

getCorRadius, setCorRadius, getCorTheta, setCorTheta methods are
renamed, in accordance with ndn-cxx code style recommendations.

refs #4094

Change-Id: Iaf3ebf3b895d6dc351b2f754e4a9c65713bdca3a
diff --git a/src/adjacent.cpp b/src/adjacent.cpp
index 508832a..fe8635e 100644
--- a/src/adjacent.cpp
+++ b/src/adjacent.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).
@@ -21,6 +21,7 @@
 #include "adjacent.hpp"
 #include "logger.hpp"
 #include "tlv-nlsr.hpp"
+#include "utility/numeric.hpp"
 
 namespace nlsr {
 
@@ -158,10 +159,9 @@
 bool
 Adjacent::operator==(const Adjacent& adjacent) const
 {
-  return (m_name == adjacent.getName()) &&
-         (m_faceUri == adjacent.getFaceUri()) &&
-         (std::abs(m_linkCost - adjacent.getLinkCost()) <
-          std::numeric_limits<double>::epsilon());
+  return m_name == adjacent.getName() &&
+         m_faceUri == adjacent.getFaceUri() &&
+         util::diffInEpsilon(m_linkCost, adjacent.getLinkCost());
 }
 
 bool
diff --git a/src/lsa/coordinate-lsa.cpp b/src/lsa/coordinate-lsa.cpp
index f25ab2c..be42d9e 100644
--- a/src/lsa/coordinate-lsa.cpp
+++ b/src/lsa/coordinate-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.
  *
@@ -38,24 +38,6 @@
   wireDecode(block);
 }
 
-bool
-CoordinateLsa::isEqualContent(const CoordinateLsa& clsa) const
-{
-  if (clsa.getCorTheta().size() != m_hyperbolicAngles.size()) {
-    return false;
-  }
-
-  std::vector<double> m_angles2 = clsa.getCorTheta();
-  for (unsigned int i = 0; i < clsa.getCorTheta().size(); i++) {
-    if (std::abs(m_hyperbolicAngles[i] - m_angles2[i]) > std::numeric_limits<double>::epsilon()) {
-      return false;
-    }
-  }
-
-  return (std::abs(m_hyperbolicRadius - clsa.getCorRadius()) <
-          std::numeric_limits<double>::epsilon());
-}
-
 template<ndn::encoding::Tag TAG>
 size_t
 CoordinateLsa::wireEncode(ndn::EncodingImpl<TAG>& block) const
@@ -155,10 +137,10 @@
 CoordinateLsa::update(const std::shared_ptr<Lsa>& lsa)
 {
   auto clsa = std::static_pointer_cast<CoordinateLsa>(lsa);
-  if (!isEqualContent(*clsa)) {
-    m_hyperbolicRadius = clsa->getCorRadius();
+  if (*this != *clsa) {
+    m_hyperbolicRadius = clsa->getRadius();
     m_hyperbolicAngles.clear();
-    for (const auto& angle : clsa->getCorTheta()) {
+    for (const auto& angle : clsa->getTheta()) {
       m_hyperbolicAngles.push_back(angle);
     }
     return {true, std::list<ndn::Name>{}, std::list<ndn::Name>{}};
diff --git a/src/lsa/coordinate-lsa.hpp b/src/lsa/coordinate-lsa.hpp
index 112e7d5..c9e3904 100644
--- a/src/lsa/coordinate-lsa.hpp
+++ b/src/lsa/coordinate-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.
  *
@@ -23,6 +23,9 @@
 #define NLSR_LSA_COORDINATE_LSA_HPP
 
 #include "lsa.hpp"
+#include "utility/numeric.hpp"
+
+#include <boost/operators.hpp>
 
 namespace nlsr {
 
@@ -33,7 +36,7 @@
                       HyperbolicRadius
                       HyperbolicAngle+
  */
-class CoordinateLsa : public Lsa
+class CoordinateLsa : public Lsa, private boost::equality_comparable<CoordinateLsa>
 {
 public:
   CoordinateLsa() = default;
@@ -57,34 +60,31 @@
   }
 
   double
-  getCorRadius() const
+  getRadius() const
   {
     return m_hyperbolicRadius;
   }
 
   void
-  setCorRadius(double cr)
+  setRadius(double cr)
   {
     m_wire.reset();
     m_hyperbolicRadius = cr;
   }
 
-  const std::vector<double>
-  getCorTheta() const
+  const std::vector<double>&
+  getTheta() const
   {
     return m_hyperbolicAngles;
   }
 
   void
-  setCorTheta(std::vector<double> ct)
+  setTheta(std::vector<double> ct)
   {
     m_wire.reset();
-    m_hyperbolicAngles = ct;
+    m_hyperbolicAngles = std::move(ct);
   }
 
-  bool
-  isEqualContent(const CoordinateLsa& clsa) const;
-
   template<ndn::encoding::Tag TAG>
   size_t
   wireEncode(ndn::EncodingImpl<TAG>& block) const;
@@ -101,6 +101,20 @@
   std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
   update(const std::shared_ptr<Lsa>& lsa) override;
 
+private: // non-member operators
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
+  // boost::equality_comparable provides != operator.
+
+  friend bool
+  operator==(const CoordinateLsa& lhs, const CoordinateLsa& rhs)
+  {
+    return util::diffInEpsilon(lhs.m_hyperbolicRadius, rhs.m_hyperbolicRadius) &&
+           std::equal(lhs.m_hyperbolicAngles.begin(), lhs.m_hyperbolicAngles.end(),
+                      rhs.m_hyperbolicAngles.begin(), rhs.m_hyperbolicAngles.end(),
+                      util::diffInEpsilon);
+  }
+
 private:
   double m_hyperbolicRadius = 0.0;
   std::vector<double> m_hyperbolicAngles;
diff --git a/src/route/routing-table-calculator.cpp b/src/route/routing-table-calculator.cpp
index 474604a..e65f5c0 100644
--- a/src/route/routing-table-calculator.cpp
+++ b/src/route/routing-table-calculator.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.
  *
@@ -496,11 +496,11 @@
     return UNKNOWN_DISTANCE;
   }
 
-  std::vector<double> srcTheta = srcLsa->getCorTheta();
-  std::vector<double> destTheta = destLsa->getCorTheta();
+  std::vector<double> srcTheta = srcLsa->getTheta();
+  std::vector<double> destTheta = destLsa->getTheta();
 
-  double srcRadius = srcLsa->getCorRadius();
-  double destRadius = destLsa->getCorRadius();
+  double srcRadius = srcLsa->getRadius();
+  double destRadius = destLsa->getRadius();
 
   double diffTheta = calculateAngularDistance(srcTheta, destTheta);
 
diff --git a/src/utility/numeric.hpp b/src/utility/numeric.hpp
new file mode 100644
index 0000000..2bf8f39
--- /dev/null
+++ b/src/utility/numeric.hpp
@@ -0,0 +1,43 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2024,  The University of Memphis,
+ *                           Regents of the University of California,
+ *                           Arizona Board of Regents.
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NLSR_NUMERIC_HPP
+#define NLSR_NUMERIC_HPP
+
+#include "common.hpp"
+
+namespace nlsr::util {
+
+/**
+ * @brief Determine whether the difference between two numbers are within epsilon.
+ * @param lhs first number.
+ * @param rhs second number.
+ * @returns true if their difference is within epsilon.
+ */
+inline bool
+diffInEpsilon(double lhs, double rhs)
+{
+  return std::abs(lhs - rhs) < std::numeric_limits<double>::epsilon();
+}
+
+} // namespace nlsr::util
+
+#endif // NLSR_NUMERIC_HPP
diff --git a/tests/lsa/test-coordinate-lsa.cpp b/tests/lsa/test-coordinate-lsa.cpp
index 182665d..8e61f8b 100644
--- a/tests/lsa/test-coordinate-lsa.cpp
+++ b/tests/lsa/test-coordinate-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.
  *
@@ -94,10 +94,10 @@
   CoordinateLsa clsa1("router1", 12, testTimePoint, 2.5, angles1);
   CoordinateLsa clsa2("router1", 12, testTimePoint, 2.5, angles2);
 
-  BOOST_CHECK_CLOSE(clsa1.getCorRadius(), 2.5, 0.0001);
-  BOOST_CHECK(clsa1.getCorTheta() == angles1);
+  BOOST_CHECK_CLOSE(clsa1.getRadius(), 2.5, 0.0001);
+  BOOST_TEST(clsa1.getTheta() == angles1, boost::test_tools::per_element());
 
-  BOOST_CHECK(clsa1.isEqualContent(clsa2));
+  BOOST_CHECK_EQUAL(clsa1, clsa2);
 
   BOOST_CHECK_EQUAL(clsa1.wireEncode(), clsa2.wireEncode());
 
@@ -105,11 +105,11 @@
   BOOST_TEST(wire == COORDINATE_LSA1, boost::test_tools::per_element());
 
   std::vector<double> angles3{40.0};
-  clsa1.setCorTheta(angles3);
+  clsa1.setTheta(angles3);
   wire = clsa1.wireEncode();
   BOOST_TEST(wire == COORDINATE_LSA_DIFF_ANGLE, boost::test_tools::per_element());
 
-  clsa1.setCorRadius(2.3);
+  clsa1.setRadius(2.3);
   wire = clsa1.wireEncode();
   BOOST_TEST(wire == COORDINATE_LSA_DIFF_RADIUS, boost::test_tools::per_element());
 
diff --git a/tests/test-statistics.cpp b/tests/test-statistics.cpp
index 887112a..43bbf70 100644
--- a/tests/test-statistics.cpp
+++ b/tests/test-statistics.cpp
@@ -268,7 +268,7 @@
   auto coorLsa = lsdb.findLsa<CoordinateLsa>(conf.getRouterPrefix());
 
   seqNo = coorLsa->getSeqNo();
-  coorLsa->setCorTheta({20.0, 30.0});
+  coorLsa->setTheta({20.0, 30.0});
   lsdb.installLsa(coorLsa);
 
   // Receive Adjacency LSA Interest