encoding: avoid misaligned memory accesses in TLV decoding

ndn::tlv::readVarNumber and ndn::tlv::readNonNegativeInteger
now properly support InputIterator, and have efficient
implementations for ContiguousIterator that do not rely on
unsafe misaligned memory accesses.

refs #4172, #4097

Change-Id: Ib02b8d908ad5cfec474679b5b3b5ccd95ba07549
diff --git a/src/encoding/tlv.hpp b/src/encoding/tlv.hpp
index 876fcb5..4e9c009 100644
--- a/src/encoding/tlv.hpp
+++ b/src/encoding/tlv.hpp
@@ -25,6 +25,7 @@
 #include "buffer.hpp"
 #include "endian.hpp"
 
+#include <cstring>
 #include <iostream>
 #include <iterator>
 
@@ -138,7 +139,7 @@
 
 /**
  * @brief Read VAR-NUMBER in NDN-TLV encoding
- * @tparam InputIterator an iterator or pointer dereferencable to uint8_t
+ * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
  *
  * @param [inout] begin  Begin of the buffer, will be incremented to point to the first byte after
  *                       the read VAR-NUMBER
@@ -148,13 +149,13 @@
  * @return true if number was successfully read from input, false otherwise
  * @note This call never throws exceptions
  */
-template<class InputIterator>
+template<typename Iterator>
 bool
-readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
+readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number);
 
 /**
  * @brief Read TLV-TYPE
- * @tparam InputIterator an iterator or pointer dereferencable to uint8_t
+ * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
  *
  * @param [inout] begin  Begin of the buffer, will be incremented to point to the first byte after
  *                       the read TLV-TYPE
@@ -166,13 +167,13 @@
  * @note This call is largely equivalent to tlv::readVarNumber, but it will return false if type
  *       is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
  */
-template<class InputIterator>
+template<typename Iterator>
 bool
-readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
+readType(Iterator& begin, const Iterator& end, uint32_t& type);
 
 /**
  * @brief Read VAR-NUMBER in NDN-TLV encoding
- * @tparam InputIterator an iterator or pointer dereferencable to uint8_t
+ * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
  *
  * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
  *                      the read VAR-NUMBER
@@ -180,13 +181,13 @@
  *
  * @throw tlv::Error VAR-NUMBER cannot be read
  */
-template<class InputIterator>
+template<typename Iterator>
 uint64_t
-readVarNumber(InputIterator& begin, const InputIterator& end);
+readVarNumber(Iterator& begin, const Iterator& end);
 
 /**
  * @brief Read TLV Type
- * @tparam InputIterator an iterator or pointer dereferencable to uint8_t
+ * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
  *
  * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
  *                      the read TLV-TYPE
@@ -196,26 +197,26 @@
  * @note This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
  *       is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
  */
-template<class InputIterator>
+template<typename Iterator>
 uint32_t
-readType(InputIterator& begin, const InputIterator& end);
+readType(Iterator& begin, const Iterator& end);
 
 /**
  * @brief Get number of bytes necessary to hold value of VAR-NUMBER
  */
 constexpr size_t
-sizeOfVarNumber(uint64_t varNumber);
+sizeOfVarNumber(uint64_t number);
 
 /**
  * @brief Write VAR-NUMBER to the specified stream
  * @return length of written VAR-NUMBER
  */
 size_t
-writeVarNumber(std::ostream& os, uint64_t varNumber);
+writeVarNumber(std::ostream& os, uint64_t number);
 
 /**
  * @brief Read nonNegativeInteger in NDN-TLV encoding
- * @tparam InputIterator an iterator or pointer dereferencable to uint8_t
+ * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
  *
  * @param [in]    size  size of the nonNegativeInteger
  * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
@@ -226,9 +227,9 @@
  * @note How many bytes to read is directly controlled by \p size, which can be either 1, 2, 4, or 8.
  *       If \p size differs from \p std::distance(begin, end), tlv::Error exception will be thrown.
  */
-template<class InputIterator>
+template<typename Iterator>
 uint64_t
-readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
+readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end);
 
 /**
  * @brief Get number of bytes necessary to hold value of nonNegativeInteger
@@ -253,9 +254,106 @@
 /////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////
 
-template<class InputIterator>
+namespace detail {
+
+/** @brief Function object to read a number from InputIterator
+ */
+template<typename Iterator>
+class ReadNumberSlow
+{
+public:
+  bool
+  operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
+  {
+    number = 0;
+    size_t count = 0;
+    for (; begin != end && count < size; ++begin, ++count) {
+      number = (number << 8) | *begin;
+    }
+    return count == size;
+  }
+};
+
+/** @brief Function object to read a number from ContiguousIterator
+ */
+template<typename Iterator>
+class ReadNumberFast
+{
+public:
+  bool
+  operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
+  {
+    if (begin + size > end) {
+      return false;
+    }
+
+    switch (size) {
+      case 1: {
+        number = *begin;
+        ++begin;
+        return true;
+      }
+      case 2: {
+        uint16_t value = 0;
+        std::memcpy(&value, &*begin, 2);
+        begin += 2;
+        number = be16toh(value);
+        return true;
+      }
+      case 4: {
+        uint32_t value = 0;
+        std::memcpy(&value, &*begin, 4);
+        begin += 4;
+        number = be32toh(value);
+        return true;
+      }
+      case 8: {
+        uint64_t value = 0;
+        std::memcpy(&value, &*begin, 8);
+        begin += 8;
+        number = be64toh(value);
+        return true;
+      }
+      default: {
+        BOOST_ASSERT(false);
+        return false;
+      }
+    }
+  }
+};
+
+/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
+ *
+ *  This is not a full ContiguousIterator detection implementation. It returns true for the most
+ *  common ContiguousIterator types used with TLV decoding function templates.
+ */
+template<typename Iterator,
+         typename DecayedIterator = typename std::decay<Iterator>::type,
+         typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
+constexpr bool
+shouldSelectContiguousReadNumber()
+{
+  return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
+          std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
+          std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
+         (std::is_same<ValueType, uint8_t>::value ||
+          std::is_same<ValueType, int8_t>::value ||
+          std::is_same<ValueType, char>::value ||
+          std::is_same<ValueType, unsigned char>::value ||
+          std::is_same<ValueType, signed char>::value);
+}
+
+template<typename Iterator>
+class ReadNumber : public std::conditional<shouldSelectContiguousReadNumber<Iterator>(),
+                                           ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>::type
+{
+};
+
+} // namespace detail
+
+template<typename Iterator>
 bool
-readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
+readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number)
 {
   if (begin == end)
     return false;
@@ -264,39 +362,17 @@
   ++begin;
   if (firstOctet < 253) {
     number = firstOctet;
-  }
-  else if (firstOctet == 253) {
-    if (end - begin < 2)
-      return false;
-
-    uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
-    begin += 2;
-    number = be16toh(value);
-  }
-  else if (firstOctet == 254) {
-    if (end - begin < 4)
-      return false;
-
-    uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
-    begin += 4;
-    number = be32toh(value);
-  }
-  else { // if (firstOctet == 255)
-    if (end - begin < 8)
-      return false;
-
-    uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
-    begin += 8;
-
-    number = be64toh(value);
+    return true;
   }
 
-  return true;
+  size_t size = firstOctet == 253 ? 2 :
+                firstOctet == 254 ? 4 : 8;
+  return detail::ReadNumber<Iterator>()(size, begin, end, number);
 }
 
-template<class InputIterator>
+template<typename Iterator>
 bool
-readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
+readType(Iterator& begin, const Iterator& end, uint32_t& type)
 {
   uint64_t number = 0;
   bool isOk = readVarNumber(begin, end, number);
@@ -308,51 +384,25 @@
   return true;
 }
 
-template<class InputIterator>
+template<typename Iterator>
 uint64_t
-readVarNumber(InputIterator& begin, const InputIterator& end)
+readVarNumber(Iterator& begin, const Iterator& end)
 {
   if (begin == end)
     BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing"));
 
-  uint64_t value;
+  uint64_t value = 0;
   bool isOk = readVarNumber(begin, end, value);
-  if (!isOk)
+  if (!isOk) {
     BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
+  }
 
   return value;
 }
 
-template<>
-inline bool
-readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
-                                              const std::istream_iterator<uint8_t>& end,
-                                              uint64_t& value)
-{
-  if (begin == end)
-    return false;
-
-  uint8_t firstOctet = *begin;
-  ++begin;
-  if (firstOctet < 253) {
-    value = firstOctet;
-    return true;
-  }
-
-  size_t expectedSize = firstOctet == 253 ? 2 :
-                        firstOctet == 254 ? 4 : 8;
-  value = 0;
-  size_t count = 0;
-  for (; begin != end && count < expectedSize; ++count) {
-    value = (value << 8) | *begin;
-    ++begin;
-  }
-  return count == expectedSize;
-}
-
-template<class InputIterator>
+template<typename Iterator>
 uint32_t
-readType(InputIterator& begin, const InputIterator& end)
+readType(Iterator& begin, const Iterator& end)
 {
   uint64_t type = readVarNumber(begin, end);
   if (type > std::numeric_limits<uint32_t>::max()) {
@@ -363,105 +413,56 @@
 }
 
 constexpr size_t
-sizeOfVarNumber(uint64_t varNumber)
+sizeOfVarNumber(uint64_t number)
 {
-  return varNumber < 253 ? 1 :
-         varNumber <= std::numeric_limits<uint16_t>::max() ? 3 :
-         varNumber <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
+  return number < 253 ? 1 :
+         number <= std::numeric_limits<uint16_t>::max() ? 3 :
+         number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
 }
 
 inline size_t
-writeVarNumber(std::ostream& os, uint64_t varNumber)
+writeVarNumber(std::ostream& os, uint64_t number)
 {
-  if (varNumber < 253) {
-    os.put(static_cast<char>(varNumber));
+  if (number < 253) {
+    os.put(static_cast<char>(number));
     return 1;
   }
-  else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
+  else if (number <= std::numeric_limits<uint16_t>::max()) {
     os.put(static_cast<char>(253));
-    uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
+    uint16_t value = htobe16(static_cast<uint16_t>(number));
     os.write(reinterpret_cast<const char*>(&value), 2);
     return 3;
   }
-  else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
+  else if (number <= std::numeric_limits<uint32_t>::max()) {
     os.put(static_cast<char>(254));
-    uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
+    uint32_t value = htobe32(static_cast<uint32_t>(number));
     os.write(reinterpret_cast<const char*>(&value), 4);
     return 5;
   }
   else {
     os.put(static_cast<char>(255));
-    uint64_t value = htobe64(varNumber);
+    uint64_t value = htobe64(number);
     os.write(reinterpret_cast<const char*>(&value), 8);
     return 9;
   }
 }
 
-template<class InputIterator>
+template<typename Iterator>
 uint64_t
-readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
-{
-  switch (size) {
-    case 1: {
-      if (end - begin < 1)
-        BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
-
-      uint8_t value = *begin;
-      begin++;
-      return value;
-    }
-    case 2: {
-      if (end - begin < 2)
-        BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
-
-      uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
-      begin += 2;
-      return be16toh(value);
-    }
-    case 4: {
-      if (end - begin < 4)
-        BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
-
-      uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
-      begin += 4;
-      return be32toh(value);
-    }
-    case 8: {
-      if (end - begin < 8)
-        BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
-
-      uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
-      begin += 8;
-      return be64toh(value);
-    }
-  }
-  BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
-                              "(only 1, 2, 4, and 8 are allowed)"));
-}
-
-template<>
-inline uint64_t
-readNonNegativeInteger<std::istream_iterator<uint8_t>>(size_t size,
-                                                       std::istream_iterator<uint8_t>& begin,
-                                                       const std::istream_iterator<uint8_t>& end)
+readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end)
 {
   if (size != 1 && size != 2 && size != 4 && size != 8) {
     BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
                                 "(only 1, 2, 4, and 8 are allowed)"));
   }
 
-  uint64_t value = 0;
-  size_t count = 0;
-  for (; begin != end && count < size; ++count) {
-    value = (value << 8) | *begin;
-    begin++;
-  }
-
-  if (count != size) {
+  uint64_t number = 0;
+  bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
+  if (!isOk) {
     BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
   }
 
-  return value;
+  return number;
 }
 
 constexpr size_t
diff --git a/tests/unit-tests/encoding/tlv.t.cpp b/tests/unit-tests/encoding/tlv.t.cpp
index 28f007b..edbb98f 100644
--- a/tests/unit-tests/encoding/tlv.t.cpp
+++ b/tests/unit-tests/encoding/tlv.t.cpp
@@ -23,6 +23,7 @@
 
 #include "boost-test.hpp"
 
+#include <boost/concept_archetype.hpp>
 #include <boost/iostreams/stream.hpp>
 #include <boost/iostreams/device/array.hpp>
 #include <boost/lexical_cast.hpp>
@@ -35,16 +36,67 @@
 BOOST_AUTO_TEST_SUITE(TestTlv)
 
 using ArrayStream = boost::iostreams::stream<boost::iostreams::array_source>;
-using Iterator = std::istream_iterator<uint8_t>;
+using StreamIterator = std::istream_iterator<uint8_t>;
+
+#define ASSERT_READ_NUMBER_IS_FAST(T) \
+  static_assert(std::is_base_of<detail::ReadNumberFast<T>, detail::ReadNumber<T>>::value, \
+                # T " should use ReadNumberFast")
+#define ASSERT_READ_NUMBER_IS_SLOW(T) \
+  static_assert(std::is_base_of<detail::ReadNumberSlow<T>, detail::ReadNumber<T>>::value, \
+                # T " should use ReadNumberSlow")
+
+ASSERT_READ_NUMBER_IS_FAST(const uint8_t*);
+ASSERT_READ_NUMBER_IS_FAST(uint8_t*);
+ASSERT_READ_NUMBER_IS_FAST(int8_t*);
+ASSERT_READ_NUMBER_IS_FAST(char*);
+ASSERT_READ_NUMBER_IS_FAST(unsigned char*);
+ASSERT_READ_NUMBER_IS_FAST(signed char*);
+ASSERT_READ_NUMBER_IS_FAST(const uint8_t[]);
+ASSERT_READ_NUMBER_IS_FAST(uint8_t[]);
+ASSERT_READ_NUMBER_IS_FAST(const uint8_t[12]);
+ASSERT_READ_NUMBER_IS_FAST(uint8_t[12]);
+using Uint8Array = std::array<uint8_t, 87>;
+ASSERT_READ_NUMBER_IS_FAST(Uint8Array::const_iterator);
+ASSERT_READ_NUMBER_IS_FAST(Uint8Array::iterator);
+using CharArray = std::array<char, 87>;
+ASSERT_READ_NUMBER_IS_FAST(CharArray::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::string::const_iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::string::iterator);
+ASSERT_READ_NUMBER_IS_FAST(Buffer::const_iterator);
+ASSERT_READ_NUMBER_IS_FAST(Buffer::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<uint8_t>::const_iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<uint8_t>::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<int8_t>::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<char>::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<unsigned char>::iterator);
+ASSERT_READ_NUMBER_IS_FAST(std::vector<signed char>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(std::vector<bool>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(std::vector<uint16_t>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(std::vector<uint32_t>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(std::vector<uint64_t>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(std::list<uint8_t>::iterator);
+ASSERT_READ_NUMBER_IS_SLOW(StreamIterator);
 
 BOOST_AUTO_TEST_SUITE(VarNumber)
 
+// This check ensures readVarNumber and readType only require InputIterator concept and nothing
+// more. This function should compile, but should never be executed.
+void
+checkArchetype()
+{
+  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);
+}
+
 static const uint8_t BUFFER[] = {
   0x01, // == 1
   0xfc, // == 252
   0xfd, 0x00, 0xfd, // == 253
   0xfe, 0x00, 0x01, 0x00, 0x00, // == 65536
-  0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 // == 4294967296LL
+  0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 // == 4294967296
 };
 
 BOOST_AUTO_TEST_CASE(SizeOf)
@@ -53,7 +105,7 @@
   BOOST_CHECK_EQUAL(sizeOfVarNumber(252), 1);
   BOOST_CHECK_EQUAL(sizeOfVarNumber(253), 3);
   BOOST_CHECK_EQUAL(sizeOfVarNumber(65536), 5);
-  BOOST_CHECK_EQUAL(sizeOfVarNumber(4294967296LL), 9);
+  BOOST_CHECK_EQUAL(sizeOfVarNumber(4294967296), 9);
 }
 
 BOOST_AUTO_TEST_CASE(Write)
@@ -64,7 +116,7 @@
   writeVarNumber(os, 252);
   writeVarNumber(os, 253);
   writeVarNumber(os, 65536);
-  writeVarNumber(os, 4294967296LL);
+  writeVarNumber(os, 4294967296);
 
   std::string buffer = os.str();
   const uint8_t* actual = reinterpret_cast<const uint8_t*>(buffer.c_str());
@@ -138,137 +190,137 @@
   BOOST_CHECK_EQUAL(readVarNumber(begin, begin + 9, value), true);
   begin = BUFFER + 10;
   BOOST_CHECK_NO_THROW(readVarNumber(begin, begin + 9));
-  BOOST_CHECK_EQUAL(value, 4294967296LL);
+  BOOST_CHECK_EQUAL(value, 4294967296);
 }
 
 BOOST_AUTO_TEST_CASE(ReadFromStream)
 {
-  Iterator end; // end of stream
+  StreamIterator end; // end of stream
   uint64_t value;
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 1);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 1);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
     BOOST_CHECK_EQUAL(value, 1);
   }
 
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 1, 1);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 1, 1);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
     BOOST_CHECK_EQUAL(value, 252);
   }
 
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 1);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 1);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
   }
 
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 2);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 2);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
   }
 
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 3);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 2, 3);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
     BOOST_CHECK_EQUAL(value, 253);
   }
 
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 1);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 1);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
   }
 
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 4);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 4);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
   }
 
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 5);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 5, 5);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
     BOOST_CHECK_EQUAL(value, 65536);
   }
 
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 1);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 1);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
   }
 
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 8);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), false);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 8);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_THROW(readVarNumber(begin, end), Error);
   }
 
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 9);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readVarNumber(begin, end, value), true);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER) + 10, 9);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_NO_THROW(readVarNumber(begin, end));
-    BOOST_CHECK_EQUAL(value, 4294967296LL);
+    BOOST_CHECK_EQUAL(value, 4294967296);
   }
 }
 
@@ -276,12 +328,21 @@
 
 BOOST_AUTO_TEST_SUITE(NonNegativeInteger)
 
+// This check ensures readNonNegativeInteger only requires InputIterator concept and nothing more.
+// This function should compile, but should never be executed.
+void
+checkArchetype()
+{
+  boost::input_iterator_archetype<uint8_t> begin, end;
+  readNonNegativeInteger(0, begin, end);
+}
+
 static const uint8_t BUFFER[] = {
   0x01, // 1
   0xff, // 255
   0x01, 0x02, // 258
-  0x01, 0x01, 0x01, 0x02, // 16843010LL
-  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02 // 72340172838076674LL
+  0x01, 0x01, 0x01, 0x02, // 16843010
+  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02 // 72340172838076674
 };
 
 BOOST_AUTO_TEST_CASE(SizeOf)
@@ -291,9 +352,9 @@
   BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(255), 1);
   BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(256), 2);
   BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(65536), 4);
-  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(16843009LL), 4);
-  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(4294967296LL), 8);
-  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(72340172838076673LL), 8);
+  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(16843009), 4);
+  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(4294967296), 8);
+  BOOST_CHECK_EQUAL(sizeOfNonNegativeInteger(72340172838076673), 8);
 }
 
 BOOST_AUTO_TEST_CASE(Write)
@@ -303,8 +364,8 @@
   writeNonNegativeInteger(os, 1);
   writeNonNegativeInteger(os, 255);
   writeNonNegativeInteger(os, 258);
-  writeNonNegativeInteger(os, 16843010LL);
-  writeNonNegativeInteger(os, 72340172838076674LL);
+  writeNonNegativeInteger(os, 16843010);
+  writeNonNegativeInteger(os, 72340172838076674);
 
   std::string buffer = os.str();
   const uint8_t* actual = reinterpret_cast<const uint8_t*>(buffer.c_str());
@@ -330,11 +391,11 @@
   BOOST_CHECK_EQUAL(begin, BUFFER + 4);
 
   begin = BUFFER + 4;
-  BOOST_CHECK_EQUAL(readNonNegativeInteger(4, begin, begin + 4), 16843010LL);
+  BOOST_CHECK_EQUAL(readNonNegativeInteger(4, begin, begin + 4), 16843010);
   BOOST_CHECK_EQUAL(begin, BUFFER + 8);
 
   begin = BUFFER + 8;
-  BOOST_CHECK_EQUAL(readNonNegativeInteger(8, begin, begin + 8), 72340172838076674LL);
+  BOOST_CHECK_EQUAL(readNonNegativeInteger(8, begin, begin + 8), 72340172838076674);
   BOOST_CHECK_EQUAL(begin, BUFFER + 16);
 
   // invalid size
@@ -354,45 +415,45 @@
 
 BOOST_AUTO_TEST_CASE(ReadFromStream)
 {
-  Iterator end; // end of stream
+  StreamIterator end; // end of stream
 
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER), sizeof(BUFFER));
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_EQUAL(readNonNegativeInteger(1, begin, end), 1);
     BOOST_CHECK_EQUAL(readNonNegativeInteger(1, begin, end), 255);
     BOOST_CHECK_EQUAL(readNonNegativeInteger(2, begin, end), 258);
-    BOOST_CHECK_EQUAL(readNonNegativeInteger(4, begin, end), 16843010LL);
-    BOOST_CHECK_EQUAL(readNonNegativeInteger(8, begin, end), 72340172838076674LL);
+    BOOST_CHECK_EQUAL(readNonNegativeInteger(4, begin, end), 16843010);
+    BOOST_CHECK_EQUAL(readNonNegativeInteger(8, begin, end), 72340172838076674);
     BOOST_CHECK(begin == end);
   }
 
   // invalid size
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 3);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_THROW(readNonNegativeInteger(3, begin, end), Error);
   }
 
   // available buffer smaller than size
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 0);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_THROW(readNonNegativeInteger(1, begin, end), Error);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 1);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_THROW(readNonNegativeInteger(2, begin, end), Error);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 3);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_THROW(readNonNegativeInteger(4, begin, end), Error);
   }
   {
     ArrayStream stream(reinterpret_cast<const char*>(BUFFER), 7);
-    Iterator begin(stream);
+    StreamIterator begin(stream);
     BOOST_CHECK_THROW(readNonNegativeInteger(8, begin, end), Error);
   }
 }