encoding: Refactoring EncodingBuffer

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

Change-Id: I8275c6276c5ecfa280f87f584189907521febf5f
Refs: #2494, #2490
diff --git a/src/encoding/encoder.hpp b/src/encoding/encoder.hpp
new file mode 100644
index 0000000..a258d1e
--- /dev/null
+++ b/src/encoding/encoder.hpp
@@ -0,0 +1,343 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_ENCODING_ENCODER_HPP
+#define NDN_ENCODING_ENCODER_HPP
+
+#include "../common.hpp"
+#include "block.hpp"
+
+namespace ndn {
+namespace encoding {
+
+/**
+ * @brief Helper class to perform TLV encoding
+ * Interface of this class (mostly) matches interface of Estimator class
+ * @sa Estimator
+ */
+class Encoder
+{
+public: // common interface between Encoder and Estimator
+  /**
+   * @brief Create instance of the encoder with the specified reserved sizes
+   * @param totalReserve  initial buffer size to reserve
+   * @param totalFromBack number of bytes to reserve for append* operations
+   */
+  explicit
+  Encoder(size_t totalReserve = 8800, size_t reserveFromBack = 400);
+
+  Encoder(const Encoder&) = delete;
+
+  Encoder&
+  operator=(const Encoder&) = delete;
+
+  /**
+   * @brief Prepend a byte
+   */
+  size_t
+  prependByte(uint8_t value);
+
+  /**
+   * @brief Append a byte
+   */
+  size_t
+  appendByte(uint8_t value);
+
+  /**
+   * @brief Prepend a byte array @p array of length @p length
+   */
+  size_t
+  prependByteArray(const uint8_t* array, size_t length);
+
+  /**
+   * @brief Append a byte array @p array of length @p length
+   */
+  size_t
+  appendByteArray(const uint8_t* array, size_t length);
+
+  /**
+   * @brief Prepend range of bytes from the range [@p first, @p last)
+   */
+  template<class Iterator>
+  size_t
+  prependRange(Iterator first, Iterator last);
+
+  /**
+   * @brief Append range of bytes from the range [@p first, @p last)
+   */
+  template<class Iterator>
+  size_t
+  appendRange(Iterator first, Iterator last);
+
+  /**
+   * @brief Prepend VarNumber @p varNumber of NDN TLV encoding
+   * @sa http://named-data.net/doc/ndn-tlv/
+   */
+  size_t
+  prependVarNumber(uint64_t varNumber);
+
+  /**
+   * @brief Prepend VarNumber @p varNumber of NDN TLV encoding
+   * @sa http://named-data.net/doc/ndn-tlv/
+   */
+  size_t
+  appendVarNumber(uint64_t varNumber);
+
+  /**
+   * @brief Prepend non-negative integer @p integer of NDN TLV encoding
+   * @sa http://named-data.net/doc/ndn-tlv/
+   */
+  size_t
+  prependNonNegativeInteger(uint64_t integer);
+
+  /**
+   * @brief Append non-negative integer @p integer of NDN TLV encoding
+   * @sa http://named-data.net/doc/ndn-tlv/
+   */
+  size_t
+  appendNonNegativeInteger(uint64_t integer);
+
+  /**
+   * @brief Prepend TLV block of type @p type and value from buffer @p array of size @p arraySize
+   */
+  size_t
+  prependByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize);
+
+  /**
+   * @brief Append TLV block of type @p type and value from buffer @p array of size @p arraySize
+   */
+  size_t
+  appendByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize);
+
+  /**
+   * @brief Prepend TLV block @p block
+   */
+  size_t
+  prependBlock(const Block& block);
+
+  /**
+   * @brief Append TLV block @p block
+   */
+  size_t
+  appendBlock(const Block& block);
+
+public: // unique interface to the Encoder
+  typedef Buffer::value_type value_type;
+  typedef Buffer::iterator iterator;
+  typedef Buffer::const_iterator const_iterator;
+
+  /**
+   * @brief Create EncodingBlock from existing block
+   *
+   * This is a dangerous constructor and should be used with caution.
+   * It will modify contents of the buffer that is used by block and may
+   * impact data in other blocks.
+   *
+   * The primary purpose for this method is to be used to extend Block
+   * after sign operation.
+   */
+  explicit
+  Encoder(const Block& block);
+
+  /**
+   * @brief Reserve @p size bytes for the underlying buffer
+   * @param addInFront if true, then @p size bytes will be available in front (i.e., subsequent call
+   *        to prepend* will not need to allocate memory).  If false, then reservation will be done
+   *        at the end of the buffer (i.d., for subsequent append* calls)
+   * @note Reserve size is exact, unlike reserveFront and reserveBack methods
+   * @sa reserveFront, reserveBack
+   */
+  void
+  reserve(size_t size, bool addInFront);
+
+  /**
+   * @brief Reserve at least @p size bytes at the back of the underlying buffer
+   * @note the actual reserve size can be (and in most cases is) larger than specified reservation
+   *       length
+   */
+  void
+  reserveBack(size_t size);
+
+  /**
+   * @brief Reserve at least @p isze bytes at the beginning of the underlying buffer
+   * @note the actual reserve size can be (and in most cases is) larger than specified reservation
+   *       length
+   */
+  void
+  reserveFront(size_t size);
+
+  /**
+   * @brief Get size of the underlying buffer
+   */
+  size_t
+  capacity() const;
+
+  /**
+   * @brief Get underlying buffer
+   */
+  shared_ptr<Buffer>
+  getBuffer();
+
+public: // accessors
+
+  /**
+   * @brief Get an iterator pointing to the first byte of the encoded buffer
+   */
+  iterator
+  begin();
+
+  /**
+   * @brief Get an iterator pointing to the past-the-end byte of the encoded buffer
+   */
+  iterator
+  end();
+
+  /**
+   * @brief Get an iterator pointing to the first byte of the encoded buffer
+   */
+  const_iterator
+  begin() const;
+
+  const_iterator
+  end() const;
+
+  /**
+   * @brief Get a pointer to the first byte of the encoded buffer
+   */
+  uint8_t*
+  buf();
+
+  /**
+   * @brief Get a pointer to the first byte of the encoded buffer
+   */
+  const uint8_t*
+  buf() const;
+
+  /**
+   * @brief Get size of the encoded buffer
+   */
+  size_t
+  size() const;
+
+  /**
+   * @brief Create Block from the underlying buffer
+   *
+   * @param verifyLength If this parameter set to true, Block's constructor
+   *                     will be requested to verify consistency of the encoded
+   *                     length in the Block, otherwise ignored
+   */
+  Block
+  block(bool verifyLength = true) const;
+
+private:
+  shared_ptr<Buffer> m_buffer;
+
+  // invariant: m_begin always points to the position of last-written byte (if prepending data)
+  iterator m_begin;
+  // invariant: m_end always points to the position of next unwritten byte (if appending data)
+  iterator m_end;
+};
+
+
+inline size_t
+Encoder::size() const
+{
+  return m_end - m_begin;
+}
+
+inline shared_ptr<Buffer>
+Encoder::getBuffer()
+{
+  return m_buffer;
+}
+
+inline size_t
+Encoder::capacity() const
+{
+  return m_buffer->size();
+}
+
+inline Buffer::iterator
+Encoder::begin()
+{
+  return m_begin;
+}
+
+inline Buffer::iterator
+Encoder::end()
+{
+  return m_end;
+}
+
+inline Buffer::const_iterator
+Encoder::begin() const
+{
+  return m_begin;
+}
+
+inline Buffer::const_iterator
+Encoder::end() const
+{
+  return m_end;
+}
+
+inline uint8_t*
+Encoder::buf()
+{
+  return &(*m_begin);
+}
+
+inline const uint8_t*
+Encoder::buf() const
+{
+  return &(*m_begin);
+}
+
+template<class Iterator>
+inline size_t
+Encoder::prependRange(Iterator first, Iterator last)
+{
+  size_t length = std::distance(first, last);
+  reserveFront(length);
+
+  m_begin -= length;
+  std::copy(first, last, m_begin);
+  return length;
+}
+
+
+template<class Iterator>
+inline size_t
+Encoder::appendRange(Iterator first, Iterator last)
+{
+  size_t length = std::distance(first, last);
+  reserveBack(length);
+
+  std::copy(first, last, m_end);
+  m_end += length;
+  return length;
+}
+
+
+} // namespace encoding
+} // namespace ndn
+
+#endif // NDN_ENCODING_ENCODER_HPP