encoding: ensure Block is move constructible and assignable

This commit also reorganizes function declarations in Block class,
and moves definition of some long functions into .cpp.

refs #2234

Change-Id: I2d13424b9a18fc4000af4f7350e623da9a031636
diff --git a/src/encoding/block.cpp b/src/encoding/block.cpp
index 9edebc2..3163f1b 100644
--- a/src/encoding/block.cpp
+++ b/src/encoding/block.cpp
@@ -21,8 +21,6 @@
  * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
  */
 
-#include "common.hpp"
-
 #include "block.hpp"
 #include "block-helpers.hpp"
 
@@ -35,6 +33,16 @@
 
 namespace ndn {
 
+#if NDN_CXX_HAVE_IS_MOVE_CONSTRUCTIBLE
+static_assert(std::is_move_constructible<Buffer>::value,
+              "Buffer must be MoveConstructible");
+#endif // NDN_CXX_HAVE_IS_MOVE_CONSTRUCTIBLE
+
+#if NDN_CXX_HAVE_IS_MOVE_ASSIGNABLE
+static_assert(std::is_move_assignable<Buffer>::value,
+              "Buffer must be MoveAssignable");
+#endif // NDN_CXX_HAVE_IS_MOVE_ASSIGNABLE
+
 const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = 8800;
 
 Block::Block()
@@ -113,7 +121,6 @@
     }
 }
 
-
 Block::Block(const uint8_t* buffer, size_t maxlength)
 {
   const uint8_t*  tmp_begin = buffer;
@@ -272,6 +279,26 @@
 }
 
 void
+Block::reset()
+{
+  m_buffer.reset(); // reset of the shared_ptr
+  m_subBlocks.clear(); // remove all parsed subelements
+
+  m_type = std::numeric_limits<uint32_t>::max();
+  m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator();
+}
+
+void
+Block::resetWire()
+{
+  m_buffer.reset(); // reset of the shared_ptr
+  // keep subblocks
+
+  // keep type
+  m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator();
+}
+
+void
 Block::parse() const
 {
   if (!m_subBlocks.empty() || value_size() == 0)
@@ -358,6 +385,34 @@
   tlv::readVarNumber(m_value_begin, m_value_end);
 }
 
+const Block&
+Block::get(uint32_t type) const
+{
+  element_const_iterator it = this->find(type);
+  if (it != m_subBlocks.end())
+    return *it;
+
+  throw Error("(Block::get) Requested a non-existed type [" +
+              boost::lexical_cast<std::string>(type) + "] from Block");
+}
+
+Block::element_const_iterator
+Block::find(uint32_t type) const
+{
+  return std::find_if(m_subBlocks.begin(), m_subBlocks.end(),
+                      [type] (const Block& subBlock) { return subBlock.type() == type; });
+}
+
+void
+Block::remove(uint32_t type)
+{
+  resetWire();
+
+  auto it = std::remove_if(m_subBlocks.begin(), m_subBlocks.end(),
+                           [type] (const Block& subBlock) { return subBlock.type() != type; });
+  m_subBlocks.resize(it - m_subBlocks.begin());
+}
+
 Block
 Block::blockFromValue() const
 {
@@ -365,7 +420,7 @@
     throw Error("Underlying value buffer is empty");
 
   Buffer::const_iterator begin = value_begin(),
-    end = value_end();
+                         end = value_end();
 
   Buffer::const_iterator element_begin = begin;
 
@@ -381,21 +436,11 @@
                begin, end);
 }
 
-const Block&
-Block::get(uint32_t type) const
+bool
+Block::operator==(const Block& other) const
 {
-  for (element_const_iterator i = m_subBlocks.begin();
-       i != m_subBlocks.end();
-       i++)
-    {
-      if (i->type() == type)
-        {
-          return *i;
-        }
-    }
-
-  throw Error("(Block::get) Requested a non-existed type [" +
-              boost::lexical_cast<std::string>(type) + "] from Block");
+  return this->size() == other.size() &&
+         std::equal(this->begin(), this->end(), other.begin());
 }
 
 Block::operator boost::asio::const_buffer() const
@@ -403,5 +448,4 @@
   return boost::asio::const_buffer(wire(), size());
 }
 
-
 } // namespace ndn