encoding: reorganize Block class code

* Improve Doxygen.
* Consolidate and simplify constructors.
* Reorder class methods in cpp file to match hpp.
* Make operator== and operator!= non-member functions.
* Improve exception messages.
* Update code style.

refs #4171

Change-Id: I4cc0393f43a24a500b0efff90108ad1b42f5fa47
diff --git a/src/encoding/block.hpp b/src/encoding/block.hpp
index 7ade6e3..a5f1e1a 100644
--- a/src/encoding/block.hpp
+++ b/src/encoding/block.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2016 Regents of the University of California.
+/*
+ * Copyright (c) 2013-2017 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -43,9 +43,9 @@
 class Block
 {
 public:
-  typedef std::vector<Block>                 element_container;
-  typedef element_container::iterator        element_iterator;
-  typedef element_container::const_iterator  element_const_iterator;
+  using element_container      = std::vector<Block>;
+  using element_iterator       = element_container::iterator;
+  using element_const_iterator = element_container::const_iterator;
 
   class Error : public tlv::Error
   {
@@ -62,286 +62,366 @@
    */
   Block();
 
-  /** @brief Create a Block based on EncodingBuffer object
+  /** @brief Parse Block from an EncodingBuffer
+   *  @param buffer an EncodingBuffer containing one TLV element
+   *  @throw tlv::Error Type-Length parsing fails, or TLV-LENGTH does not match size of TLV-VALUE
    */
   explicit
   Block(const EncodingBuffer& buffer);
 
-  /** @brief Create a Block from the raw buffer with Type-Length parsing
+  /** @brief Parse Block from a wire Buffer
+   *  @param buffer a Buffer containing one TLV element
+   *  @note This constructor takes shared ownership of @p buffer.
+   *  @throw tlv::Error Type-Length parsing fails, or TLV-LENGTH does not match size of TLV-VALUE
    */
   explicit
   Block(const ConstBufferPtr& buffer);
 
-  /** @brief Create a Block from a buffer, directly specifying boundaries
-   *         of the block within the buffer
-   *
-   *  This overload will automatically detect type and position of the value within the block
+  /** @brief Parse Block within boundaries of a wire Buffer
+   *  @param buffer a Buffer containing an TLV element at [@p begin,@p end)
+   *  @param begin begin position of the TLV element within @p buffer
+   *  @param end end position of the TLV element within @p buffer
+   *  @param verifyLength if true, check TLV-LENGTH equals size of TLV-VALUE
+   *  @throw std::invalid_argument @p buffer is empty, or [@p begin,@p end) range are not within @p buffer
+   *  @throw tlv::Error Type-Length parsing fails, or TLV-LENGTH does not match size of TLV-VALUE
+   *  @note This overload automatically detects TLV-TYPE and position of TLV-VALUE.
    */
-  Block(const ConstBufferPtr& buffer,
-        const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
+  Block(ConstBufferPtr buffer, Buffer::const_iterator begin, Buffer::const_iterator end,
         bool verifyLength = true);
 
-  /** @brief Create a Block from existing block (reusing the underlying buffer), directly
-   *         specifying boundaries of the block within the buffer
-   *
-   *  This overload will automatically detect type and position of the value within the block
+  /** @brief Parse Block within boundaries of an existing Block, reusing underlying wire Buffer
+   *  @param block a Block whose buffer contains an TLV element at [@p begin,@p end)
+   *  @param begin begin position of the TLV element within @p block
+   *  @param end end position of the TLV element within @p block
+   *  @param verifyLength if true, check TLV-LENGTH equals size of TLV-VALUE
+   *  @throw std::invalid_argument [@p begin,@p end) range are not within @p block
+   *  @throw tlv::Error Type-Length parsing fails, or TLV-LENGTH does not match size of TLV-VALUE
    */
-  Block(const Block& block,
-        const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
+  Block(const Block& block, Buffer::const_iterator begin, Buffer::const_iterator end,
         bool verifyLength = true);
 
-  /** @brief Create a Block from the raw buffer with Type-Length parsing
+  /** @brief Create a Block from a wire Buffer without parsing
+   *  @param buffer a Buffer containing an TLV element at [@p begin,@p end)
+   *  @param type TLV-TYPE
+   *  @param begin begin position of the TLV element within @p buffer
+   *  @param end end position of the TLV element within @p buffer
+   *  @param valueBegin begin position of TLV-VALUE within @p buffer
+   *  @param valueEnd end position of TLV-VALUE within @p buffer
    */
-  Block(const uint8_t* buffer, size_t maxlength);
+  Block(ConstBufferPtr buffer, uint32_t type,
+        Buffer::const_iterator begin, Buffer::const_iterator end,
+        Buffer::const_iterator valueBegin, Buffer::const_iterator valueEnd);
 
-  /** @brief Create a Block from the raw buffer with Type-Length parsing
+  /** @brief Parse Block from a raw buffer
+   *  @param buf pointer to the first octet of an TLV element
+   *  @param bufSize size of the raw buffer; may be more than size of the TLV element
+   *  @throw tlv::Error Type-Length parsing fails, or size of TLV-VALUE exceeds @p bufSize
+   *  @note This overload copies the TLV element into an internal wire buffer.
    */
-  Block(const void* buffer, size_t maxlength);
+  Block(const uint8_t* buf, size_t bufSize);
 
-  /** @brief Create a Block from the wire buffer (no parsing)
-   *
-   *  This overload does not do any parsing
+  /** @brief Parse Block from a raw buffer
+   *  @deprecated use Block(const uint8_t*, size_t)
    */
-  Block(const ConstBufferPtr& wire,
-        uint32_t type,
-        const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
-        const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd);
+  Block(const void* buf, size_t bufSize);
 
-  /** @brief Create Block of a specific type with empty wire buffer
+  /** @brief Create an empty Block with specified TLV-TYPE
+   *  @param type TLV-TYPE
    */
   explicit
   Block(uint32_t type);
 
-  /** @brief Create a Block of a specific type with the specified value
-   *
-   *  The underlying buffer holds only value Additional operations are needed
-   *  to construct wire encoding, one need to prepend the wire buffer with type
-   *  and value-length VAR-NUMBERs
+  /** @brief Create a Block with specified TLV-TYPE and TLV-VALUE
+   *  @param type TLV-TYPE
+   *  @param value a Buffer containing the TLV-VALUE
    */
-  Block(uint32_t type, const ConstBufferPtr& value);
+  Block(uint32_t type, ConstBufferPtr value);
 
-  /** @brief Create a nested Block of a specific type with the specified value
-   *
-   *  The underlying buffer holds only value. Additional operations are needed
-   *  to construct wire encoding, one need to prepend the wire buffer with type
-   *  and value-length VAR-NUMBERs
+  /** @brief Create a Block with specified TLV-TYPE and TLV-VALUE
+   *  @param type TLV-TYPE
+   *  @param value a Block to be nested as TLV-VALUE
    */
   Block(uint32_t type, const Block& value);
 
-  /** @brief Create a Block from an input stream
+  /** @brief Parse Block from an input stream
    */
   static Block
   fromStream(std::istream& is);
 
-  /** @brief Try to construct block from Buffer
-   *  @param buffer the buffer to construct block from
-   *  @note buffer is passed by value because the constructed block
-   *        takes shared ownership of the buffer
-   *  @param offset offset from beginning of \p buffer to construct Block from
-   *
-   *  This method does not throw upon decoding error.
-   *  This method does not copy the bytes.
-   *
-   *  @return true and the Block, if Block is successfully created; otherwise false
+  /** @brief Try to parse Block from a wire buffer
+   *  @param buffer a Buffer containing an TLV element at offset @p offset
+   *  @param offset begin position of the TLV element within @p buffer
+   *  @note This function does not throw exceptions upon decoding failure.
+   *  @return true and the Block if parsing succeeds; otherwise false
    */
   static std::tuple<bool, Block>
   fromBuffer(ConstBufferPtr buffer, size_t offset);
 
-  /** @brief Try to construct block from raw buffer
-   *  @param buffer the raw buffer to copy bytes from
-   *  @param maxSize the maximum size of constructed block;
-   *                 @p buffer must have a size of at least @p maxSize
-   *
-   *  This method does not throw upon decoding error.
-   *  This method copies the bytes into a new Buffer.
-   *
-   *  @return true and the Block, if Block is successfully created; otherwise false
+  /** @brief Try to parse Block from a raw buffer
+   *  @param buf pointer to the first octet of an TLV element
+   *  @param bufSize size of the raw buffer; may be more than size of the TLV element
+   *  @note This function does not throw exceptions upon decoding failure.
+   *  @note This overload copies the TLV element into an internal wire buffer.
+   *  @return true and the Block if parsing succeeds; otherwise false
    */
   static std::tuple<bool, Block>
-  fromBuffer(const uint8_t* buffer, size_t maxSize);
+  fromBuffer(const uint8_t* buf, size_t bufSize);
 
 public: // wire format
   /** @brief Check if the Block is empty
+   *
+   *  A Block is "empty" only if it is default-constructed. A Block with zero-length TLV-VALUE is
+   *  not considered empty.
    */
   bool
-  empty() const;
+  empty() const
+  {
+    return m_type == std::numeric_limits<uint32_t>::max();
+  }
 
   /** @brief Check if the Block has fully encoded wire
+   *
+   *  A Block has fully encoded wire if the underlying buffer exists and contains full
+   *  Type-Length-Value instead of just TLV-VALUE field.
    */
   bool
   hasWire() const;
 
   /** @brief Reset wire buffer of the element
+   *  @post empty() == true
    */
   void
   reset();
 
-  /** @brief Reset wire buffer but keep sub elements (if any)
+  /** @brief Reset wire buffer but keep TLV-TYPE and sub elements (if any)
+   *  @post hasWire() == false
+   *  @post hasValue() == false
    */
   void
   resetWire();
 
+  /** @brief Get begin iterator of encoded wire
+   *  @pre hasWire() == true
+   */
   Buffer::const_iterator
   begin() const;
 
+  /** @brief Get end iterator of encoded wire
+   *  @pre hasWire() == true
+   */
   Buffer::const_iterator
   end() const;
 
+  /** @brief Get pointer to encoded wire
+   *  @pre hasWire() == true
+   */
   const uint8_t*
   wire() const;
 
+  /** @brief Get size of encoded wire, including Type-Length-Value
+   *  @pre empty() == false
+   */
   size_t
   size() const;
 
-public: // type and value
-  uint32_t
-  type() const;
+  /** @brief Get underlying buffer
+   */
+  shared_ptr<const Buffer>
+  getBuffer() const
+  {
+    return m_buffer;
+  }
 
-  /** @brief Check if the Block has value block (no type and length are encoded)
+public: // type and value
+  /** @brief Get TLV-TYPE
+   */
+  uint32_t
+  type() const
+  {
+    return m_type;
+  }
+
+  /** @brief Get begin iterator of TLV-VALUE
+   *
+   *  This property reflects whether the underlying buffer contains TLV-VALUE. If this is false,
+   *  TLV-VALUE has zero-length. If this is true, TLV-VALUE may be zero-length.
    */
   bool
-  hasValue() const;
+  hasValue() const
+  {
+    return m_buffer != nullptr;
+  }
 
+  /** @brief Get begin iterator of TLV-VALUE
+   *  @pre hasValue() == true
+   */
   Buffer::const_iterator
-  value_begin() const;
+  value_begin() const
+  {
+    return m_valueBegin;
+  }
 
+  /** @brief Get end iterator of TLV-VALUE
+   *  @pre hasValue() == true
+   */
   Buffer::const_iterator
-  value_end() const;
+  value_end() const
+  {
+    return m_valueEnd;
+  }
 
+  /** @brief Get pointer to TLV-VALUE
+   */
   const uint8_t*
   value() const;
 
+  /** @brief Get size of TLV-VALUE aka TLV-LENGTH
+   */
   size_t
   value_size() const;
 
-public: // sub elements
-  /** @brief Parse wire buffer into subblocks
-   *
-   *  This method is not really const, but it does not modify any data.  It simply
-   *  parses contents of the buffer into subblocks
-   */
-  void
-  parse() const;
-
-  /** @brief Encode subblocks into wire buffer
-   */
-  void
-  encode();
-
-  /** @brief Get the first subelement of the requested type
-   */
-  const Block&
-  get(uint32_t type) const;
-
-  element_const_iterator
-  find(uint32_t type) const;
-
-  /**
-   * @brief remove all subelements of \p type
-   * @param type TLV-TYPE of subelements to remove
-   * @pre parse() has been invoked
-   */
-  void
-  remove(uint32_t type);
-
-  element_iterator
-  erase(element_const_iterator position);
-
-  element_iterator
-  erase(element_const_iterator first, element_const_iterator last);
-
-  void
-  push_back(const Block& element);
-
-  /**
-   * @brief insert Insert a new element in a specific position
-   * @param pos Position to insert the new element
-   * @param element Element to be inserted
-   * @return An iterator that points to the first of the newly inserted elements.
-   */
-  element_iterator
-  insert(element_const_iterator pos, const Block& element);
-
-  /** @brief Get all subelements
-   */
-  const element_container&
-  elements() const;
-
-  element_const_iterator
-  elements_begin() const;
-
-  element_const_iterator
-  elements_end() const;
-
-  size_t
-  elements_size() const;
-
   Block
   blockFromValue() const;
 
-  /**
-   * @brief Get underlying buffer
+public: // sub elements
+  /** @brief Parse TLV-VALUE into sub elements
+   *  @post elements() reflects sub elements found in TLV-VALUE
+   *  @throw tlv::Error TLV-VALUE is not a sequence of TLV elements
+   *  @note This method does not perform recursive parsing.
+   *  @note This method has no effect if elements() is already populated.
+   *  @note This method is not really const, but it does not modify any data.
    */
-  shared_ptr<const Buffer>
-  getBuffer() const;
+  void
+  parse() const;
 
-public: // EqualityComparable concept
-  bool
-  operator==(const Block& other) const;
+  /** @brief Encode sub elements into TLV-VALUE
+   *  @post TLV-VALUE contains sub elements from elements()
+   */
+  void
+  encode();
 
-  bool
-  operator!=(const Block& other) const;
+  /** @brief Get the first sub element of specified TLV-TYPE
+   *  @pre parse() has been executed
+   *  @throw Error sub element of @p type does not exist
+   */
+  const Block&
+  get(uint32_t type) const;
 
-public: // ConvertibleToConstBuffer
+  /** @brief Find the first sub element of specified TLV-TYPE
+   *  @pre parse() has been executed
+   *  @return iterator in elements() to the found sub element, otherwise elements_end()
+   */
+  element_const_iterator
+  find(uint32_t type) const;
+
+  /** @brief Remove all sub elements of specified TLV-TYPE
+   *  @pre parse() has been executed
+   *  @post find(type) == elements_end()
+   */
+  void
+  remove(uint32_t type);
+
+  /** @brief Erase a sub element
+   */
+  element_iterator
+  erase(element_const_iterator position);
+
+  /** @brief Erase a range of sub elements
+   */
+  element_iterator
+  erase(element_const_iterator first, element_const_iterator last);
+
+  /** @brief Append a sub element
+   */
+  void
+  push_back(const Block& element);
+
+  /** @brief Insert a sub element
+   *  @param pos position of new sub element
+   *  @param element new sub element
+   *  @return iterator in elements() to the new sub element
+   */
+  element_iterator
+  insert(element_const_iterator pos, const Block& element);
+
+  /** @brief Get container of sub elements
+   *  @pre parse() has been executed
+   */
+  const element_container&
+  elements() const
+  {
+    return m_elements;
+  }
+
+  /** @brief Equivalent to elements().begin()
+   */
+  element_const_iterator
+  elements_begin() const
+  {
+    return m_elements.begin();
+  }
+
+  /** @brief Equivalent to elements().end()
+   */
+  element_const_iterator
+  elements_end() const
+  {
+    return m_elements.end();
+  }
+
+  /** @brief Equivalent to elements().size()
+   */
+  size_t
+  elements_size() const
+  {
+    return m_elements.size();
+  }
+
+public: // misc
+  /** @brief Implicit conversion to const_buffer
+   */
   operator boost::asio::const_buffer() const;
 
 protected:
+  /** @brief underlying buffer storing TLV-VALUE and possibly TLV-TYPE and TLV-LENGTH fields
+   *
+   *  If m_buffer is nullptr, this is an empty Block with TLV-TYPE given in m_type.
+   *  Otherwise,
+   *  - [m_valueBegin, m_valueEnd) point to TLV-VALUE within m_buffer.
+   *  - If m_begin != m_end, [m_begin,m_end) point to Type-Length-Value of this Block within m_buffer.
+   *    Otherwise, m_buffer does not contain TLV-TYPE and TLV-LENGTH fields.
+   */
   shared_ptr<const Buffer> m_buffer;
+  Buffer::const_iterator m_begin; ///< @sa m_buffer
+  Buffer::const_iterator m_end; ///< @sa m_buffer
 
-  uint32_t m_type;
+  Buffer::const_iterator m_valueBegin; ///< @sa m_buffer
+  Buffer::const_iterator m_valueEnd; ///< @sa m_buffer
 
-  Buffer::const_iterator m_begin;
-  Buffer::const_iterator m_end;
+  uint32_t m_type; ///< TLV-TYPE
+
+  /** @brief total size including Type-Length-Value
+   *
+   *  This field is valid only if empty() is false.
+   */
   uint32_t m_size;
 
-  Buffer::const_iterator m_value_begin;
-  Buffer::const_iterator m_value_end;
-
-  mutable element_container m_subBlocks;
+  /** @brief sub elements
+   *
+   *  This field is valid only if parse() has been executed.
+   */
+  mutable element_container m_elements;
 };
 
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
+/** @brief Compare whether two Blocks have same TLV-TYPE, TLV-LENGTH, and TLV-VALUE
+ */
+bool
+operator==(const Block& lhs, const Block& rhs);
 
-inline shared_ptr<const Buffer>
-Block::getBuffer() const
+inline bool
+operator!=(const Block& lhs, const Block& rhs)
 {
-  return m_buffer;
-}
-
-inline uint32_t
-Block::type() const
-{
-  return m_type;
-}
-
-inline Buffer::const_iterator
-Block::value_begin() const
-{
-  return m_value_begin;
-}
-
-inline Buffer::const_iterator
-Block::value_end() const
-{
-  return m_value_end;
-}
-
-inline const Block::element_container&
-Block::elements() const
-{
-  return m_subBlocks;
+  return !(lhs == rhs);
 }
 
 } // namespace ndn