Declare overloaded comparison operators as non-member functions

Change-Id: I4fd4638c29d01b39df69ad6d8cbc3a0dc9604db3
diff --git a/ndn-cxx/delegation-list.cpp b/ndn-cxx/delegation-list.cpp
index e2a5786..d999f92 100644
--- a/ndn-cxx/delegation-list.cpp
+++ b/ndn-cxx/delegation-list.cpp
@@ -219,12 +219,6 @@
   return nErased;
 }
 
-bool
-operator==(const DelegationList& lhs, const DelegationList& rhs)
-{
-  return lhs.m_dels == rhs.m_dels;
-}
-
 std::ostream&
 operator<<(std::ostream& os, const DelegationList& dl)
 {
diff --git a/ndn-cxx/delegation-list.hpp b/ndn-cxx/delegation-list.hpp
index 031072f..b60b096 100644
--- a/ndn-cxx/delegation-list.hpp
+++ b/ndn-cxx/delegation-list.hpp
@@ -215,6 +215,26 @@
   size_t
   eraseImpl(optional<uint64_t> preference, const Name& name);
 
+private: // non-member operators
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
+
+  /** \brief Compare whether two DelegationLists are equal.
+   *  \note Order matters! If two DelegationLists contain the same Delegations but at least one is
+   *        unsorted, they may compare unequal if the Delegations appear in different order.
+   */
+  friend bool
+  operator==(const DelegationList& lhs, const DelegationList& rhs)
+  {
+    return lhs.m_dels == rhs.m_dels;
+  }
+
+  friend bool
+  operator!=(const DelegationList& lhs, const DelegationList& rhs)
+  {
+    return lhs.m_dels != rhs.m_dels;
+  }
+
 private:
   bool m_isSorted;
 
@@ -226,8 +246,6 @@
    *        therefore the overhead of moving items during insertion and deletion is small.
    */
   std::vector<Delegation> m_dels;
-
-  friend bool operator==(const DelegationList&, const DelegationList&);
 };
 
 #ifndef DOXYGEN
@@ -238,19 +256,6 @@
 DelegationList::wireEncode<encoding::EstimatorTag>(EncodingEstimator&, uint32_t) const;
 #endif
 
-/** \brief compare whether two DelegationLists are equal
- *  \note Order matters! If two DelegationLists contain the same Delegations but at least one is
- *        unsorted, they may compare unequal if the Delegations appear in different order.
- */
-bool
-operator==(const DelegationList& lhs, const DelegationList& rhs);
-
-inline bool
-operator!=(const DelegationList& lhs, const DelegationList& rhs)
-{
-  return !(lhs == rhs);
-}
-
 std::ostream&
 operator<<(std::ostream& os, const DelegationList& dl);
 
diff --git a/ndn-cxx/delegation.cpp b/ndn-cxx/delegation.cpp
deleted file mode 100644
index 7af9f3e..0000000
--- a/ndn-cxx/delegation.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2013-2018 Regents of the University of California.
- *
- * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
- *
- * ndn-cxx library is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * ndn-cxx library 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 Lesser General Public License for more details.
- *
- * You should have received copies of the GNU General Public License and GNU Lesser
- * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- */
-
-#include "ndn-cxx/delegation.hpp"
-
-namespace ndn {
-
-BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Delegation>));
-
-bool
-operator==(const Delegation& lhs, const Delegation& rhs)
-{
-  return lhs.preference == rhs.preference &&
-         lhs.name == rhs.name;
-}
-
-bool
-operator<(const Delegation& lhs, const Delegation& rhs)
-{
-  return std::tie(lhs.preference, lhs.name) <
-         std::tie(rhs.preference, rhs.name);
-}
-
-bool
-operator<=(const Delegation& lhs, const Delegation& rhs)
-{
-  return std::tie(lhs.preference, lhs.name) <=
-         std::tie(rhs.preference, rhs.name);
-}
-
-std::ostream&
-operator<<(std::ostream& os, const Delegation& del)
-{
-  return os << del.name << '(' << del.preference << ')';
-}
-
-} // namespace ndn
diff --git a/ndn-cxx/delegation.hpp b/ndn-cxx/delegation.hpp
index 28558e0..84c8e7b 100644
--- a/ndn-cxx/delegation.hpp
+++ b/ndn-cxx/delegation.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -26,45 +26,64 @@
 
 namespace ndn {
 
-/** \brief represents a delegation
- *  \sa https://named-data.net/doc/ndn-tlv/link.html
+/** \brief Represents a Delegation.
+ *  \sa https://named-data.net/doc/NDN-packet-spec/current/link.html
  */
-struct Delegation
+class Delegation
 {
+private: // non-member operators
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
+
+  friend bool
+  operator==(const Delegation& lhs, const Delegation& rhs)
+  {
+    return !(lhs != rhs);
+  }
+
+  friend bool
+  operator!=(const Delegation& lhs, const Delegation& rhs)
+  {
+    return lhs.preference != rhs.preference ||
+           lhs.name != rhs.name;
+  }
+
+  friend bool
+  operator<(const Delegation& lhs, const Delegation& rhs)
+  {
+    return std::tie(lhs.preference, lhs.name) <
+           std::tie(rhs.preference, rhs.name);
+  }
+
+  friend bool
+  operator<=(const Delegation& lhs, const Delegation& rhs)
+  {
+    return !(rhs < lhs);
+  }
+
+  friend bool
+  operator>(const Delegation& lhs, const Delegation& rhs)
+  {
+    return rhs < lhs;
+  }
+
+  friend bool
+  operator>=(const Delegation& lhs, const Delegation& rhs)
+  {
+    return !(lhs < rhs);
+  }
+
+  friend std::ostream&
+  operator<<(std::ostream& os, const Delegation& d)
+  {
+    return os << d.name << '(' << d.preference << ')';
+  }
+
+public:
   uint64_t preference;
   Name name;
 };
 
-bool
-operator==(const Delegation& lhs, const Delegation& rhs);
-
-inline bool
-operator!=(const Delegation& lhs, const Delegation& rhs)
-{
-  return !(lhs == rhs);
-}
-
-bool
-operator<(const Delegation& lhs, const Delegation& rhs);
-
-bool
-operator<=(const Delegation& lhs, const Delegation& rhs);
-
-inline bool
-operator>(const Delegation& lhs, const Delegation& rhs)
-{
-  return !(lhs <= rhs);
-}
-
-inline bool
-operator>=(const Delegation& lhs, const Delegation& rhs)
-{
-  return !(lhs < rhs);
-}
-
-std::ostream&
-operator<<(std::ostream& os, const Delegation& del);
-
 } // namespace ndn
 
 #endif // NDN_DELEGATION_HPP
diff --git a/ndn-cxx/detail/cf-releaser-osx.hpp b/ndn-cxx/detail/cf-releaser-osx.hpp
index 516b2e4..fff58ab 100644
--- a/ndn-cxx/detail/cf-releaser-osx.hpp
+++ b/ndn-cxx/detail/cf-releaser-osx.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -100,18 +100,6 @@
     return m_typeRef;
   }
 
-  bool
-  operator==(const std::nullptr_t&)
-  {
-    return m_typeRef == nullptr;
-  }
-
-  bool
-  operator!=(const std::nullptr_t&)
-  {
-    return m_typeRef != nullptr;
-  }
-
 public: // Miscellaneous
   void
   retain(const T& typeRef)
@@ -140,6 +128,19 @@
     }
   }
 
+private: // Comparison with nullptr
+  friend bool
+  operator==(const CFReleaser& lhs, std::nullptr_t)
+  {
+    return lhs.m_typeRef == nullptr;
+  }
+
+  friend bool
+  operator!=(const CFReleaser& lhs, std::nullptr_t)
+  {
+    return lhs.m_typeRef != nullptr;
+  }
+
 private:
   T m_typeRef;
 };
diff --git a/ndn-cxx/name-component.hpp b/ndn-cxx/name-component.hpp
index df91ac8..079b9fe 100644
--- a/ndn-cxx/name-component.hpp
+++ b/ndn-cxx/name-component.hpp
@@ -529,7 +529,7 @@
   static Component
   fromParametersSha256Digest(const uint8_t* digest, size_t digestSize);
 
-public: // operators
+public: // comparison
   bool
   empty() const
   {
@@ -559,77 +559,6 @@
   compare(const Component& other) const;
 
   /**
-   * @brief Check if this is the same component as other
-   *
-   * @param other The other Component to compare with.
-   * @return true if the components are equal, otherwise false.
-   */
-  bool
-  operator==(const Component& other) const
-  {
-    return equals(other);
-  }
-
-  /**
-   * @brief Check if this is not the same component as other
-   * @param other The other Component to compare with
-   * @return true if the components are not equal, otherwise false
-   */
-  bool
-  operator!=(const Component& other) const
-  {
-    return !equals(other);
-  }
-
-  /**
-   * @brief Check if the *this is less than or equal to the other in NDN canonical ordering
-   * @param other The other Component to compare with
-   *
-   * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order
-   */
-  bool
-  operator<=(const Component& other) const
-  {
-    return compare(other) <= 0;
-  }
-
-  /**
-   * @brief Check if the *this is less than the other in NDN canonical ordering
-   * @param other The other Component to compare with
-   *
-   * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order
-   */
-  bool
-  operator<(const Component& other) const
-  {
-    return compare(other) < 0;
-  }
-
-  /**
-   * @brief Check if the *this is greater or equal than the other in NDN canonical ordering
-   * @param other The other Component to compare with
-   *
-   * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order
-   */
-  bool
-  operator>=(const Component& other) const
-  {
-    return compare(other) >= 0;
-  }
-
-  /**
-   * @brief Check if the *this is greater than the other in NDN canonical ordering
-   * @param other The other Component to compare with
-   *
-   * @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#canonical-order
-   */
-  bool
-  operator>(const Component& other) const
-  {
-    return compare(other) > 0;
-  }
-
-  /**
    * @brief Get the successor of this name component.
    *
    * The successor of a name component is defined as follows:
@@ -667,6 +596,53 @@
   void
   ensureValid() const;
 
+private: // non-member operators
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
+
+  friend bool
+  operator==(const Component& lhs, const Component& rhs)
+  {
+    return lhs.equals(rhs);
+  }
+
+  friend bool
+  operator!=(const Component& lhs, const Component& rhs)
+  {
+    return !lhs.equals(rhs);
+  }
+
+  friend bool
+  operator<(const Component& lhs, const Component& rhs)
+  {
+    return lhs.compare(rhs) < 0;
+  }
+
+  friend bool
+  operator<=(const Component& lhs, const Component& rhs)
+  {
+    return lhs.compare(rhs) <= 0;
+  }
+
+  friend bool
+  operator>(const Component& lhs, const Component& rhs)
+  {
+    return lhs.compare(rhs) > 0;
+  }
+
+  friend bool
+  operator>=(const Component& lhs, const Component& rhs)
+  {
+    return lhs.compare(rhs) >= 0;
+  }
+
+  friend std::ostream&
+  operator<<(std::ostream& os, const Component& component)
+  {
+    component.toUri(os);
+    return os;
+  }
+
   // !!! NOTE TO IMPLEMENTOR !!!
   //
   // This class MUST NOT contain any data fields.
@@ -675,13 +651,6 @@
 
 NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(Component);
 
-inline std::ostream&
-operator<<(std::ostream& os, const Component& component)
-{
-  component.toUri(os);
-  return os;
-}
-
 } // namespace name
 } // namespace ndn
 
diff --git a/ndn-cxx/name.hpp b/ndn-cxx/name.hpp
index 0ce98a4..cbb33bd 100644
--- a/ndn-cxx/name.hpp
+++ b/ndn-cxx/name.hpp
@@ -535,6 +535,46 @@
   compare(size_t pos1, size_t count1,
           const Name& other, size_t pos2 = 0, size_t count2 = npos) const;
 
+private: // non-member operators
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
+
+  friend bool
+  operator==(const Name& lhs, const Name& rhs)
+  {
+    return lhs.equals(rhs);
+  }
+
+  friend bool
+  operator!=(const Name& lhs, const Name& rhs)
+  {
+    return !lhs.equals(rhs);
+  }
+
+  friend bool
+  operator<(const Name& lhs, const Name& rhs)
+  {
+    return lhs.compare(rhs) < 0;
+  }
+
+  friend bool
+  operator<=(const Name& lhs, const Name& rhs)
+  {
+    return lhs.compare(rhs) <= 0;
+  }
+
+  friend bool
+  operator>(const Name& lhs, const Name& rhs)
+  {
+    return lhs.compare(rhs) > 0;
+  }
+
+  friend bool
+  operator>=(const Name& lhs, const Name& rhs)
+  {
+    return lhs.compare(rhs) >= 0;
+  }
+
 public:
   /** @brief indicates "until the end" in getSubName and compare
    */
@@ -546,42 +586,6 @@
 
 NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(Name);
 
-inline bool
-operator==(const Name& lhs, const Name& rhs)
-{
-  return lhs.equals(rhs);
-}
-
-inline bool
-operator!=(const Name& lhs, const Name& rhs)
-{
-  return !lhs.equals(rhs);
-}
-
-inline bool
-operator<=(const Name& lhs, const Name& rhs)
-{
-  return lhs.compare(rhs) <= 0;
-}
-
-inline bool
-operator<(const Name& lhs, const Name& rhs)
-{
-  return lhs.compare(rhs) < 0;
-}
-
-inline bool
-operator>=(const Name& lhs, const Name& rhs)
-{
-  return lhs.compare(rhs) >= 0;
-}
-
-inline bool
-operator>(const Name& lhs, const Name& rhs)
-{
-  return lhs.compare(rhs) > 0;
-}
-
 /** @brief Print URI representation of a name
  *  @sa https://named-data.net/doc/NDN-packet-spec/current/name.html#ndn-uri-scheme
  */
diff --git a/ndn-cxx/net/face-uri.cpp b/ndn-cxx/net/face-uri.cpp
index 65372dd..191ab3c 100644
--- a/ndn-cxx/net/face-uri.cpp
+++ b/ndn-cxx/net/face-uri.cpp
@@ -184,22 +184,6 @@
   return uri;
 }
 
-bool
-FaceUri::operator==(const FaceUri& rhs) const
-{
-  return m_isV6 == rhs.m_isV6 &&
-         m_scheme == rhs.m_scheme &&
-         m_host == rhs.m_host &&
-         m_port == rhs.m_port &&
-         m_path == rhs.m_path;
-}
-
-bool
-FaceUri::operator!=(const FaceUri& rhs) const
-{
-  return !(*this == rhs);
-}
-
 std::string
 FaceUri::toString() const
 {
diff --git a/ndn-cxx/net/face-uri.hpp b/ndn-cxx/net/face-uri.hpp
index d1fed76..1a6f6f6 100644
--- a/ndn-cxx/net/face-uri.hpp
+++ b/ndn-cxx/net/face-uri.hpp
@@ -136,13 +136,6 @@
   std::string
   toString() const;
 
-public: // EqualityComparable concept
-  bool
-  operator==(const FaceUri& rhs) const;
-
-  bool
-  operator!=(const FaceUri& rhs) const;
-
 public: // canonical FaceUri
   /** \return whether a FaceUri of the scheme can be canonized
    */
@@ -175,6 +168,26 @@
            boost::asio::io_service& io,
            time::nanoseconds timeout) const;
 
+private: // non-member operators
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
+
+  friend bool
+  operator==(const FaceUri& lhs, const FaceUri& rhs)
+  {
+    return !(lhs != rhs);
+  }
+
+  friend bool
+  operator!=(const FaceUri& lhs, const FaceUri& rhs)
+  {
+    return lhs.m_isV6 != rhs.m_isV6 ||
+           lhs.m_scheme != rhs.m_scheme ||
+           lhs.m_host != rhs.m_host ||
+           lhs.m_port != rhs.m_port ||
+           lhs.m_path != rhs.m_path;
+  }
+
 private:
   std::string m_scheme;
   std::string m_host;
diff --git a/ndn-cxx/security/signing-info.cpp b/ndn-cxx/security/signing-info.cpp
index 848bdeb..f4ef2c5 100644
--- a/ndn-cxx/security/signing-info.cpp
+++ b/ndn-cxx/security/signing-info.cpp
@@ -185,14 +185,5 @@
   return os;
 }
 
-bool
-SigningInfo::operator==(const SigningInfo& rhs) const
-{
-  return getSignerType() == rhs.getSignerType() &&
-    getSignerName() == rhs.getSignerName() &&
-    getDigestAlgorithm() == rhs.getDigestAlgorithm() &&
-    getSignatureInfo() == rhs.getSignatureInfo();
-}
-
 } // namespace security
 } // namespace ndn
diff --git a/ndn-cxx/security/signing-info.hpp b/ndn-cxx/security/signing-info.hpp
index 95a0955..ab60b19 100644
--- a/ndn-cxx/security/signing-info.hpp
+++ b/ndn-cxx/security/signing-info.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -231,13 +231,23 @@
   static const Name&
   getDigestSha256Identity();
 
-  bool
-  operator==(const SigningInfo& rhs) const;
+private: // non-member operators
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
 
-  bool
-  operator!=(const SigningInfo& rhs) const
+  friend bool
+  operator==(const SigningInfo& lhs, const SigningInfo& rhs)
   {
-    return !(*this == rhs);
+    return !(lhs != rhs);
+  }
+
+  friend bool
+  operator!=(const SigningInfo& lhs, const SigningInfo& rhs)
+  {
+    return lhs.m_type != rhs.m_type ||
+           lhs.m_name != rhs.m_name ||
+           lhs.m_digestAlgorithm != rhs.m_digestAlgorithm ||
+           lhs.m_info != rhs.m_info;
   }
 
 private:
diff --git a/ndn-cxx/security/v2/additional-description.cpp b/ndn-cxx/security/v2/additional-description.cpp
index d885cca..9c03758 100644
--- a/ndn-cxx/security/v2/additional-description.cpp
+++ b/ndn-cxx/security/v2/additional-description.cpp
@@ -162,32 +162,17 @@
   }
 }
 
-bool
-AdditionalDescription::operator==(const AdditionalDescription& other) const
-{
-  return (m_info == other.m_info);
-}
-
-bool
-AdditionalDescription::operator!=(const AdditionalDescription& other) const
-{
-  return !(*this == other);
-}
-
 std::ostream&
-operator<<(std::ostream& os, const AdditionalDescription& other)
+operator<<(std::ostream& os, const AdditionalDescription& desc)
 {
-  size_t count = 0;
-  os << "(";
-  for (const auto& entry : other) {
-    if (count > 0)
-      os << ", ";
-    os << "(" << entry.first << ":" << entry.second << ")";
-    count++;
-  }
-  os << ")";
+  os << "[";
 
-  return os;
+  auto join = make_ostream_joiner(os, ", ");
+  for (const auto& entry : desc) {
+    join = "(" + entry.first + ":" + entry.second + ")";
+  }
+
+  return os << "]";
 }
 
 } // namespace v2
diff --git a/ndn-cxx/security/v2/additional-description.hpp b/ndn-cxx/security/v2/additional-description.hpp
index 0523712..5057ed5 100644
--- a/ndn-cxx/security/v2/additional-description.hpp
+++ b/ndn-cxx/security/v2/additional-description.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -110,12 +110,21 @@
   void
   wireDecode(const Block& wire);
 
-public: // EqualityComparable concept
-  bool
-  operator==(const AdditionalDescription& other) const;
+private: // EqualityComparable concept
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
 
-  bool
-  operator!=(const AdditionalDescription& other) const;
+  friend bool
+  operator==(const AdditionalDescription& lhs, const AdditionalDescription& rhs)
+  {
+    return lhs.m_info == rhs.m_info;
+  }
+
+  friend bool
+  operator!=(const AdditionalDescription& lhs, const AdditionalDescription& rhs)
+  {
+    return lhs.m_info != rhs.m_info;
+  }
 
 private:
   std::map<std::string, std::string> m_info;
@@ -126,7 +135,7 @@
 NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(AdditionalDescription);
 
 std::ostream&
-operator<<(std::ostream& os, const AdditionalDescription& period);
+operator<<(std::ostream& os, const AdditionalDescription& desc);
 
 } // namespace v2
 
diff --git a/ndn-cxx/security/validity-period.cpp b/ndn-cxx/security/validity-period.cpp
index 435056c..554d2c1 100644
--- a/ndn-cxx/security/validity-period.cpp
+++ b/ndn-cxx/security/validity-period.cpp
@@ -149,19 +149,6 @@
   return m_notBefore <= now && now <= m_notAfter;
 }
 
-bool
-ValidityPeriod::operator==(const ValidityPeriod& other) const
-{
-  return (this->m_notBefore == other.m_notBefore &&
-          this->m_notAfter == other.m_notAfter);
-}
-
-bool
-ValidityPeriod::operator!=(const ValidityPeriod& other) const
-{
-  return !(*this == other);
-}
-
 std::ostream&
 operator<<(std::ostream& os, const ValidityPeriod& period)
 {
diff --git a/ndn-cxx/security/validity-period.hpp b/ndn-cxx/security/validity-period.hpp
index 073b1f4..7249ade 100644
--- a/ndn-cxx/security/validity-period.hpp
+++ b/ndn-cxx/security/validity-period.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -105,12 +105,22 @@
   void
   wireDecode(const Block& wire);
 
-public: // EqualityComparable concept
-  bool
-  operator==(const ValidityPeriod& other) const;
+private: // EqualityComparable concept
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
 
-  bool
-  operator!=(const ValidityPeriod& other) const;
+  friend bool
+  operator==(const ValidityPeriod& lhs, const ValidityPeriod& rhs)
+  {
+    return !(lhs != rhs);
+  }
+
+  friend bool
+  operator!=(const ValidityPeriod& lhs, const ValidityPeriod& rhs)
+  {
+    return lhs.m_notBefore != rhs.m_notBefore ||
+           lhs.m_notAfter != rhs.m_notAfter;
+  }
 
 private:
   typedef boost::chrono::time_point<time::system_clock, time::seconds> TimePoint;
diff --git a/ndn-cxx/util/scheduler.cpp b/ndn-cxx/util/scheduler.cpp
index f930810..e2e58bf 100644
--- a/ndn-cxx/util/scheduler.cpp
+++ b/ndn-cxx/util/scheduler.cpp
@@ -63,13 +63,6 @@
   return sp != nullptr && !sp->isExpired;
 }
 
-bool
-EventId::operator==(const EventId& other) const noexcept
-{
-  return (!*this && !other) ||
-         !(m_info.owner_before(other.m_info) || other.m_info.owner_before(m_info));
-}
-
 void
 EventId::reset() noexcept
 {
diff --git a/ndn-cxx/util/scheduler.hpp b/ndn-cxx/util/scheduler.hpp
index ae69cc6..7a2c2f3 100644
--- a/ndn-cxx/util/scheduler.hpp
+++ b/ndn-cxx/util/scheduler.hpp
@@ -71,18 +71,6 @@
   explicit
   operator bool() const noexcept;
 
-  /** \brief Determine whether this and other refer to the same event, or are both
-   *         empty/expired/cancelled.
-   */
-  bool
-  operator==(const EventId& other) const noexcept;
-
-  bool
-  operator!=(const EventId& other) const noexcept
-  {
-    return !this->operator==(other);
-  }
-
   /** \brief Clear this EventId without canceling.
    *  \post !(*this)
    */
@@ -90,6 +78,27 @@
   reset() noexcept;
 
 private:
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
+
+  /** \brief Determine whether this and other refer to the same event, or are both
+   *         empty/expired/cancelled.
+   */
+  friend bool
+  operator==(const EventId& lhs, const EventId& rhs) noexcept
+  {
+    return (!lhs && !rhs) ||
+        (!lhs.m_info.owner_before(rhs.m_info) &&
+         !rhs.m_info.owner_before(lhs.m_info));
+  }
+
+  friend bool
+  operator!=(const EventId& lhs, const EventId& rhs) noexcept
+  {
+    return !(lhs == rhs);
+  }
+
+private:
   EventId(Scheduler& sched, weak_ptr<EventInfo> info);
 
 private:
diff --git a/ndn-cxx/util/signal/connection.cpp b/ndn-cxx/util/signal/connection.cpp
index 94d3cbd..1eb6a08 100644
--- a/ndn-cxx/util/signal/connection.cpp
+++ b/ndn-cxx/util/signal/connection.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -27,7 +27,7 @@
 
 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Connection>));
 
-Connection::Connection(weak_ptr<function<void()>> disconnect) noexcept
+Connection::Connection(weak_ptr<DisconnectFunction> disconnect) noexcept
   : m_disconnect(std::move(disconnect))
 {
 }
@@ -41,26 +41,6 @@
   }
 }
 
-bool
-Connection::isConnected() const noexcept
-{
-  return !m_disconnect.expired();
-}
-
-bool
-Connection::operator==(const Connection& other) const
-{
-  auto f1 = m_disconnect.lock();
-  auto f2 = other.m_disconnect.lock();
-  return f1 == f2;
-}
-
-bool
-Connection::operator!=(const Connection& other) const
-{
-  return !(this->operator==(other));
-}
-
 } // namespace signal
 } // namespace util
 } // namespace ndn
diff --git a/ndn-cxx/util/signal/connection.hpp b/ndn-cxx/util/signal/connection.hpp
index a5aabbe..01bce60 100644
--- a/ndn-cxx/util/signal/connection.hpp
+++ b/ndn-cxx/util/signal/connection.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -28,6 +28,8 @@
 namespace util {
 namespace signal {
 
+using DisconnectFunction = std::function<void()>;
+
 /** \brief represents a connection to a signal
  *  \note This type is copyable. Any copy can be used to disconnect.
  */
@@ -47,30 +49,44 @@
   disconnect();
 
   /** \brief check if connected to the signal
-   *  \return false if disconnected from the signal
    */
   bool
-  isConnected() const noexcept;
+  isConnected() const noexcept
+  {
+    return !m_disconnect.expired();
+  }
+
+private:
+  /** \param disconnect weak_ptr to a function that disconnects the handler
+   */
+  explicit
+  Connection(weak_ptr<DisconnectFunction> disconnect) noexcept;
+
+  template<typename Owner, typename ...TArgs>
+  friend class Signal;
+
+private:
+  // NOTE: the following "hidden friend" operators are available via
+  //       argument-dependent lookup only and must be defined inline.
 
   /** \brief compare for equality
    *
    *  Two connections are equal if they both refer to the same connection that isn't disconnected,
    *  or they are both disconnected.
    */
-  bool
-  operator==(const Connection& other) const;
+  friend bool
+  operator==(const Connection& lhs, const Connection& rhs) noexcept
+  {
+    return (!lhs.isConnected() && !rhs.isConnected()) ||
+        (!lhs.m_disconnect.owner_before(rhs.m_disconnect) &&
+         !rhs.m_disconnect.owner_before(lhs.m_disconnect));
+  }
 
-  bool
-  operator!=(const Connection& other) const;
-
-private:
-  /** \param disconnect weak_ptr to a function that disconnects the handler
-   */
-  explicit
-  Connection(weak_ptr<function<void()>> disconnect) noexcept;
-
-  template<typename Owner, typename ...TArgs>
-  friend class Signal;
+  friend bool
+  operator!=(const Connection& lhs, const Connection& rhs) noexcept
+  {
+    return !(lhs == rhs);
+  }
 
 private:
   /** \note The only shared_ptr to the disconnect function is stored in Signal<..>::Slot,
@@ -80,7 +96,7 @@
    *        because the disconnect function is bound with an iterator to the Slot,
    *        which is invalidated when the Slot is erased.
    */
-  weak_ptr<function<void()>> m_disconnect;
+  weak_ptr<DisconnectFunction> m_disconnect;
 };
 
 } // namespace signal
diff --git a/ndn-cxx/util/signal/signal.hpp b/ndn-cxx/util/signal/signal.hpp
index 0de476a..fe2aee5 100644
--- a/ndn-cxx/util/signal/signal.hpp
+++ b/ndn-cxx/util/signal/signal.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -100,13 +100,6 @@
 
 private: // internal implementation
   typedef Signal<Owner, TArgs...> Self;
-  struct Slot;
-
-  /** \brief stores slots
-   *  \note std::list is used because iterators must not be invalidated
-   *        when other slots are added or removed
-   */
-  typedef std::list<Slot> SlotList;
 
   /** \brief stores a handler function, and a function to disconnect this handler
    */
@@ -126,11 +119,14 @@
      *  When the slot is erased or the signal is destructed, this function object is
      *  destructed, and the related Connections cannot disconnect this slot again.
      */
-    shared_ptr<function<void()>> disconnect;
+    shared_ptr<DisconnectFunction> disconnect;
   };
 
   /** \brief stores slots
+   *  \note std::list is used because iterators must not be invalidated
+   *        when other slots are added or removed
    */
+  typedef std::list<Slot> SlotList;
   SlotList m_slots;
 
   /** \brief is a signal handler executing?
@@ -165,9 +161,9 @@
 Signal<Owner, TArgs...>::connect(Handler handler)
 {
   auto it = m_slots.insert(m_slots.end(), {std::move(handler), nullptr});
-  it->disconnect = make_shared<function<void()>>([=] { disconnect(it); });
+  it->disconnect = make_shared<DisconnectFunction>([=] { disconnect(it); });
 
-  return signal::Connection(weak_ptr<function<void()>>(it->disconnect));
+  return signal::Connection(it->disconnect);
 }
 
 template<typename Owner, typename ...TArgs>
@@ -175,8 +171,8 @@
 Signal<Owner, TArgs...>::connectSingleShot(Handler handler)
 {
   auto it = m_slots.insert(m_slots.end(), {nullptr, nullptr});
-  it->disconnect = make_shared<function<void()>>([=] { disconnect(it); });
-  signal::Connection conn(weak_ptr<function<void()>>(it->disconnect));
+  it->disconnect = make_shared<DisconnectFunction>([=] { disconnect(it); });
+  signal::Connection conn(it->disconnect);
 
   it->handler = [conn, handler = std::move(handler)] (const TArgs&... args) mutable {
     handler(args...);
diff --git a/tests/unit/security/v2/additional-description.t.cpp b/tests/unit/security/v2/additional-description.t.cpp
index 2ed09f9..86a3a90 100644
--- a/tests/unit/security/v2/additional-description.t.cpp
+++ b/tests/unit/security/v2/additional-description.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2019 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -44,7 +44,7 @@
         0x76, 0x61, 0x6c, 0x32, // "val2"
 };
 
-const std::string text = "((key1:val1), (key2:val2))";
+const std::string text = "[(key1:val1), (key2:val2)]";
 
 BOOST_AUTO_TEST_CASE(Basic)
 {
diff --git a/tests/unit/util/scheduler.t.cpp b/tests/unit/util/scheduler.t.cpp
index 3c13c70..d403a7c 100644
--- a/tests/unit/util/scheduler.t.cpp
+++ b/tests/unit/util/scheduler.t.cpp
@@ -222,23 +222,31 @@
   BOOST_CHECK(!eid);
 }
 
-BOOST_AUTO_TEST_CASE(Compare)
+BOOST_AUTO_TEST_CASE(Equality)
 {
   EventId eid, eid2;
-  BOOST_CHECK_EQUAL(eid == eid2, true);
-  BOOST_CHECK_EQUAL(eid != eid2, false);
+  BOOST_CHECK(eid == eid2);
 
   eid = scheduler.schedule(10_ms, []{});
-  BOOST_CHECK_EQUAL(eid == eid2, false);
-  BOOST_CHECK_EQUAL(eid != eid2, true);
-
-  eid2 = eid;
-  BOOST_CHECK_EQUAL(eid, eid2);
-  BOOST_CHECK_EQUAL(eid != eid2, false);
+  BOOST_CHECK(eid != eid2);
 
   eid2 = scheduler.schedule(10_ms, []{});
-  BOOST_CHECK_EQUAL(eid == eid2, false);
-  BOOST_CHECK_NE(eid, eid2);
+  BOOST_CHECK(eid != eid2);
+
+  eid.cancel();
+  BOOST_CHECK(eid != eid2);
+  BOOST_CHECK(eid == EventId{});
+
+  eid2.cancel();
+  BOOST_CHECK(eid == eid2);
+
+  eid = eid2 = scheduler.schedule(20_ms, []{});
+  BOOST_CHECK(eid == eid2);
+  BOOST_CHECK(eid != EventId{});
+
+  eid.cancel();
+  BOOST_CHECK(eid == eid2);
+  BOOST_CHECK(eid == EventId{});
 }
 
 BOOST_AUTO_TEST_CASE(Valid)
diff --git a/tests/unit/util/signal.t.cpp b/tests/unit/util/signal.t.cpp
index f0eb192..2c53336 100644
--- a/tests/unit/util/signal.t.cpp
+++ b/tests/unit/util/signal.t.cpp
@@ -444,6 +444,35 @@
   BOOST_CHECK_EQUAL(hit, 2); // handler called
 }
 
+BOOST_AUTO_TEST_CASE(ConnectionEquality)
+{
+  SignalOwner0 so;
+
+  Connection conn1, conn2;
+  BOOST_CHECK(conn1 == conn2);
+
+  conn1 = so.sig.connect([]{});
+  BOOST_CHECK(conn1 != conn2);
+
+  conn2 = so.sig.connect([]{});
+  BOOST_CHECK(conn1 != conn2);
+
+  conn1.disconnect();
+  BOOST_CHECK(conn1 != conn2);
+  BOOST_CHECK(conn1 == Connection{});
+
+  conn2.disconnect();
+  BOOST_CHECK(conn1 == conn2);
+
+  conn1 = conn2 = so.sig.connect([]{});
+  BOOST_CHECK(conn1 == conn2);
+  BOOST_CHECK(conn1 != Connection{});
+
+  conn1.disconnect();
+  BOOST_CHECK(conn1 == conn2);
+  BOOST_CHECK(conn1 == Connection{});
+}
+
 BOOST_AUTO_TEST_SUITE_END() // TestSignal
 BOOST_AUTO_TEST_SUITE_END() // Util