name: Make use of naming conventions for segment, version, timestamp, and sequence number encoding
Change-Id: I99fe3965b2a4797bd14b6966b1d1d7d8fc530aef
Refs: #1761
diff --git a/src/name.hpp b/src/name.hpp
index 0e8c840..f4b1411 100644
--- a/src/name.hpp
+++ b/src/name.hpp
@@ -28,10 +28,6 @@
#include "common.hpp"
#include "name-component.hpp"
-#include "util/time.hpp"
-
-#include "encoding/block.hpp"
-#include "encoding/encoding-buffer.hpp"
#include <boost/iterator/reverse_iterator.hpp>
@@ -233,7 +229,9 @@
getSubName(size_t iStartComponent, size_t nComponents) const;
/**
- * Get a new name, constructed as a subset of components starting at iStartComponent until the end of the name.
+ * @brief Get a new name, constructed as a subset of components starting at
+ * iStartComponent until the end of the name.
+ *
* @param iStartComponent The index if the first component to get.
* @return A new name.
*/
@@ -241,13 +239,15 @@
getSubName(size_t iStartComponent) const;
/**
- * Return a new Name with the first nComponents components of this Name.
- * @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.
+ * @brief Return a new Name with the first nComponents components of this Name.
+ *
+ * @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.
*/
Name
- getPrefix(int nComponents) const
+ getPrefix(ssize_t nComponents) const
{
if (nComponents < 0)
return getSubName(0, m_nameBlock.elements_size() + nComponents);
@@ -271,41 +271,87 @@
* @return This name so that you can chain calls to append.
*/
Name&
- appendNumber(uint64_t number)
- {
- m_nameBlock.push_back(Component::fromNumber(number));
- return *this;
- }
+ appendNumber(uint64_t number);
/**
- * @brief An alias for appendNumber(uint64_t)
+ * @brief Create a component encoded as NameComponentWithMarker
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ *
+ * @param marker 1-byte marker octet
+ * @param number The non-negative number
*/
Name&
- appendVersion(uint64_t number)
- {
- return appendNumber(number);
- }
+ appendNumberWithMarker(uint8_t marker, uint64_t number);
/**
- * @brief Append a component with the encoded version number (current UNIX timestamp
- * in milliseconds)
+ * @brief Append version using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendVersion(uint64_t version);
+
+ /**
+ * @brief Append version using NDN naming conventions based on current UNIX timestamp
+ * in milliseconds
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
*/
Name&
appendVersion();
/**
- * @brief An alias for appendNumber(uint64_t)
+ * @brief Append segment number (sequential) using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
*/
Name&
- appendSegment(uint64_t number)
- {
- return appendNumber(number);
- }
+ appendSegment(uint64_t segmentNo);
/**
- * @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
+ * @brief Append segment byte offset using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendSegmentOffset(uint64_t offset);
+
+ /**
+ * @brief Append timestamp using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendTimestamp(const time::system_clock::TimePoint& timePoint = time::system_clock::now());
+
+ /**
+ * @brief Append sequence number using NDN naming conventions
+ *
+ * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendSequenceNumber(uint64_t seqNo);
+
+ /**
+ * @brief Get the successor of a name
+ *
+ * The successor of a name is defined as follows:
+ *
+ * N represents the set of NDN Names, and X,Y ∈ N.
+ * Operator < is defined by canonical order on N.
+ * Y is the successor of X, if (a) X < Y, and (b) ∄ Z ∈ N s.t. X < Z < Y.
+ *
+ * In plain words, successor of a name is the same name, but with its last component
+ * advanced to a next possible value.
+ *
+ * Examples:
+ *
+ * - successor for / is /%00
+ * - successor for /%00%01/%01%02 is /%00%01/%01%03
+ * - successor for /%00%01/%01%FF is /%00%01/%02%00
+ * - successor for /%00%01/%FF%FF is /%00%01/%00%00%00
+ *
* @return a new name
*/
Name
@@ -320,9 +366,12 @@
equals(const Name& name) const;
/**
- * Check if the N components of this name are the same as the first N components of the given name.
+ * @brief Check if the N components of this name are the same as the first N components
+ * of the given name.
+ *
* @param name The Name to check.
- * @return true if this matches the given name, otherwise false. This always returns true if this name is empty.
+ * @return true if this matches the given name, otherwise false. This always returns
+ * true if this name is empty.
*/
bool
isPrefixOf(const Name& name) const;
@@ -534,255 +583,11 @@
mutable Block m_nameBlock;
};
-inline std::ostream&
-operator<<(std::ostream& os, const Name& name)
-{
- if (name.empty())
- {
- os << "/";
- }
- else
- {
- for (Name::const_iterator i = name.begin(); i != name.end(); i++) {
- os << "/";
- i->toUri(os);
- }
- }
- return os;
-}
+std::ostream&
+operator<<(std::ostream& os, const Name& name);
-inline std::string
-Name::toUri() const
-{
- std::ostringstream os;
- os << *this;
- return os.str();
-}
-
-inline std::istream&
-operator>>(std::istream& is, Name& name)
-{
- std::string inputString;
- is >> inputString;
- name.set(inputString);
-
- return is;
-}
-
-
-inline void
-Name::set(const char* uri_cstr)
-{
- clear();
-
- std::string uri = uri_cstr;
- trim(uri);
- if (uri.size() == 0)
- return;
-
- size_t iColon = uri.find(':');
- if (iColon != std::string::npos) {
- // Make sure the colon came before a '/'.
- size_t iFirstSlash = uri.find('/');
- if (iFirstSlash == std::string::npos || iColon < iFirstSlash) {
- // Omit the leading protocol such as ndn:
- uri.erase(0, iColon + 1);
- trim(uri);
- }
- }
-
- // Trim the leading slash and possibly the authority.
- if (uri[0] == '/') {
- if (uri.size() >= 2 && uri[1] == '/') {
- // Strip the authority following "//".
- size_t iAfterAuthority = uri.find('/', 2);
- if (iAfterAuthority == std::string::npos)
- // Unusual case: there was only an authority.
- return;
- else {
- uri.erase(0, iAfterAuthority + 1);
- trim(uri);
- }
- }
- else {
- uri.erase(0, 1);
- trim(uri);
- }
- }
-
- size_t iComponentStart = 0;
-
- // Unescape the components.
- while (iComponentStart < uri.size()) {
- size_t iComponentEnd = uri.find("/", iComponentStart);
- if (iComponentEnd == std::string::npos)
- iComponentEnd = uri.size();
-
- Component component = Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd);
- // Ignore illegal components. This also gets rid of a trailing '/'.
- if (!component.empty())
- append(Component(component));
-
- iComponentStart = iComponentEnd + 1;
- }
-}
-
-inline Name&
-Name::append(const Name& name)
-{
- if (&name == this)
- // Copying from this name, so need to make a copy first.
- return append(Name(name));
-
- for (size_t i = 0; i < name.size(); ++i)
- append(name.at(i));
-
- return *this;
-}
-
-inline Name&
-Name::appendVersion()
-{
- appendNumber(time::toUnixTimestamp(time::system_clock::now()).count());
- return *this;
-}
-
-inline Name
-Name::getSubName(size_t iStartComponent, size_t nComponents) const
-{
- Name result;
-
- size_t iEnd = iStartComponent + nComponents;
- for (size_t i = iStartComponent; i < iEnd && i < size(); ++i)
- result.append(at(i));
-
- return result;
-}
-
-inline Name
-Name::getSubName(size_t iStartComponent) const
-{
- Name result;
-
- for (size_t i = iStartComponent; i < size(); ++i)
- result.append(at(i));
-
- 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
-{
- if (size() != name.size())
- return false;
-
- for (size_t i = 0; i < size(); ++i) {
- if (at(i) != name.at(i))
- return false;
- }
-
- return true;
-}
-
-inline bool
-Name::isPrefixOf(const Name& name) const
-{
- // This name is longer than the name we are checking it against.
- if (size() > name.size())
- return false;
-
- // Check if at least one of given components doesn't match.
- for (size_t i = 0; i < size(); ++i) {
- if (at(i) != name.at(i))
- return false;
- }
-
- return true;
-}
-
-
-inline int
-Name::compare(const Name& other) const
-{
- for (size_t i = 0; i < size() && i < other.size(); ++i) {
- int comparison = at(i).compare(other.at(i));
- if (comparison == 0)
- // The components at this index are equal, so check the next components.
- continue;
-
- // Otherwise, the result is based on the components at this index.
- return comparison;
- }
-
- // The components up to min(this.size(), other.size()) are equal, so the shorter name is less.
- if (size() < other.size())
- return -1;
- else if (size() > other.size())
- return 1;
- else
- return 0;
-}
-
-
-
-template<bool T>
-inline size_t
-Name::wireEncode(EncodingImpl<T>& blk) const
-{
- size_t totalLength = 0;
-
- for (const_reverse_iterator i = rbegin();
- i != rend();
- ++i)
- {
- totalLength += i->wireEncode(blk);
- }
-
- totalLength += blk.prependVarNumber(totalLength);
- totalLength += blk.prependVarNumber(tlv::Name);
- return totalLength;
-}
-
-inline const Block&
-Name::wireEncode() const
-{
- if (m_nameBlock.hasWire())
- return m_nameBlock;
-
- EncodingEstimator estimator;
- size_t estimatedSize = wireEncode(estimator);
-
- EncodingBuffer buffer(estimatedSize, 0);
- wireEncode(buffer);
-
- m_nameBlock = buffer.block();
- m_nameBlock.parse();
-
- return m_nameBlock;
-}
-
-inline void
-Name::wireDecode(const Block& wire)
-{
- if (wire.type() != tlv::Name)
- throw tlv::Error("Unexpected TLV type when decoding Name");
-
- m_nameBlock = wire;
- m_nameBlock.parse();
-}
+std::istream&
+operator>>(std::istream& is, Name& name);
inline bool
Name::hasWire() const