util: backport C++17 [[nodiscard]] attribute

Change-Id: I6bdeeaed09a4a5d36647ec967aead47e4461e583
diff --git a/ndn-cxx/delegation-list.hpp b/ndn-cxx/delegation-list.hpp
index b60b096..0570426 100644
--- a/ndn-cxx/delegation-list.hpp
+++ b/ndn-cxx/delegation-list.hpp
@@ -98,7 +98,7 @@
     return m_dels.end();
   }
 
-  bool
+  NDN_CXX_NODISCARD bool
   empty() const noexcept
   {
     return m_dels.empty();
diff --git a/ndn-cxx/encoding/block.hpp b/ndn-cxx/encoding/block.hpp
index 0cd6867..51f9f4d 100644
--- a/ndn-cxx/encoding/block.hpp
+++ b/ndn-cxx/encoding/block.hpp
@@ -165,7 +165,7 @@
    *  @note This function does not throw upon decoding failure.
    *  @return `true` and the parsed Block if parsing succeeds; otherwise `false` and an invalid Block
    */
-  static std::tuple<bool, Block>
+  NDN_CXX_NODISCARD static std::tuple<bool, Block>
   fromBuffer(ConstBufferPtr buffer, size_t offset);
 
   /** @brief Try to parse Block from a raw buffer
@@ -175,7 +175,7 @@
    *  @note This overload copies the TLV element octets into an internal wire buffer.
    *  @return `true` and the parsed Block if parsing succeeds; otherwise `false` and an invalid Block
    */
-  static std::tuple<bool, Block>
+  NDN_CXX_NODISCARD static std::tuple<bool, Block>
   fromBuffer(const uint8_t* buf, size_t bufSize);
 
 public: // wire format
@@ -197,7 +197,7 @@
    *  @warning Note that an empty Block is *not* the same as a valid but zero-length Block.
    *  @deprecated Use Block::isValid()
    */
-  bool
+  NDN_CXX_NODISCARD bool
   empty() const noexcept
   {
     return !isValid();
diff --git a/ndn-cxx/encoding/tlv.hpp b/ndn-cxx/encoding/tlv.hpp
index 5706e52..a3b6979 100644
--- a/ndn-cxx/encoding/tlv.hpp
+++ b/ndn-cxx/encoding/tlv.hpp
@@ -188,7 +188,7 @@
  * @return true if number was successfully read from input, false otherwise
  */
 template<typename Iterator>
-bool
+NDN_CXX_NODISCARD bool
 readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept;
 
 /**
@@ -205,7 +205,7 @@
  *       the TLV-TYPE is zero or larger than 2^32-1 (maximum allowed by the packet format).
  */
 template<typename Iterator>
-bool
+NDN_CXX_NODISCARD bool
 readType(Iterator& begin, Iterator end, uint32_t& type) noexcept;
 
 /**
diff --git a/ndn-cxx/impl/record-container.hpp b/ndn-cxx/impl/record-container.hpp
index d488393..94b2f5e 100644
--- a/ndn-cxx/impl/record-container.hpp
+++ b/ndn-cxx/impl/record-container.hpp
@@ -172,7 +172,7 @@
     });
   }
 
-  bool
+  NDN_CXX_NODISCARD bool
   empty() const noexcept
   {
     return m_container.empty();
diff --git a/ndn-cxx/interest-filter.hpp b/ndn-cxx/interest-filter.hpp
index 38f9b6b..74b7229 100644
--- a/ndn-cxx/interest-filter.hpp
+++ b/ndn-cxx/interest-filter.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).
  *
@@ -123,7 +123,7 @@
 
   /** \brief Get whether Interest loopback is allowed
    */
-  bool
+  NDN_CXX_NODISCARD bool
   allowsLoopback() const
   {
     return m_allowsLoopback;
diff --git a/ndn-cxx/interest.hpp b/ndn-cxx/interest.hpp
index 432f68c..a127dae 100644
--- a/ndn-cxx/interest.hpp
+++ b/ndn-cxx/interest.hpp
@@ -517,7 +517,7 @@
   void
   setApplicationParametersInternal(Block parameters);
 
-  shared_ptr<Buffer>
+  NDN_CXX_NODISCARD shared_ptr<Buffer>
   computeParametersDigest() const;
 
   /** @brief Append a ParametersSha256DigestComponent to the Interest's name
diff --git a/ndn-cxx/key-locator.hpp b/ndn-cxx/key-locator.hpp
index 417c21d..df12134 100644
--- a/ndn-cxx/key-locator.hpp
+++ b/ndn-cxx/key-locator.hpp
@@ -83,7 +83,7 @@
   wireDecode(const Block& wire);
 
 public: // attributes
-  bool
+  NDN_CXX_NODISCARD bool
   empty() const
   {
     return holds_alternative<monostate>(m_locator);
diff --git a/ndn-cxx/lp/packet.hpp b/ndn-cxx/lp/packet.hpp
index 624a0a5..d3a9766 100644
--- a/ndn-cxx/lp/packet.hpp
+++ b/ndn-cxx/lp/packet.hpp
@@ -58,7 +58,7 @@
    * \retval true packet has no field
    * \retval false packet has one or more fields
    */
-  bool
+  NDN_CXX_NODISCARD bool
   empty() const
   {
     return m_wire.elements_size() == 0;
@@ -70,7 +70,7 @@
    * \details This is equivalent to count() > 0
    */
   template<typename FIELD>
-  bool
+  NDN_CXX_NODISCARD bool
   has() const
   {
     return count<FIELD>() > 0;
@@ -80,7 +80,7 @@
    * \return number of occurrences of FIELD
    */
   template<typename FIELD>
-  size_t
+  NDN_CXX_NODISCARD size_t
   count() const
   {
     return std::count_if(m_wire.elements_begin(), m_wire.elements_end(),
@@ -112,7 +112,7 @@
    * \return values of all occurrences of FIELD
    */
   template<typename FIELD>
-  std::vector<typename FIELD::ValueType>
+  NDN_CXX_NODISCARD std::vector<typename FIELD::ValueType>
   list() const
   {
     std::vector<typename FIELD::ValueType> output;
diff --git a/ndn-cxx/metadata-object.hpp b/ndn-cxx/metadata-object.hpp
index 3639b8e..0403d3e 100644
--- a/ndn-cxx/metadata-object.hpp
+++ b/ndn-cxx/metadata-object.hpp
@@ -76,7 +76,7 @@
    *
    * @throw tlv::Error @p discoveryInterestName is not valid
    */
-  Data
+  NDN_CXX_NODISCARD Data
   makeData(Name discoveryInterestName,
            KeyChain& keyChain,
            const ndn::security::SigningInfo& si = KeyChain::getDefaultSigningInfo(),
@@ -114,7 +114,7 @@
    *
    * @param name prefix of data collection
    */
-  static Interest
+  NDN_CXX_NODISCARD static Interest
   makeDiscoveryInterest(Name name);
 
 private:
diff --git a/ndn-cxx/name-component.hpp b/ndn-cxx/name-component.hpp
index ef06d20..fbea9ac 100644
--- a/ndn-cxx/name-component.hpp
+++ b/ndn-cxx/name-component.hpp
@@ -530,7 +530,7 @@
   fromParametersSha256Digest(const uint8_t* digest, size_t digestSize);
 
 public: // comparison
-  bool
+  NDN_CXX_NODISCARD bool
   empty() const
   {
     return value_size() == 0;
diff --git a/ndn-cxx/name.hpp b/ndn-cxx/name.hpp
index 27859fb..18b1fc3 100644
--- a/ndn-cxx/name.hpp
+++ b/ndn-cxx/name.hpp
@@ -135,7 +135,7 @@
 public: // access
   /** @brief Checks if the name is empty, i.e. has no components.
    */
-  bool
+  NDN_CXX_NODISCARD bool
   empty() const
   {
     return m_wire.elements().empty();
diff --git a/ndn-cxx/net/face-uri.hpp b/ndn-cxx/net/face-uri.hpp
index 1a6f6f6..aeb12c0 100644
--- a/ndn-cxx/net/face-uri.hpp
+++ b/ndn-cxx/net/face-uri.hpp
@@ -66,7 +66,7 @@
   FaceUri(const char* uri);
 
   /// exception-safe parsing
-  bool
+  NDN_CXX_NODISCARD bool
   parse(const std::string& uri);
 
 public: // scheme-specific construction
diff --git a/ndn-cxx/net/network-monitor.hpp b/ndn-cxx/net/network-monitor.hpp
index a28bee2..84ef90c 100644
--- a/ndn-cxx/net/network-monitor.hpp
+++ b/ndn-cxx/net/network-monitor.hpp
@@ -92,7 +92,7 @@
    * @warning May return incomplete results if called before the
    *          #onEnumerationCompleted signal has been emitted.
    */
-  std::vector<shared_ptr<const NetworkInterface>>
+  NDN_CXX_NODISCARD std::vector<shared_ptr<const NetworkInterface>>
   listNetworkInterfaces() const;
 
 protected:
diff --git a/ndn-cxx/security/impl/openssl-helper.hpp b/ndn-cxx/security/impl/openssl-helper.hpp
index 6c7668b..679a694 100644
--- a/ndn-cxx/security/impl/openssl-helper.hpp
+++ b/ndn-cxx/security/impl/openssl-helper.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).
  *
@@ -29,10 +29,10 @@
 namespace security {
 namespace detail {
 
-const EVP_MD*
+NDN_CXX_NODISCARD const EVP_MD*
 digestAlgorithmToEvpMd(DigestAlgorithm algo);
 
-int
+NDN_CXX_NODISCARD int
 getEvpPkeyType(EVP_PKEY* key);
 
 class EvpMdCtx : noncopyable
@@ -90,10 +90,10 @@
     return m_bio;
   }
 
-  bool
+  NDN_CXX_NODISCARD bool
   read(uint8_t* buf, size_t buflen) const noexcept;
 
-  bool
+  NDN_CXX_NODISCARD bool
   write(const uint8_t* buf, size_t buflen) noexcept;
 
 private:
diff --git a/ndn-cxx/security/tpm/back-end.hpp b/ndn-cxx/security/tpm/back-end.hpp
index ab570f2..069bfe1 100644
--- a/ndn-cxx/security/tpm/back-end.hpp
+++ b/ndn-cxx/security/tpm/back-end.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).
  *
@@ -157,7 +157,7 @@
    *
    * @return True if the TPM was unlocked.
    */
-  virtual bool
+  NDN_CXX_NODISCARD virtual bool
   unlockTpm(const char* pw, size_t pwLen) const;
 
 protected: // static helper methods
diff --git a/ndn-cxx/security/tpm/tpm.hpp b/ndn-cxx/security/tpm/tpm.hpp
index 419eae4..5fc6636 100644
--- a/ndn-cxx/security/tpm/tpm.hpp
+++ b/ndn-cxx/security/tpm/tpm.hpp
@@ -147,7 +147,7 @@
    * @param password The password to unlock the TPM.
    * @param passwordLength The password size.
    */
-  bool
+  NDN_CXX_NODISCARD bool
   unlockTpm(const char* password, size_t passwordLength) const;
 
 NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
diff --git a/ndn-cxx/security/transform/private-key.cpp b/ndn-cxx/security/transform/private-key.cpp
index 8ac39d4..570c18c 100644
--- a/ndn-cxx/security/transform/private-key.cpp
+++ b/ndn-cxx/security/transform/private-key.cpp
@@ -360,7 +360,8 @@
     NDN_THROW(Error("Cannot convert key to PKCS #1 format"));
 
   auto buffer = make_shared<Buffer>(BIO_pending(membio));
-  membio.read(buffer->data(), buffer->size());
+  if (!membio.read(buffer->data(), buffer->size()))
+    NDN_THROW(Error("Read error during PKCS #1 conversion"));
 
   return buffer;
 }
@@ -378,7 +379,8 @@
     NDN_THROW(Error("Cannot convert key to PKCS #8 format"));
 
   auto buffer = make_shared<Buffer>(BIO_pending(membio));
-  membio.read(buffer->data(), buffer->size());
+  if (!membio.read(buffer->data(), buffer->size()))
+    NDN_THROW(Error("Read error during PKCS #8 conversion"));
 
   return buffer;
 }
@@ -395,7 +397,8 @@
     NDN_THROW(Error("Cannot convert key to PKCS #8 format"));
 
   auto buffer = make_shared<Buffer>(BIO_pending(membio));
-  membio.read(buffer->data(), buffer->size());
+  if (!membio.read(buffer->data(), buffer->size()))
+    NDN_THROW(Error("Read error during PKCS #8 conversion"));
 
   return buffer;
 }
diff --git a/ndn-cxx/util/backports.hpp b/ndn-cxx/util/backports.hpp
index e87f0e0..22a484e 100644
--- a/ndn-cxx/util/backports.hpp
+++ b/ndn-cxx/util/backports.hpp
@@ -56,6 +56,18 @@
 #  define NDN_CXX_FALLTHROUGH ((void)0)
 #endif
 
+//
+// http://wg21.link/P0189
+// [[nodiscard]] attribute (C++17)
+//
+#if (__cplusplus > 201402L) && NDN_CXX_HAS_CPP_ATTRIBUTE(nodiscard)
+#  define NDN_CXX_NODISCARD [[nodiscard]]
+#elif NDN_CXX_HAS_CPP_ATTRIBUTE(gnu::warn_unused_result)
+#  define NDN_CXX_NODISCARD [[gnu::warn_unused_result]]
+#else
+#  define NDN_CXX_NODISCARD
+#endif
+
 #ifndef NDEBUG
 #  define NDN_CXX_UNREACHABLE BOOST_ASSERT(false)
 #elif BOOST_COMP_GNUC || BOOST_COMP_CLANG
diff --git a/ndn-cxx/util/scheduler.cpp b/ndn-cxx/util/scheduler.cpp
index e2e58bf..9cbe734 100644
--- a/ndn-cxx/util/scheduler.cpp
+++ b/ndn-cxx/util/scheduler.cpp
@@ -38,7 +38,7 @@
   {
   }
 
-  time::nanoseconds
+  NDN_CXX_NODISCARD time::nanoseconds
   expiresFromNow() const
   {
     return std::max(expireTime - time::steady_clock::now(), 0_ns);
diff --git a/ndn-cxx/util/string-helper.hpp b/ndn-cxx/util/string-helper.hpp
index 57c27fb..97973da 100644
--- a/ndn-cxx/util/string-helper.hpp
+++ b/ndn-cxx/util/string-helper.hpp
@@ -125,7 +125,7 @@
  *
  * The output string is a continuous sequence of hex characters without any whitespace separators.
  */
-std::string
+NDN_CXX_NODISCARD std::string
 toHex(const uint8_t* buffer, size_t length, bool wantUpperCase = true);
 
 /**
@@ -134,7 +134,7 @@
  * @param buffer Buffer of bytes to convert to hexadecimal format
  * @param wantUpperCase if true (the default) use uppercase hex chars
  */
-std::string
+NDN_CXX_NODISCARD std::string
 toHex(const Buffer& buffer, bool wantUpperCase = true);
 
 /**
@@ -149,7 +149,7 @@
 /**
  * @brief Convert (the least significant nibble of) @p n to the corresponding hex character
  */
-constexpr char
+NDN_CXX_NODISCARD constexpr char
 toHexChar(unsigned int n, bool wantUpperCase = true) noexcept
 {
   return wantUpperCase ?
@@ -160,7 +160,7 @@
 /**
  * @brief Convert the hex character @p c to an integer in [0, 15], or -1 if it's not a hex character
  */
-constexpr int
+NDN_CXX_NODISCARD constexpr int
 fromHexChar(char c) noexcept
 {
   return (c >= '0' && c <= '9') ? int(c - '0') :
@@ -185,7 +185,7 @@
  * escape("100%") == "100%25"
  * @endcode
  */
-std::string
+NDN_CXX_NODISCARD std::string
 escape(const std::string& str);
 
 void
@@ -204,7 +204,7 @@
  * unescape("hello%20world%FooBar") == "hello world%FooBar"
  * @endcode
  */
-std::string
+NDN_CXX_NODISCARD std::string
 unescape(const std::string& str);
 
 void
diff --git a/tests/unit/encoding/tlv.t.cpp b/tests/unit/encoding/tlv.t.cpp
index 1810f01..478fd83 100644
--- a/tests/unit/encoding/tlv.t.cpp
+++ b/tests/unit/encoding/tlv.t.cpp
@@ -106,9 +106,10 @@
 {
   boost::input_iterator_archetype<uint8_t> begin, end;
   uint64_t number = readVarNumber(begin, end);
-  uint32_t type = readType(begin, end);;
-  readVarNumber(begin, end, number);
-  readType(begin, end, type);
+  uint32_t type = readType(begin, end);
+  bool ok = readVarNumber(begin, end, number);
+  ok = readType(begin, end, type);
+  static_cast<void>(ok);
 }
 
 static const uint8_t BUFFER[] = {