name: New method to get "successor" of a name

Change-Id: I41a53e64994970121766bc92cd9dd4796ba5fcfb
refs #1677
diff --git a/src/name-component.hpp b/src/name-component.hpp
index b7b529f..0e17580 100644
--- a/src/name-component.hpp
+++ b/src/name-component.hpp
@@ -290,6 +290,9 @@
     return !hasValue();
   }
 
+  Component
+  getSuccessor() const;
+
   /**
    * @brief Check if this is the same component as other
    *
@@ -566,6 +569,34 @@
   return std::memcmp(value(), other.value(), value_size());
 }
 
+inline Component
+Component::getSuccessor() const
+{
+  size_t totalLength = 0;
+  EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
+                                         // in unlikely case TLV length changes more,
+                                         // EncodingBuffer will take care of that
+
+  bool isOverflow = true;
+  size_t i = value_size();
+  for (; isOverflow && i > 0; i--) {
+    uint8_t newValue = static_cast<uint8_t>((value()[i - 1] + 1) & 0xFF);
+    totalLength += encoder.prependByte(newValue);
+    isOverflow = (newValue == 0);
+  }
+  totalLength += encoder.prependByteArray(value(), i);
+
+  if (isOverflow) {
+    // new name components has to be extended
+    totalLength += encoder.appendByte(0);
+  }
+
+  totalLength += encoder.prependVarNumber(totalLength);
+  totalLength += encoder.prependVarNumber(Tlv::NameComponent);
+
+  return encoder.block();
+}
+
 
 template<bool T>
 inline size_t
diff --git a/src/name.hpp b/src/name.hpp
index 9c33528..7522a19 100644
--- a/src/name.hpp
+++ b/src/name.hpp
@@ -303,6 +303,15 @@
   }
 
   /**
+   * @brief get the successor of a name
+   * successor of a name is defined that its last component is
+   * advanced next possible value of last component of original name
+   * @return a new name
+   */
+  Name
+  getSuccessor() const;
+
+  /**
    * Check if this name has the same component count and components as the given name.
    * @param name The Name to check.
    * @return true if the names are equal, otherwise false.
@@ -661,6 +670,19 @@
   return result;
 }
 
+inline Name
+Name::getSuccessor() const
+{
+  if (empty()) {
+    static uint8_t firstValue[] = { 0 };
+    Name firstName;
+    firstName.append(firstValue, 1);
+    return firstName;
+  }
+
+  return getPrefix(-1).append(get(-1).getSuccessor());
+}
+
 inline bool
 Name::equals(const Name& name) const
 {
diff --git a/tests/unit-tests/test-name.cpp b/tests/unit-tests/test-name.cpp
index e5f438d..dd9cc78 100644
--- a/tests/unit-tests/test-name.cpp
+++ b/tests/unit-tests/test-name.cpp
@@ -128,6 +128,14 @@
     }
 }
 
+BOOST_AUTO_TEST_CASE(GetSuccessor)
+{
+  BOOST_CHECK_EQUAL(Name("ndn:/%00%01/%01%02").getSuccessor(), Name("ndn:/%00%01/%01%03"));
+  BOOST_CHECK_EQUAL(Name("ndn:/%00%01/%01%FF").getSuccessor(), Name("ndn:/%00%01/%02%00"));
+  BOOST_CHECK_EQUAL(Name("ndn:/%00%01/%FF%FF").getSuccessor(), Name("ndn:/%00%01/%00%00%00"));
+  BOOST_CHECK_EQUAL(Name().getSuccessor(), Name("ndn:/%00"));
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace ndn