encoding: Refactoring EncodingBuffer

Breaks: nfd:commit:c0273e3505ac2ccf843401be77a513d8eb663127
Breaks: ChronoSync:commit:e042f83a1df184a8e7a90ef00034d11026891cd1

Change-Id: I8275c6276c5ecfa280f87f584189907521febf5f
Refs: #2494, #2490
diff --git a/src/encoding/block-helpers.hpp b/src/encoding/block-helpers.hpp
index 0a58aa0..e3e86f4 100644
--- a/src/encoding/block-helpers.hpp
+++ b/src/encoding/block-helpers.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2014 Regents of the University of California.
+ * Copyright (c) 2013-2015 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -17,8 +17,6 @@
  * <http://www.gnu.org/licenses/>.
  *
  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- *
- * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
  */
 
 #ifndef NDN_ENCODING_BLOCK_HELPERS_HPP
@@ -27,8 +25,66 @@
 #include "block.hpp"
 #include "encoding-buffer.hpp"
 
+#include <iterator>
+
 namespace ndn {
 
+/**
+ * @deprecated Use Encoder::prependBlock and Estimator::prependBlock instead
+ */
+template<bool P>
+inline size_t
+prependBlock(EncodingImpl<P>& encoder, const Block& block)
+{
+  return encoder.prependBlock(block);
+}
+
+/**
+ * @deprecated Use Encoder::prependByteArrayBlock and Estimator::prependByteArrayBlock instead
+ */
+template<bool P>
+inline size_t
+prependByteArrayBlock(EncodingImpl<P>& encoder,
+                      uint32_t type, const uint8_t* array, size_t arraySize)
+{
+  return encoder.prependByteArrayBlock(type, array, arraySize);
+}
+
+template<bool P>
+inline size_t
+prependNonNegativeIntegerBlock(EncodingImpl<P>& encoder, uint32_t type, uint64_t number)
+{
+  size_t valueLength = encoder.prependNonNegativeInteger(number);
+  size_t totalLength = valueLength;
+  totalLength += encoder.prependVarNumber(valueLength);
+  totalLength += encoder.prependVarNumber(type);
+
+  return totalLength;
+}
+
+template<bool P>
+inline size_t
+prependBooleanBlock(EncodingImpl<P>& encoder, uint32_t type)
+{
+  size_t totalLength = encoder.prependVarNumber(0);
+  totalLength += encoder.prependVarNumber(type);
+
+  return totalLength;
+}
+
+template<bool P, class U>
+inline size_t
+prependNestedBlock(EncodingImpl<P>& encoder, uint32_t type, const U& nestedBlock)
+{
+  size_t valueLength = nestedBlock.wireEncode(encoder);
+  size_t totalLength = valueLength;
+  totalLength += encoder.prependVarNumber(valueLength);
+  totalLength += encoder.prependVarNumber(type);
+
+  return totalLength;
+}
+
+
 inline Block
 nonNegativeIntegerBlock(uint32_t type, uint64_t value)
 {
@@ -64,10 +120,10 @@
 dataBlock(uint32_t type, const uint8_t* data, size_t dataSize)
 {
   EncodingEstimator estimator;
-  size_t totalLength = prependByteArrayBlock(estimator, type, data, dataSize);
+  size_t totalLength = estimator.prependByteArrayBlock(type, data, dataSize);
 
   EncodingBuffer encoder(totalLength, 0);
-  prependByteArrayBlock(encoder, type, data, dataSize);
+  encoder.prependByteArrayBlock(type, data, dataSize);
 
   return encoder.block();
 }
@@ -78,21 +134,77 @@
   return dataBlock(type, reinterpret_cast<const uint8_t*>(data), dataSize);
 }
 
-// template<class InputIterator>
-// inline Block
-// dataBlock(uint32_t type, InputIterator first, InputIterator last)
-// {
-//   size_t dataSize = 0;
-//   for (InputIterator i = first; i != last; i++)
-//     ++dataSize;
+/**
+ * @brief Helper class template to create a data block when RandomAccessIterator is used
+ */
+template<class Iterator>
+class DataBlockFast
+{
+public:
+  BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Iterator>));
 
-//   OBufferStream os;
-//   tlv::writeVarNumber(os, type);
-//   tlv::writeVarNumber(os, dataSize);
-//   std::copy(first, last, std::ostream_iterator<uint8_t>(os));
+  static Block
+  makeBlock(uint32_t type, Iterator first, Iterator last)
+  {
+    EncodingEstimator estimator;
+    size_t valueLength = last - first;
+    size_t totalLength = valueLength;
+    totalLength += estimator.prependVarNumber(valueLength);
+    totalLength += estimator.prependVarNumber(type);
 
-//   return Block(os.buf());
-// }
+    EncodingBuffer encoder(totalLength, 0);
+    encoder.prependRange(first, last);
+    encoder.prependVarNumber(valueLength);
+    encoder.prependVarNumber(type);
+
+    return encoder.block();
+  }
+};
+
+/**
+ * @brief Helper class template to create a data block when generic InputIterator is used
+ */
+template<class Iterator>
+class DataBlockSlow
+{
+public:
+  BOOST_CONCEPT_ASSERT((boost::InputIterator<Iterator>));
+
+  static Block
+  makeBlock(uint32_t type, Iterator first, Iterator last)
+  {
+    // reserve 4 bytes in front (common for 1(type)-3(length) encoding
+    // Actual size will be adjusted as necessary by the encoder
+    EncodingBuffer encoder(4, 4);
+    size_t valueLength = encoder.appendRange(first, last);
+    encoder.prependVarNumber(valueLength);
+    encoder.prependVarNumber(type);
+
+    return encoder.block();
+  }
+};
+
+/**
+ * @brief Free function to create a block given @p type and range [@p first, @p last) of bytes
+ * @tparam Iterator iterator type satisfying at least InputIterator concept.  Implementation
+ *                  is more optimal when the iterator type satisfies RandomAccessIterator concept
+ *                  It is required that sizeof(std::iterator_traits<Iterator>::value_type) == 1.
+ */
+template<class Iterator>
+inline Block
+dataBlock(uint32_t type, Iterator first, Iterator last)
+{
+  static_assert(sizeof(typename std::iterator_traits<Iterator>::value_type) == 1,
+                "Iterator should point only to char or unsigned char");
+
+  typedef typename boost::mpl::if_<
+    std::is_base_of<std::random_access_iterator_tag,
+                    typename std::iterator_traits<Iterator>::iterator_category>,
+    DataBlockFast<Iterator>,
+    DataBlockSlow<Iterator>>::type DataBlock;
+
+  return DataBlock::makeBlock(type, first, last);
+}
 
 } // namespace ndn