encoding: declare Block operators as hidden friends

Change-Id: Ib6a0792110cb1627e691c66bf83adf27df065c46
diff --git a/ndn-cxx/encoding/block.cpp b/ndn-cxx/encoding/block.cpp
index 358871d..c7ed7b8 100644
--- a/ndn-cxx/encoding/block.cpp
+++ b/ndn-cxx/encoding/block.cpp
@@ -25,8 +25,11 @@
 #include "ndn-cxx/encoding/buffer-stream.hpp"
 #include "ndn-cxx/encoding/encoding-buffer.hpp"
 #include "ndn-cxx/encoding/tlv.hpp"
-#include "ndn-cxx/security/transform.hpp"
+#include "ndn-cxx/security/transform/hex-decode.hpp"
+#include "ndn-cxx/security/transform/step-source.hpp"
+#include "ndn-cxx/security/transform/stream-sink.hpp"
 #include "ndn-cxx/util/ostream-joiner.hpp"
+#include "ndn-cxx/util/scope.hpp"
 #include "ndn-cxx/util/string-helper.hpp"
 
 #include <boost/asio/buffer.hpp>
@@ -478,41 +481,44 @@
 }
 
 bool
-operator==(const Block& lhs, const Block& rhs) noexcept
+Block::equals(const Block& other) const noexcept
 {
-  return lhs.type() == rhs.type() &&
-         lhs.value_size() == rhs.value_size() &&
-         (lhs.value_size() == 0 ||
-          std::memcmp(lhs.value(), rhs.value(), lhs.value_size()) == 0);
+  return type() == other.type() &&
+         value_size() == other.value_size() &&
+         (value_size() == 0 ||
+          std::equal(value_begin(), value_end(), other.value_begin()));
 }
 
-std::ostream&
-operator<<(std::ostream& os, const Block& block)
+void
+Block::print(std::ostream& os) const
 {
-  auto oldFmt = os.flags(std::ios_base::dec);
+  auto oldFlags = os.flags(std::ios_base::dec);
+  auto restoreFlags = make_scope_exit([&] {
+    os.flags(oldFlags);
+  });
 
-  if (!block.isValid()) {
+  if (!isValid()) {
     os << "[invalid]";
   }
-  else if (!block.m_elements.empty()) {
+  else if (!m_elements.empty()) {
     EncodingEstimator estimator;
-    size_t tlvLength = block.encodeValue(estimator);
-    os << block.type() << '[' << tlvLength << "]={";
-    std::copy(block.elements_begin(), block.elements_end(), make_ostream_joiner(os, ','));
+    size_t tlvLength = encodeValue(estimator);
+    os << type() << '[' << tlvLength << "]={";
+    std::copy(elements_begin(), elements_end(), make_ostream_joiner(os, ','));
     os << '}';
   }
-  else if (block.value_size() > 0) {
-    os << block.type() << '[' << block.value_size() << "]=";
-    printHex(os, block.value_bytes(), true);
+  else if (value_size() > 0) {
+    os << type() << '[' << value_size() << "]=";
+    printHex(os, value_bytes(), true);
   }
   else {
-    os << block.type() << "[empty]";
+    os << type() << "[empty]";
   }
-
-  os.flags(oldFmt);
-  return os;
 }
 
+inline namespace literals {
+inline namespace block_literals {
+
 Block
 operator ""_block(const char* input, std::size_t len)
 {
@@ -537,4 +543,6 @@
   return Block(os.buf());
 }
 
+} // inline namespace block_literals
+} // inline namespace literals
 } // namespace ndn
diff --git a/ndn-cxx/encoding/block.hpp b/ndn-cxx/encoding/block.hpp
index f43d085..0aa4f7f 100644
--- a/ndn-cxx/encoding/block.hpp
+++ b/ndn-cxx/encoding/block.hpp
@@ -221,20 +221,30 @@
     return m_buffer != nullptr && m_begin != m_end;
   }
 
-  /** @brief Get begin iterator of encoded wire
-   *  @pre `hasWire() == true`
+  /**
+   * @brief Returns an iterator to the beginning of the encoded wire.
+   * @pre `hasWire() == true`
    */
   const_iterator
   begin() const;
 
-  /** @brief Get end iterator of encoded wire
-   *  @pre `hasWire() == true`
+  /**
+   * @brief Returns an iterator past-the-end of the encoded wire.
+   * @pre `hasWire() == true`
    */
   const_iterator
   end() const;
 
   /**
-   * @brief Return a raw pointer to the beginning of the encoded wire
+   * @brief Returns the size of the encoded wire, i.e., of the whole TLV.
+   * @pre `isValid() == true`
+   * @sa value_size()
+   */
+  size_t
+  size() const;
+
+  /**
+   * @brief Returns a raw pointer to the beginning of the encoded wire, i.e., the whole TLV.
    * @pre `hasWire() == true`
    * @sa value()
    */
@@ -252,14 +262,7 @@
   }
 
   /**
-   * @brief Return the size of the encoded wire, i.e., of the whole TLV
-   * @pre `isValid() == true`
-   * @sa value_size()
-   */
-  size_t
-  size() const;
-
-  /** @brief Get underlying buffer
+   * @brief Returns the underlying buffer.
    */
   ConstBufferPtr
   getBuffer() const
@@ -269,7 +272,7 @@
 
 public: // type and value
   /**
-   * @brief Return the TLV-TYPE of the Block
+   * @brief Return the TLV-TYPE of the Block.
    * @note This will return tlv::Invalid if isValid() is false.
    */
   uint32_t
@@ -279,7 +282,7 @@
   }
 
   /**
-   * @brief Check if the Block has a non-empty TLV-VALUE
+   * @brief Check if the Block has a non-empty TLV-VALUE.
    *
    * This property reflects whether the underlying buffer contains a TLV-VALUE. If this is false,
    * TLV-VALUE has zero-length. If this is true, TLV-VALUE may be zero-length.
@@ -293,7 +296,7 @@
   }
 
   /**
-   * @brief Get begin iterator of TLV-VALUE
+   * @brief Get begin iterator of TLV-VALUE.
    * @pre `hasValue() == true`
    */
   const_iterator
@@ -303,7 +306,7 @@
   }
 
   /**
-   * @brief Get end iterator of TLV-VALUE
+   * @brief Get end iterator of TLV-VALUE.
    * @pre `hasValue() == true`
    */
   const_iterator
@@ -313,7 +316,7 @@
   }
 
   /**
-   * @brief Return the size of TLV-VALUE, i.e., the TLV-LENGTH
+   * @brief Return the size of TLV-VALUE, i.e., the TLV-LENGTH.
    * @sa size()
    */
   size_t
@@ -323,7 +326,7 @@
   }
 
   /**
-   * @brief Return a read-only view of TLV-VALUE as a contiguous range of bytes
+   * @brief Return a read-only view of TLV-VALUE as a contiguous range of bytes.
    */
   span<const uint8_t>
   value_bytes() const noexcept
@@ -335,14 +338,14 @@
   }
 
   /**
-   * @brief Return a raw pointer to the beginning of TLV-VALUE
+   * @brief Return a raw pointer to the beginning of TLV-VALUE.
    * @sa value_bytes(), data()
    */
   const uint8_t*
   value() const noexcept;
 
   /**
-   * @brief Return a new Block constructed from the TLV-VALUE of this Block
+   * @brief Return a new Block constructed from the TLV-VALUE of this Block.
    * @pre `value_size() > 0`
    */
   Block
@@ -460,24 +463,73 @@
    */
   operator boost::asio::const_buffer() const;
 
+protected:
+  /**
+   * @brief Returns whether this Block has the same TLV-TYPE/TLV-LENGTH/TLV-VALUE as @p other.
+   */
+  bool
+  equals(const Block& other) const noexcept;
+
 private:
-  /** @brief Estimate Block size as if sub-elements are encoded into TLV-VALUE
+  /**
+   * @brief Estimate Block size as if sub-elements are encoded into TLV-VALUE.
    */
   size_t
   encode(EncodingEstimator& estimator) const;
 
-  /** @brief Estimate TLV-LENGTH as if sub-elements are encoded into TLV-VALUE
+  /**
+   * @brief Estimate TLV-LENGTH as if sub-elements are encoded into TLV-VALUE.
    */
   size_t
   encodeValue(EncodingEstimator& estimator) const;
 
-  /** @brief Encode sub-elements into TLV-VALUE and prepend Block to encoder
-   *  @post TLV-VALUE contains sub-elements from elements()
-   *  @post internal buffer and iterators point to Encoder's buffer
+  /**
+   * @brief Encode sub-elements into TLV-VALUE and prepend Block to encoder.
+   * @post TLV-VALUE contains sub-elements from elements()
+   * @post internal buffer and iterators point to Encoder's buffer
    */
   size_t
   encode(EncodingBuffer& encoder);
 
+  void
+  print(std::ostream& os) const;
+
+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 Blocks have the same TLV-TYPE, TLV-LENGTH, and TLV-VALUE.
+   */
+  friend bool
+  operator==(const Block& lhs, const Block& rhs) noexcept
+  {
+    return lhs.equals(rhs);
+  }
+
+  friend bool
+  operator!=(const Block& lhs, const Block& rhs) noexcept
+  {
+    return !lhs.equals(rhs);
+  }
+
+  /**
+   * @brief Print @p block to @p os.
+   *
+   * Default-constructed Block is printed as: `[invalid]`.
+   * Zero-length Block is printed as: `TT[empty]`, where TT is TLV-TYPE in decimal.
+   * Non-zero-length Block on which parse() has not been called is printed as: `TT[LL]=VVVV`,
+   * where LL is TLV-LENGTH in decimal, and VVVV is TLV-VALUE in hexadecimal.
+   * Block on which parse() has been called is printed as: `TT[LL]={SUB,SUB}`,
+   * where each SUB is a sub-element printed using this format.
+   */
+  friend std::ostream&
+  operator<<(std::ostream& os, const Block& block)
+  {
+    block.print(os);
+    return os;
+  }
+
 protected:
   /** @brief Underlying buffer storing TLV-VALUE and possibly TLV-TYPE and TLV-LENGTH fields
    *
@@ -509,19 +561,6 @@
    * This field is valid only if parse() has been called on the Block instance.
    */
   mutable element_container m_elements;
-
-  /**
-   * @brief Print @p block to @p os.
-   *
-   * Default-constructed Block is printed as: `[invalid]`.
-   * Zero-length Block is printed as: `TT[empty]`, where TT is TLV-TYPE in decimal.
-   * Non-zero-length Block on which parse() has not been called is printed as: `TT[LL]=VVVV`,
-   * where LL is TLV-LENGTH in decimal, and VVVV is TLV-VALUE in hexadecimal.
-   * Block on which parse() has been called is printed as: `TT[LL]={SUB,SUB}`,
-   * where each SUB is a sub-element printed using this format.
-   */
-  friend std::ostream&
-  operator<<(std::ostream& os, const Block& block);
 };
 
 inline
@@ -530,17 +569,8 @@
 inline Block&
 Block::operator=(Block&&) noexcept = default;
 
-/**
- * @brief Compare whether two Blocks have the same TLV-TYPE, TLV-LENGTH, and TLV-VALUE.
- */
-bool
-operator==(const Block& lhs, const Block& rhs) noexcept;
-
-inline bool
-operator!=(const Block& lhs, const Block& rhs) noexcept
-{
-  return !(lhs == rhs);
-}
+inline namespace literals {
+inline namespace block_literals {
 
 /** @brief Construct a Block from hexadecimal @p input.
  *  @param input a string containing hexadecimal bytes and comments.
@@ -558,6 +588,8 @@
 Block
 operator ""_block(const char* input, std::size_t len);
 
+} // inline namespace block_literals
+} // inline namespace literals
 } // namespace ndn
 
 #endif // NDN_CXX_ENCODING_BLOCK_HPP
diff --git a/ndn-cxx/name-component.cpp b/ndn-cxx/name-component.cpp
index 964353e..9092271 100644
--- a/ndn-cxx/name-component.cpp
+++ b/ndn-cxx/name-component.cpp
@@ -425,14 +425,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool
-Component::equals(const Component& other) const noexcept
-{
-  return type() == other.type() &&
-         value_size() == other.value_size() &&
-         std::equal(value_begin(), value_end(), other.value_begin());
-}
-
 int
 Component::compare(const Component& other) const
 {
diff --git a/ndn-cxx/name-component.hpp b/ndn-cxx/name-component.hpp
index 9b245c1..5870bb8 100644
--- a/ndn-cxx/name-component.hpp
+++ b/ndn-cxx/name-component.hpp
@@ -135,19 +135,21 @@
 
   /**
    * @brief Construct a NameComponent of TLV-TYPE @p type, using TLV-VALUE from @p buffer.
-   * @throw Error the NameComponent is invalid.
    *
    * This constructor does not copy the underlying buffer, but retains a pointer to it.
    * Therefore, the caller must not change the underlying buffer.
+   *
+   * @throw Error the NameComponent is invalid.
    */
   Component(uint32_t type, ConstBufferPtr buffer);
 
   /**
    * @brief Construct a GenericNameComponent, using TLV-VALUE from @p buffer.
-   * @throw Error the NameComponent is invalid.
    *
    * This constructor does not copy the underlying buffer, but retains a pointer to it.
    * Therefore, the caller must not change the underlying buffer.
+   *
+   * @throw Error the NameComponent is invalid.
    */
   explicit
   Component(ConstBufferPtr buffer)
@@ -480,16 +482,18 @@
   }
 
   /**
-   * @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.
+   * @brief Check whether this is the same component as @p other.
+   * @param other The name component to compare with
+   * @return true if the components are equal, false otherwise.
    */
   bool
-  equals(const Component& other) const noexcept;
+  equals(const Component& other) const noexcept
+  {
+    return Block::equals(other);
+  }
 
   /**
-   * @brief Compare this to the other Component using NDN canonical ordering
+   * @brief Compare this to the other Component using NDN canonical ordering.
    *
    * @param other The other Component to compare with.
    * @retval negative this comes before other in canonical ordering
diff --git a/ndn-cxx/security/certificate.cpp b/ndn-cxx/security/certificate.cpp
index ac74913..37f2e58 100644
--- a/ndn-cxx/security/certificate.cpp
+++ b/ndn-cxx/security/certificate.cpp
@@ -24,7 +24,10 @@
 
 #include "ndn-cxx/security/certificate.hpp"
 #include "ndn-cxx/security/additional-description.hpp"
-#include "ndn-cxx/security/transform.hpp"
+#include "ndn-cxx/security/transform/base64-encode.hpp"
+#include "ndn-cxx/security/transform/buffer-source.hpp"
+#include "ndn-cxx/security/transform/public-key.hpp"
+#include "ndn-cxx/security/transform/stream-sink.hpp"
 #include "ndn-cxx/util/indented-stream.hpp"
 
 namespace ndn::security {
diff --git a/ndn-cxx/security/tpm/impl/back-end-file.cpp b/ndn-cxx/security/tpm/impl/back-end-file.cpp
index 4c466d1..fd4c3a7 100644
--- a/ndn-cxx/security/tpm/impl/back-end-file.cpp
+++ b/ndn-cxx/security/tpm/impl/back-end-file.cpp
@@ -20,10 +20,14 @@
  */
 
 #include "ndn-cxx/security/tpm/impl/back-end-file.hpp"
-#include "ndn-cxx/security/tpm/impl/key-handle-mem.hpp"
-#include "ndn-cxx/security/transform.hpp"
-#include "ndn-cxx/security/transform/private-key.hpp"
+
 #include "ndn-cxx/encoding/buffer-stream.hpp"
+#include "ndn-cxx/security/tpm/impl/key-handle-mem.hpp"
+#include "ndn-cxx/security/transform/buffer-source.hpp"
+#include "ndn-cxx/security/transform/digest-filter.hpp"
+#include "ndn-cxx/security/transform/hex-encode.hpp"
+#include "ndn-cxx/security/transform/private-key.hpp"
+#include "ndn-cxx/security/transform/stream-sink.hpp"
 
 #include <cstdlib>
 #include <fstream>
diff --git a/ndn-cxx/util/string-helper.cpp b/ndn-cxx/util/string-helper.cpp
index ef7f85b..b4d9bc2 100644
--- a/ndn-cxx/util/string-helper.cpp
+++ b/ndn-cxx/util/string-helper.cpp
@@ -20,11 +20,13 @@
  */
 
 #include "ndn-cxx/util/string-helper.hpp"
+
 #include "ndn-cxx/encoding/buffer-stream.hpp"
 #include "ndn-cxx/security/transform/buffer-source.hpp"
 #include "ndn-cxx/security/transform/hex-decode.hpp"
 #include "ndn-cxx/security/transform/hex-encode.hpp"
 #include "ndn-cxx/security/transform/stream-sink.hpp"
+#include "ndn-cxx/util/scope.hpp"
 
 #include <sstream>
 
@@ -33,12 +35,15 @@
 void
 printHex(std::ostream& os, uint64_t num, bool wantUpperCase)
 {
-  auto osFlags = os.flags();
+  auto oldFlags = os.flags();
+  auto restoreFlags = make_scope_exit([&] {
+    os.flags(oldFlags);
+  });
+
   // std::showbase doesn't work with number 0
   os << "0x" << std::noshowbase << std::noshowpos
      << (wantUpperCase ? std::uppercase : std::nouppercase)
      << std::hex << num;
-  os.flags(osFlags);
 }
 
 void