name: Allow negative start index in getSubName method
refs #1962
Change-Id: I2f1b77d95d534d837d925022934f9a6ccaa340d2
diff --git a/src/name.cpp b/src/name.cpp
index c5adb7d..ff698d8 100644
--- a/src/name.cpp
+++ b/src/name.cpp
@@ -188,11 +188,11 @@
}
Name&
-Name::append(const Name& name)
+Name::append(const PartialName& name)
{
if (&name == this)
// Copying from this name, so need to make a copy first.
- return append(Name(name));
+ return append(PartialName(name));
for (size_t i = 0; i < name.size(); ++i)
append(name.at(i));
@@ -270,16 +270,20 @@
return *this;
}
-Name
-Name::getSubName(size_t iStartComponent, size_t nComponents) const
+PartialName
+Name::getSubName(ssize_t iStartComponent, size_t nComponents) const
{
- Name result;
+ PartialName result;
+ ssize_t iStart = iStartComponent < 0 ? this->size() + iStartComponent : iStartComponent;
size_t iEnd = this->size();
- if (nComponents != npos)
- iEnd = std::min(this->size(), iStartComponent + nComponents);
- for (size_t i = iStartComponent; i < iEnd; ++i)
+ iStart = std::max(iStart, static_cast<ssize_t>(0));
+
+ if (nComponents != npos)
+ iEnd = std::min(this->size(), iStart + nComponents);
+
+ for (size_t i = iStart; i < iEnd; ++i)
result.append(at(i));
return result;
diff --git a/src/name.hpp b/src/name.hpp
index 719cf7f2..2cbab7d 100644
--- a/src/name.hpp
+++ b/src/name.hpp
@@ -33,13 +33,22 @@
namespace ndn {
+class Name;
+
/**
- * @brief A Name holds an array of name::Component and represents an NDN name
+ * @brief Partial name abstraction to represent an arbitrary sequence of name components
+ */
+typedef Name PartialName;
+
+/**
+ * @brief Name abstraction to represent an absolute name
*/
class Name : public enable_shared_from_this<Name>
{
public:
- /// @brief Error that can be thrown from Name
+ /**
+ * @brief Error that can be thrown from Name
+ */
class Error : public name::Component::Error
{
public:
@@ -195,12 +204,12 @@
}
/**
- * Append the components of the given name to this name.
- * @param name The Name with components to append.
- * @return This name so that you can chain calls to append.
+ * @brief append a PartialName to this Name.
+ * @param name the components to append
+ * @return this name
*/
Name&
- append(const Name& name);
+ append(const PartialName& name);
/**
* Clear all the components.
@@ -212,24 +221,31 @@
}
/**
- * Get a new name, constructed as a subset of components.
- * @param iStartComponent The index if the first component to get.
+ * @brief Extract a sub-name (PartialName) of @p nComponents components starting
+ * from @p iStartComponent
+ * @param iStartComponent index of the first component;
+ * if iStartComponent is negative, size()+iStartComponent is used instead
* @param nComponents The number of components starting at iStartComponent.
- * Use npos to get the sub Name until the end of this Name.
- * @return A new name.
+ * Use npos to get the Partial Name until the end of this Name.
+ * @detail If iStartComponent is out of bounds and is negative, will return the components
+ * starting in the beginning of the Name
+ * If iStartComponent is out of bounds and is positive, will return the component "/"
+ * If nComponents is out of bounds, will return the components until the end of
+ * this Name
+ * @return A new partial name
*/
- Name
- getSubName(size_t iStartComponent, size_t nComponents = npos) const;
+ PartialName
+ getSubName(ssize_t iStartComponent, size_t nComponents = npos) const;
/**
- * @brief Return a new Name with the first nComponents components of this Name.
+ * @brief Extract a prefix (PartialName) of the name, containing first @p nComponents components
*
* @param nComponents The number of prefix components. If nComponents is -N then return
* the prefix up to name.size() - N. For example getPrefix(-1)
* returns the name without the final component.
- * @return A new Name.
+ * @return A new partial name
*/
- Name
+ PartialName
getPrefix(ssize_t nComponents) const
{
if (nComponents < 0)
diff --git a/tests/unit-tests/name.t.cpp b/tests/unit-tests/name.t.cpp
index 7576b61..0531f59 100644
--- a/tests/unit-tests/name.t.cpp
+++ b/tests/unit-tests/name.t.cpp
@@ -502,6 +502,62 @@
BOOST_CHECK_THROW(Name("/hello//world"), name::Component::Error);
}
+BOOST_AUTO_TEST_CASE(Append)
+{
+ PartialName toAppend("/and");
+ PartialName toAppend1("/beyond");
+ {
+ Name name("/hello/world");
+ BOOST_CHECK_EQUAL("/hello/world/hello/world", name.append(name));
+ BOOST_CHECK_EQUAL("/hello/world/hello/world", name);
+ }
+ {
+ Name name("/hello/world");
+ BOOST_CHECK_EQUAL("/hello/world/and", name.append(toAppend));
+ }
+ {
+ Name name("/hello/world");
+ BOOST_CHECK_EQUAL("/hello/world/and/beyond", name.append(toAppend).append(toAppend1));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(SubName)
+{
+ Name name("/hello/world");
+
+ BOOST_CHECK_EQUAL("/hello/world", name.getSubName(0));
+ BOOST_CHECK_EQUAL("/world", name.getSubName(1));
+ BOOST_CHECK_EQUAL("/hello/", name.getSubName(0, 1));
+}
+
+BOOST_AUTO_TEST_CASE(SubNameNegativeIndex)
+{
+ Name name("/first/second/third/last");
+
+ BOOST_CHECK_EQUAL("/last", name.getSubName(-1));
+ BOOST_CHECK_EQUAL("/third/last", name.getSubName(-2));
+ BOOST_CHECK_EQUAL("/second", name.getSubName(-3, 1));
+}
+
+BOOST_AUTO_TEST_CASE(SubNameOutOfRangeIndexes)
+{
+ Name name("/first/second/last");
+ // No length
+ BOOST_CHECK_EQUAL("/first/second/last", name.getSubName(-10));
+ BOOST_CHECK_EQUAL("/", name.getSubName(10));
+
+ // Starting after the max position
+ BOOST_CHECK_EQUAL("/", name.getSubName(10, 1));
+ BOOST_CHECK_EQUAL("/", name.getSubName(10, 10));
+
+ // Not enough components
+ BOOST_CHECK_EQUAL("/second/last", name.getSubName(1, 10));
+ BOOST_CHECK_EQUAL("/last", name.getSubName(-1, 10));
+
+ // Start before first
+ BOOST_CHECK_EQUAL("/first/second", name.getSubName(-10, 2));
+ BOOST_CHECK_EQUAL("/first/second/last", name.getSubName(-10, 10));
+}
BOOST_AUTO_TEST_SUITE_END()