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/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);
   }
 }