name: reorganize Name class
* Categorize class methods.
* Make append component methods inline.
* Make comparison operators non-member functions.
* Improve Doxygen.
* Simplify Name::at implementation.
* Reorder test cases.
* Add test coverage for Name::empty() and iterators.
* Make naming convention test case more readable,
and move it to TestNameComponent test suite.
refs #4171
Change-Id: I5f7deff2535f8265ac4942f892879dd7e56f6414
diff --git a/src/name.cpp b/src/name.cpp
index ad15d08..58b1cc3 100644
--- a/src/name.cpp
+++ b/src/name.cpp
@@ -1,5 +1,5 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
* Copyright (c) 2013-2017 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -25,10 +25,11 @@
#include "name.hpp"
-#include "util/time.hpp"
#include "encoding/block.hpp"
#include "encoding/encoding-buffer.hpp"
+#include "util/time.hpp"
+#include <sstream>
#include <boost/algorithm/string/trim.hpp>
#include <boost/functional/hash.hpp>
@@ -43,15 +44,17 @@
const size_t Name::npos = std::numeric_limits<size_t>::max();
+// ---- constructors, encoding, decoding ----
+
Name::Name()
- : m_nameBlock(tlv::Name)
+ : m_wire(tlv::Name)
{
}
Name::Name(const Block& wire)
{
- m_nameBlock = wire;
- m_nameBlock.parse();
+ m_wire = wire;
+ m_wire.parse();
}
Name::Name(const char* uri)
@@ -108,13 +111,12 @@
}
}
-Name
-Name::deepCopy() const
+std::string
+Name::toUri() const
{
- Name copiedName(*this);
- copiedName.m_nameBlock.resetWire();
- copiedName.wireEncode(); // "compress" the underlying buffer
- return copiedName;
+ std::ostringstream os;
+ os << *this;
+ return os.str();
}
template<encoding::Tag TAG>
@@ -123,10 +125,9 @@
{
size_t totalLength = 0;
- for (const_reverse_iterator i = rbegin(); i != rend(); ++i)
- {
- totalLength += i->wireEncode(encoder);
- }
+ for (const_reverse_iterator i = rbegin(); i != rend(); ++i) {
+ totalLength += i->wireEncode(encoder);
+ }
totalLength += encoder.prependVarNumber(totalLength);
totalLength += encoder.prependVarNumber(tlv::Name);
@@ -142,8 +143,8 @@
const Block&
Name::wireEncode() const
{
- if (m_nameBlock.hasWire())
- return m_nameBlock;
+ if (m_wire.hasWire())
+ return m_wire;
EncodingEstimator estimator;
size_t estimatedSize = wireEncode(estimator);
@@ -151,10 +152,10 @@
EncodingBuffer buffer(estimatedSize, 0);
wireEncode(buffer);
- m_nameBlock = buffer.block();
- m_nameBlock.parse();
+ m_wire = buffer.block();
+ m_wire.parse();
- return m_nameBlock;
+ return m_wire;
}
void
@@ -163,99 +164,33 @@
if (wire.type() != tlv::Name)
BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Name"));
- m_nameBlock = wire;
- m_nameBlock.parse();
+ m_wire = wire;
+ m_wire.parse();
}
-std::string
-Name::toUri() const
+Name
+Name::deepCopy() const
{
- std::ostringstream os;
- os << *this;
- return os.str();
+ Name copiedName(*this);
+ copiedName.m_wire.resetWire();
+ copiedName.wireEncode(); // "compress" the underlying buffer
+ return copiedName;
}
-Name&
-Name::append(const PartialName& name)
+// ---- accessors ----
+
+const name::Component&
+Name::at(ssize_t i) const
{
- if (&name == this)
- // Copying from this name, so need to make a copy first.
- return append(PartialName(name));
+ if (i < 0) {
+ i = size() + i;
+ }
- for (size_t i = 0; i < name.size(); ++i)
- append(name.at(i));
+ if (i < 0 || static_cast<size_t>(i) >= size()) {
+ BOOST_THROW_EXCEPTION(Error("Requested component does not exist (out of bounds)"));
+ }
- return *this;
-}
-
-Name&
-Name::appendNumber(uint64_t number)
-{
- m_nameBlock.push_back(Component::fromNumber(number));
- return *this;
-}
-
-Name&
-Name::appendNumberWithMarker(uint8_t marker, uint64_t number)
-{
- m_nameBlock.push_back(Component::fromNumberWithMarker(marker, number));
- return *this;
-}
-
-Name&
-Name::appendVersion(uint64_t version)
-{
- m_nameBlock.push_back(Component::fromVersion(version));
- return *this;
-}
-
-Name&
-Name::appendVersion()
-{
- appendVersion(time::toUnixTimestamp(time::system_clock::now()).count());
- return *this;
-}
-
-Name&
-Name::appendSegment(uint64_t segmentNo)
-{
- m_nameBlock.push_back(Component::fromSegment(segmentNo));
- return *this;
-}
-
-Name&
-Name::appendSegmentOffset(uint64_t offset)
-{
- m_nameBlock.push_back(Component::fromSegmentOffset(offset));
- return *this;
-}
-
-Name&
-Name::appendTimestamp(const time::system_clock::TimePoint& timePoint)
-{
- m_nameBlock.push_back(Component::fromTimestamp(timePoint));
- return *this;
-}
-
-Name&
-Name::appendSequenceNumber(uint64_t seqNo)
-{
- m_nameBlock.push_back(Component::fromSequenceNumber(seqNo));
- return *this;
-}
-
-Name&
-Name::appendImplicitSha256Digest(const ConstBufferPtr& digest)
-{
- m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest));
- return *this;
-}
-
-Name&
-Name::appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
-{
- m_nameBlock.push_back(Component::fromImplicitSha256Digest(digest, digestSize));
- return *this;
+ return reinterpret_cast<const Component&>(m_wire.elements()[i]);
}
PartialName
@@ -277,11 +212,40 @@
return result;
}
+// ---- modifiers ----
+
+Name&
+Name::appendVersion()
+{
+ return appendVersion(time::toUnixTimestamp(time::system_clock::now()).count());
+}
+
+Name&
+Name::appendTimestamp()
+{
+ return appendTimestamp(time::system_clock::now());
+}
+
+Name&
+Name::append(const PartialName& name)
+{
+ if (&name == this)
+ // Copying from this name, so need to make a copy first.
+ return append(PartialName(name));
+
+ for (size_t i = 0; i < name.size(); ++i)
+ append(name.at(i));
+
+ return *this;
+}
+
+// ---- algorithms ----
+
Name
Name::getSuccessor() const
{
if (empty()) {
- static uint8_t firstValue[] = { 0 };
+ static uint8_t firstValue[] {0};
Name firstName;
firstName.append(firstValue, 1);
return firstName;
@@ -291,13 +255,15 @@
}
bool
-Name::equals(const Name& name) const
+Name::isPrefixOf(const Name& other) const
{
- if (size() != name.size())
+ // This name is longer than the name we are checking against.
+ if (size() > other.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))
+ if (get(i) != other.get(i))
return false;
}
@@ -305,15 +271,13 @@
}
bool
-Name::isPrefixOf(const Name& name) const
+Name::equals(const Name& other) const
{
- // This name is longer than the name we are checking against.
- if (size() > name.size())
+ if (size() != other.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))
+ if (get(i) != other.get(i))
return false;
}
@@ -328,7 +292,7 @@
size_t count = std::min(count1, count2);
for (size_t i = 0; i < count; ++i) {
- int comp = this->at(pos1 + i).compare(other.at(pos2 + i));
+ int comp = get(pos1 + i).compare(other.get(pos2 + i));
if (comp != 0) { // i-th component differs
return comp;
}
@@ -337,20 +301,20 @@
return count1 - count2;
}
+// ---- stream operators ----
+
std::ostream&
operator<<(std::ostream& os, const Name& name)
{
- if (name.empty())
- {
+ if (name.empty()) {
+ os << "/";
+ }
+ else {
+ for (const auto& component : name) {
os << "/";
+ component.toUri(os);
}
- else
- {
- for (Name::const_iterator i = name.begin(); i != name.end(); i++) {
- os << "/";
- i->toUri(os);
- }
- }
+ }
return os;
}
@@ -367,6 +331,7 @@
} // namespace ndn
namespace std {
+
size_t
hash<ndn::Name>::operator()(const ndn::Name& name) const
{
diff --git a/src/name.hpp b/src/name.hpp
index 880343c..1760def 100644
--- a/src/name.hpp
+++ b/src/name.hpp
@@ -26,29 +26,22 @@
#ifndef NDN_NAME_HPP
#define NDN_NAME_HPP
-#include "common.hpp"
#include "name-component.hpp"
-
#include <boost/iterator/reverse_iterator.hpp>
namespace ndn {
class Name;
-/**
- * @brief Partial name abstraction to represent an arbitrary sequence of name components
+/** @brief Represents an arbitrary sequence of name components
*/
-typedef Name PartialName;
+using PartialName = Name;
-/**
- * @brief Name abstraction to represent an absolute name
+/** @brief Represents an absolute name
*/
class Name
{
-public:
- /**
- * @brief Error that can be thrown from Name
- */
+public: // nested types
class Error : public name::Component::Error
{
public:
@@ -59,180 +52,156 @@
}
};
- typedef name::Component Component;
+ using Component = name::Component;
+ using component_container = std::vector<Component>;
- typedef std::vector<Component> component_container;
+ // Name appears as a container of name components
+ using value_type = Component;
+ using allocator_type = void;
+ using reference = Component&;
+ using const_reference = const Component;
+ using pointer = Component*;
+ using const_pointer = const Component*;
+ using iterator = Component*;
+ using const_iterator = const Component*;
+ using reverse_iterator = boost::reverse_iterator<iterator>;
+ using const_reverse_iterator = boost::reverse_iterator<const_iterator>;
+ using difference_type = component_container::difference_type;
+ using size_type = component_container::size_type;
- typedef Component value_type;
- typedef void allocator_type;
- typedef Component& reference;
- typedef const Component const_reference;
- typedef Component* pointer;
- typedef const Component* const_pointer;
- typedef Component* iterator;
- typedef const Component* const_iterator;
-
- typedef boost::reverse_iterator<iterator> reverse_iterator;
- typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
-
- typedef component_container::difference_type difference_type;
- typedef component_container::size_type size_type;
-
- /**
- * @brief Create a new Name with no components.
+public: // constructors, encoding, decoding
+ /** @brief Create an empty name
+ * @post empty() == true
*/
Name();
- /**
- * @brief Create Name object from wire block
+ /** @brief Decode Name from wire encoding
+ * @throw tlv::Error wire encoding is invalid
*
- * This is a more efficient equivalent for
- * @code
+ * This is a more efficient equivalent for
+ * @code
* Name name;
* name.wireDecode(wire);
- * @endcode
+ * @endcode
*/
explicit
Name(const Block& wire);
- /**
- * @brief Create name from @p uri (NDN URI scheme)
- * @param uri The null-terminated URI string
+ /** @brief Parse name from NDN URI
+ * @param uri a null-terminated URI string
+ * @sa https://named-data.net/doc/ndn-tlv/name.html#ndn-uri-scheme
*/
Name(const char* uri);
- /**
- * @brief Create name from @p uri (NDN URI scheme)
- * @param uri The URI string
+ /** @brief Create name from NDN URI
+ * @param uri a URI string
+ * @sa https://named-data.net/doc/ndn-tlv/name.html#ndn-uri-scheme
*/
Name(std::string uri);
- /**
- * @brief Make a deep copy of the name, reallocating the underlying memory buffer
+ /** @brief Get URI representation of the name
+ * @return URI representation; "ndn:" scheme identifier is not included
+ * @sa https://named-data.net/doc/ndn-tlv/name.html#ndn-uri-scheme
+ * @note To print URI representation into a stream, it is more efficient to use ``os << name``.
*/
- Name
- deepCopy() const;
+ std::string
+ toUri() const;
- /**
- * @brief Fast encoding or block size estimation
+ /** @brief Check if this Name instance already has wire encoding
+ */
+ bool
+ hasWire() const
+ {
+ return m_wire.hasWire();
+ }
+
+ /** @brief Fast encoding or block size estimation
*/
template<encoding::Tag TAG>
size_t
wireEncode(EncodingImpl<TAG>& encoder) const;
+ /** @brief Perform wire encoding, or return existing wire encoding
+ * @post hasWire() == true
+ */
const Block&
wireEncode() const;
+ /** @brief Decode name from wire encoding
+ * @throw tlv::Error wire encoding is invalid
+ * @post hasWire() == true
+ */
void
wireDecode(const Block& wire);
- /**
- * @brief Check if already has wire
+ /** @brief Make a deep copy of the name, reallocating the underlying memory buffer
+ */
+ Name
+ deepCopy() const;
+
+public: // access
+ /** @brief Check if name is empty
*/
bool
- hasWire() const;
-
- /**
- * @brief Append a new component, copying from value of length valueLength.
- * @return This name so that you can chain calls to append.
- */
- Name&
- append(const uint8_t* value, size_t valueLength)
+ empty() const
{
- m_nameBlock.push_back(Component(value, valueLength));
- return *this;
+ return m_wire.elements().empty();
}
- /**
- * @brief Append a new component, copying from value frome the range [@p first, @p last) of bytes
- * @param first Iterator pointing to the beginning of the buffer
- * @param last Iterator pointing to the ending of the buffer
- * @tparam Iterator iterator type satisfying at least InputIterator concept. Implementation
- * is more optimal when the iterator type satisfies RandomAccessIterator concept.
- * It is required that sizeof(std::iterator_traits<Iterator>::value_type) == 1.
- * @return This name so that you can chain calls to append.
+ /** @brief Get number of components
*/
- template<class Iterator>
- Name&
- append(Iterator first, Iterator last)
+ size_t
+ size() const
{
- m_nameBlock.push_back(Component(first, last));
- return *this;
+ return m_wire.elements_size();
}
- /**
- * @brief Append component @p value
+ /** @brief Get the component at the given index
+ * @param i zero-based index; if negative, it starts at the end of this name
+ * @warning Indexing out of bounds triggers undefined behavior.
*/
- Name&
- append(const Component& value)
+ const Component&
+ get(ssize_t i) const
{
- m_nameBlock.push_back(value);
- return *this;
+ if (i < 0) {
+ i += size();
+ }
+ return reinterpret_cast<const Component&>(m_wire.elements()[i]);
}
- /**
- * @brief Append name component that represented as a string
+ /** @brief Equivalent to get(i)
+ */
+ const Component&
+ operator[](ssize_t i) const
+ {
+ return get(i);
+ }
+
+ /** @brief Get the component at the given index
+ * @param i zero-based index; if negative, size()+i is used instead
+ * @throws Name::Error index is out of bounds
+ */
+ const Component&
+ at(ssize_t i) const;
+
+ /** @brief Extract some components as a sub-name (PartialName)
+ * @param iStartComponent zero-based index of the first component;
+ * if negative, size()+iStartComponent is used instead
+ * @param nComponents Number of components starting at iStartComponent.
+ * Use @p npos to get the PartialName until the end of this Name.
+ * @return a new PartialName containing the extracted components
*
- * Note that this method is necessary to ensure correctness and unambiguity of
- * ``append("string")`` operations (both Component and Name can be implicitly
- * converted from string, each having different outcomes
- */
- Name&
- append(const char* value)
- {
- m_nameBlock.push_back(Component(value));
- return *this;
- }
-
- Name&
- append(const Block& value)
- {
- if (value.type() == tlv::NameComponent)
- m_nameBlock.push_back(value);
- else
- m_nameBlock.push_back(Block(tlv::NameComponent, value));
-
- return *this;
- }
-
- /**
- * @brief append a PartialName to this Name.
- * @param name the components to append
- * @return this name
- */
- Name&
- append(const PartialName& name);
-
- /**
- * Clear all the components.
- */
- void
- clear()
- {
- m_nameBlock = Block(tlv::Name);
- }
-
- /**
- * @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 Partial Name until the end of this Name.
- * @details If iStartComponent is out of bounds and is negative, returns the components
- * starting from the beginning of the Name.
- * If iStartComponent is out of bounds and is positive, returns the component "/".
- * If nComponents is out of bounds, returns the components until the end of
- * this Name
- * @return A new partial name
+ * If iStartComponent is positive and indexes out of bounds, returns an empty PartialName.
+ * If iStartComponent is negative and indexes out of bounds, returns components starting from the
+ * beginning of the Name. If nComponents is out of bounds, returns the components until the end
+ * of this Name.
*/
PartialName
getSubName(ssize_t iStartComponent, size_t nComponents = npos) const;
- /**
- * @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
+ /** @brief Extract a prefix of the name
+ * @param nComponents Number of components; if negative, size()+nComponents is used instead
+ * @return a new Name containing the prefix
* the prefix up to name.size() - N. For example getPrefix(-1)
* returns the name without the final component.
* @return A new partial name
@@ -241,348 +210,31 @@
getPrefix(ssize_t nComponents) const
{
if (nComponents < 0)
- return getSubName(0, m_nameBlock.elements_size() + nComponents);
+ return getSubName(0, size() + nComponents);
else
return getSubName(0, nComponents);
}
- /**
- * Encode this name as a URI.
- * @return The encoded URI.
- */
- std::string
- toUri() const;
-
- /**
- * @brief Append a component with the number encoded as nonNegativeInteger
- *
- * @see http://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
- *
- * @param number The non-negative number
- * @return This name so that you can chain calls to append.
- */
- Name&
- appendNumber(uint64_t number);
-
- /**
- * @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&
- appendNumberWithMarker(uint8_t marker, uint64_t number);
-
- /**
- * @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 Append segment number (sequential) using NDN naming conventions
- *
- * @see http://named-data.net/doc/tech-memos/naming-conventions.pdf
- */
- Name&
- appendSegment(uint64_t segmentNo);
-
- /**
- * @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 Append ImplicitSha256Digest
- */
- Name&
- appendImplicitSha256Digest(const ConstBufferPtr& digest);
-
- /**
- * @brief Append ImplicitSha256Digest
- */
- Name&
- appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize);
-
- /**
- * @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
- 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.
- */
- bool
- equals(const Name& name) const;
-
- /**
- * @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.
- */
- bool
- isPrefixOf(const Name& name) const;
-
- //
- // vector equivalent interface.
- //
-
- /**
- * @brief Check if name is emtpy
- */
- bool
- empty() const
- {
- return m_nameBlock.elements().empty();
- }
-
- /**
- * Get the number of components.
- * @return The number of components.
- */
- size_t
- size() const
- {
- return m_nameBlock.elements_size();
- }
-
- /**
- * Get the component at the given index.
- * @param i The index of the component, starting from 0.
- * @return The name component at the index.
- */
- const Component&
- get(ssize_t i) const
- {
- if (i >= 0)
- return reinterpret_cast<const Component&>(m_nameBlock.elements()[i]);
- else
- return reinterpret_cast<const Component&>(m_nameBlock.elements()[size() + i]);
- }
-
- const Component&
- operator[](ssize_t i) const
- {
- return get(i);
- }
-
- /**
- * @brief Get component at the specified index
- *
- * Unlike get() and operator[] methods, at() checks for out of bounds
- * and will throw Name::Error when it happens
- *
- * @throws Name::Error if index out of bounds
- */
- const Component&
- at(ssize_t i) const
- {
- if ((i >= 0 && static_cast<size_t>(i) >= size()) ||
- (i < 0 && static_cast<size_t>(-i) > size()))
- BOOST_THROW_EXCEPTION(Error("Requested component does not exist (out of bounds)"));
-
- return get(i);
- }
-
- /**
- * @brief Compare this to the other Name using NDN canonical ordering.
- *
- * If the first components of each name are not equal, this returns a negative value if
- * the first comes before the second using the NDN canonical ordering for name
- * components, or a positive value if it comes after. If they are equal, this compares
- * the second components of each name, etc. If both names are the same up to the size
- * of the shorter name, this returns a negative value if the first name is shorter than
- * the second or a positive value if it is longer. For example, if you std::sort gives:
- * /a/b/d /a/b/cc /c /c/a /bb .
- * This is intuitive because all names with the prefix /a are next to each other.
- * But it may be also be counter-intuitive because /c comes before /bb according
- * to NDN canonical ordering since it is shorter.
- *
- * @param other The other Name to compare with.
- *
- * @retval negative this comes before other in canonical ordering
- * @retval zero this equals other
- * @retval positive this comes after other in canonical ordering
- *
- * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
- */
- int
- compare(const Name& other) const
- {
- return this->compare(0, npos, other);
- }
-
- /** \brief compares [pos1, pos1+count1) components in this Name
- * to [pos2, pos2+count2) components in \p other
- *
- * This is equivalent to this->getSubName(pos1, count1).compare(other.getSubName(pos2, count2));
- */
- int
- compare(size_t pos1, size_t count1,
- const Name& other, size_t pos2 = 0, size_t count2 = npos) const;
-
- /**
- * Append the component
- * @param component The component of type T.
- */
- template<class T> void
- push_back(const T& component)
- {
- append(component);
- }
-
- /**
- * 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.
- */
- bool
- operator==(const Name& name) const
- {
- return equals(name);
- }
-
- /**
- * 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 not equal, otherwise false.
- */
- bool
- operator!=(const Name& name) const
- {
- return !equals(name);
- }
-
- /**
- * Return true if this is less than or equal to the other Name in the NDN canonical ordering.
- * @param other The other Name to compare with.
- *
- * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
- */
- bool
- operator<=(const Name& other) const
- {
- return compare(other) <= 0;
- }
-
- /**
- * Return true if this is less than the other Name in the NDN canonical ordering.
- * @param other The other Name to compare with.
- *
- * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
- */
- bool
- operator<(const Name& other) const
- {
- return compare(other) < 0;
- }
-
- /**
- * Return true if this is less than or equal to the other Name in the NDN canonical ordering.
- * @param other The other Name to compare with.
- *
- * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
- */
- bool
- operator>=(const Name& other) const
- {
- return compare(other) >= 0;
- }
-
- /**
- * Return true if this is greater than the other Name in the NDN canonical ordering.
- * @param other The other Name to compare with.
- *
- * @see http://named-data.net/doc/ndn-tlv/name.html#canonical-order
- */
- bool
- operator>(const Name& other) const
- {
- return compare(other) > 0;
- }
-
- //
- // Iterator interface to name components.
- //
-
- /**
- * Begin iterator (const).
+public: // iterators
+ /** @brief Begin iterator
*/
const_iterator
begin() const
{
- return reinterpret_cast<const_iterator>(&*m_nameBlock.elements().begin());
+ // XXX This triggers undefined behavior if name is empty (#4181)
+ return reinterpret_cast<const_iterator>(&*m_wire.elements().begin());
}
- /**
- * End iterator (const).
- *
- * @todo Check if this crash when there are no elements in the buffer
+ /** @brief End iterator
*/
const_iterator
end() const
{
- return reinterpret_cast<const_iterator>(&*m_nameBlock.elements().end());
+ // XXX This triggers undefined behavior if name is empty (#4181)
+ return reinterpret_cast<const_iterator>(&*m_wire.elements().end());
}
- /**
- * Reverse begin iterator (const).
+ /** @brief Reverse begin iterator
*/
const_reverse_iterator
rbegin() const
@@ -590,8 +242,7 @@
return const_reverse_iterator(end());
}
- /**
- * Reverse end iterator (const).
+ /** @brief Reverse end iterator
*/
const_reverse_iterator
rend() const
@@ -599,30 +250,350 @@
return const_reverse_iterator(begin());
}
+public: // modifiers
+ /** @brief Append a component
+ * @return a reference to this name, to allow chaining
+ */
+ Name&
+ append(const Component& component)
+ {
+ m_wire.push_back(component);
+ return *this;
+ }
+
+ /** @brief Append a component, copying from a zero-terminated byte string
+ * @param value a zero-terminated string; it will be constructed as a component as is
+ * and will not be interpreted as a URI
+ * @note This overload is necessary to ensure unambiguity of ``append("string")``, because both
+ * Component and PartialName are implicitly convertible from zero-terminated byte string.
+ * This overload ensures the string is constructed as a Component.
+ */
+ Name&
+ append(const char* value)
+ {
+ return append(Component(value));
+ }
+
+ /** @brief Append a component, copying from [@p value, @p value + @p valueLength)
+ * @return a reference to this name, to allow chaining
+ */
+ Name&
+ append(const uint8_t* value, size_t valueLength)
+ {
+ return append(Component(value, valueLength));
+ }
+
+ /** @brief Append a component, copying from [@p first, @p last)
+ * @tparam Iterator an InputIterator dereferencing to a one-octet value type. More efficient
+ * implementation is available when @p Iterator additionally satisfies
+ * RandomAccessIterator concept.
+ * @param first begin position of the value
+ * @param last end position of the value
+ * @return a reference to this name, to allow chaining
+ */
+ template<class Iterator>
+ Name&
+ append(Iterator first, Iterator last)
+ {
+ static_assert(sizeof(std::iterator_traits<Iterator>::value_type) == 1,
+ "iterator does not dereference to one-octet value type");
+ return append(Component(first, last));
+ }
+
+ /** @brief Append a component, decoding from a Block
+ * @param value a Block; if its TLV-TYPE is not NameComponent, it is nested into a NameComponent
+ * @return a reference to this name, to allow chaining
+ */
+ Name&
+ append(const Block& value)
+ {
+ if (value.type() == tlv::NameComponent) {
+ m_wire.push_back(value);
+ }
+ else {
+ m_wire.push_back(Block(tlv::NameComponent, value));
+ }
+
+ return *this;
+ }
+
+ /** @brief Append a component with a nonNegativeInteger
+ * @sa number the number
+ * @return a reference to this name, to allow chaining
+ * @sa https://named-data.net/doc/ndn-tlv/tlv.html#non-negative-integer-encoding
+ */
+ Name&
+ appendNumber(uint64_t number)
+ {
+ return append(Component::fromNumber(number));
+ }
+
+ /** @brief Append a component with a marked number
+ * @param marker 1-octet marker
+ * @param number the number
+ *
+ * The component is encoded as a 1-octet marker, followed by a nonNegativeInteger.
+ *
+ * @return a reference to this name, to allow chaining
+ * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendNumberWithMarker(uint8_t marker, uint64_t number)
+ {
+ return append(Component::fromNumberWithMarker(marker, number));
+ }
+
+ /** @brief Append a version component
+ * @return a reference to this name, to allow chaining
+ * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendVersion(uint64_t version)
+ {
+ return append(Component::fromVersion(version));
+ }
+
+ /** @brief Append a version component based on current time
+ *
+ * The version number is the current UNIX timestamp in milliseconds
+ *
+ * @return a reference to this name, to allow chaining
+ * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendVersion();
+
+ /** @brief Append a segment number (sequential) component
+ * @return a reference to this name, to allow chaining
+ * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendSegment(uint64_t segmentNo)
+ {
+ return append(Component::fromSegment(segmentNo));
+ }
+
+ /** @brief Append a segment byte offset component
+ * @return a reference to this name, to allow chaining
+ * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendSegmentOffset(uint64_t offset)
+ {
+ return append(Component::fromSegmentOffset(offset));
+ }
+
+ /** @brief Append a timestamp component
+ * @return a reference to this name, to allow chaining
+ * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendTimestamp(const time::system_clock::TimePoint& timePoint)
+ {
+ return append(Component::fromTimestamp(timePoint));
+ }
+
+ /** @brief Append a timestamp component based on current time
+ * @return a reference to this name, to allow chaining
+ * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendTimestamp();
+
+ /** @brief Append a sequence number component
+ * @return a reference to this name, to allow chaining
+ * @sa NDN Naming Conventions https://named-data.net/doc/tech-memos/naming-conventions.pdf
+ */
+ Name&
+ appendSequenceNumber(uint64_t seqNo)
+ {
+ return append(Component::fromSequenceNumber(seqNo));
+ }
+
+ /** @brief Append an ImplicitSha256Digest component
+ * @return a reference to this name, to allow chaining
+ */
+ Name&
+ appendImplicitSha256Digest(const ConstBufferPtr& digest)
+ {
+ return append(Component::fromImplicitSha256Digest(digest));
+ }
+
+ /** @brief Append an ImplicitSha256Digest component
+ * @return a reference to this name, to allow chaining
+ */
+ Name&
+ appendImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
+ {
+ return append(Component::fromImplicitSha256Digest(digest, digestSize));
+ }
+
+ /** @brief Append a PartialName
+ * @param name the components to append
+ * @return a reference to this name, to allow chaining
+ */
+ Name&
+ append(const PartialName& name);
+
+ /** @brief Append a component
+ * @note This makes push_back an alias of append, giving Name a similar API as STL vector.
+ */
+ template<class T>
+ void
+ push_back(const T& component)
+ {
+ append(component);
+ }
+
+ /** @brief Remove all components
+ * @post empty() == true
+ */
+ void
+ clear()
+ {
+ m_wire = Block(tlv::Name);
+ }
+
+public: // algorithms
+ /** @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 containing the successor
+ */
+ Name
+ getSuccessor() const;
+
+ /** @brief Check if this name is a prefix of another name
+ *
+ * This name is a prefix of @p other if the N components of this name are same as the first N
+ * components of @p other.
+ *
+ * @retval true this name is a prefix of @p other
+ * @retval false this name is not a prefix of @p other
+ */
+ bool
+ isPrefixOf(const Name& other) const;
+
+ /** @brief Check if this name equals another name
+ *
+ * Two names are equal if they have the same number of components, and components at each index
+ * are equal.
+ */
+ bool
+ equals(const Name& other) const;
+
+ /** @brief Compare this to the other Name using NDN canonical ordering.
+ *
+ * If the first components of each name are not equal, this returns a negative value if
+ * the first comes before the second using the NDN canonical ordering for name
+ * components, or a positive value if it comes after. If they are equal, this compares
+ * the second components of each name, etc. If both names are the same up to the size
+ * of the shorter name, this returns a negative value if the first name is shorter than
+ * the second or a positive value if it is longer. For example, if you std::sort gives:
+ * /a/b/d /a/b/cc /c /c/a /bb .
+ * This is intuitive because all names with the prefix /a are next to each other.
+ * But it may be also be counter-intuitive because /c comes before /bb according
+ * to NDN canonical ordering since it is shorter.
+ *
+ * @param other The other Name to compare with.
+ *
+ * @retval negative this comes before other in canonical ordering
+ * @retval zero this equals other
+ * @retval positive this comes after other in canonical ordering
+ *
+ * @sa https://named-data.net/doc/ndn-tlv/name.html#canonical-order
+ */
+ int
+ compare(const Name& other) const
+ {
+ return this->compare(0, npos, other);
+ }
+
+ /** @brief compares [pos1, pos1+count1) components in this Name
+ * to [pos2, pos2+count2) components in @p other
+ *
+ * This is equivalent to this->getSubName(pos1, count1).compare(other.getSubName(pos2, count2));
+ */
+ int
+ compare(size_t pos1, size_t count1,
+ const Name& other, size_t pos2 = 0, size_t count2 = npos) const;
+
public:
/** \brief indicates "until the end" in getSubName and compare
*/
static const size_t npos;
private:
- mutable Block m_nameBlock;
+ mutable Block m_wire;
};
+inline bool
+operator==(const Name& lhs, const Name& rhs)
+{
+ return lhs.equals(rhs);
+}
+
+inline bool
+operator!=(const Name& lhs, const Name& rhs)
+{
+ return !lhs.equals(rhs);
+}
+
+inline bool
+operator<=(const Name& lhs, const Name& rhs)
+{
+ return lhs.compare(rhs) <= 0;
+}
+
+inline bool
+operator<(const Name& lhs, const Name& rhs)
+{
+ return lhs.compare(rhs) < 0;
+}
+
+inline bool
+operator>=(const Name& lhs, const Name& rhs)
+{
+ return lhs.compare(rhs) >= 0;
+}
+
+inline bool
+operator>(const Name& lhs, const Name& rhs)
+{
+ return lhs.compare(rhs) > 0;
+}
+
+/** @brief Print URI representation of a name
+ * @sa https://named-data.net/doc/ndn-tlv/name.html#ndn-uri-scheme
+ */
std::ostream&
operator<<(std::ostream& os, const Name& name);
+/** @brief Parse URI from stream as Name
+ * @sa https://named-data.net/doc/ndn-tlv/name.html#ndn-uri-scheme
+ */
std::istream&
operator>>(std::istream& is, Name& name);
-inline bool
-Name::hasWire() const
-{
- return m_nameBlock.hasWire();
-}
-
} // namespace ndn
namespace std {
+
template<>
struct hash<ndn::Name>
{
diff --git a/tests/unit-tests/name-component.t.cpp b/tests/unit-tests/name-component.t.cpp
index 8a99b2f..651b160 100644
--- a/tests/unit-tests/name-component.t.cpp
+++ b/tests/unit-tests/name-component.t.cpp
@@ -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).
*
@@ -20,6 +20,7 @@
*/
#include "name-component.hpp"
+#include "name.hpp"
#include "boost-test.hpp"
#include <boost/mpl/vector.hpp>
@@ -205,6 +206,149 @@
BOOST_AUTO_TEST_SUITE_END() // CreateFromIterators
+BOOST_AUTO_TEST_SUITE(NamingConvention)
+
+template<typename ArgType>
+struct ConventionTest
+{
+ function<name::Component(ArgType)> makeComponent;
+ function<ArgType(const name::Component&)> getValue;
+ function<Name&(Name&, ArgType)> append;
+ Name expected;
+ ArgType value;
+ function<bool(const name::Component&)> isComponent;
+};
+
+class NumberWithMarker
+{
+public:
+ ConventionTest<uint64_t>
+ operator()() const
+ {
+ return {bind(&name::Component::fromNumberWithMarker, 0xAA, _1),
+ bind(&name::Component::toNumberWithMarker, _1, 0xAA),
+ bind(&Name::appendNumberWithMarker, _1, 0xAA, _2),
+ Name("/%AA%03%E8"),
+ 1000,
+ bind(&name::Component::isNumberWithMarker, _1, 0xAA)};
+ }
+};
+
+class Segment
+{
+public:
+ ConventionTest<uint64_t>
+ operator()() const
+ {
+ return {&name::Component::fromSegment,
+ bind(&name::Component::toSegment, _1),
+ bind(&Name::appendSegment, _1, _2),
+ Name("/%00%27%10"),
+ 10000,
+ bind(&name::Component::isSegment, _1)};
+ }
+};
+
+class SegmentOffset
+{
+public:
+ ConventionTest<uint64_t>
+ operator()() const
+ {
+ return {&name::Component::fromSegmentOffset,
+ bind(&name::Component::toSegmentOffset, _1),
+ bind(&Name::appendSegmentOffset, _1, _2),
+ Name("/%FB%00%01%86%A0"),
+ 100000,
+ bind(&name::Component::isSegmentOffset, _1)};
+ }
+};
+
+class Version
+{
+public:
+ ConventionTest<uint64_t>
+ operator()() const
+ {
+ return {&name::Component::fromVersion,
+ bind(&name::Component::toVersion, _1),
+ [] (Name& name, uint64_t version) -> Name& { return name.appendVersion(version); },
+ Name("/%FD%00%0FB%40"),
+ 1000000,
+ bind(&name::Component::isVersion, _1)};
+ }
+};
+
+class Timestamp
+{
+public:
+ ConventionTest<time::system_clock::TimePoint>
+ operator()() const
+ {
+ return {&name::Component::fromTimestamp,
+ bind(&name::Component::toTimestamp, _1),
+ [] (Name& name, time::system_clock::TimePoint t) -> Name& { return name.appendTimestamp(t); },
+ Name("/%FC%00%04%7BE%E3%1B%00%00"),
+ time::getUnixEpoch() + time::days(14600), // 40 years
+ bind(&name::Component::isTimestamp, _1)};
+ }
+};
+
+class SequenceNumber
+{
+public:
+ ConventionTest<uint64_t>
+ operator()() const
+ {
+ return {&name::Component::fromSequenceNumber,
+ bind(&name::Component::toSequenceNumber, _1),
+ bind(&Name::appendSequenceNumber, _1, _2),
+ Name("/%FE%00%98%96%80"),
+ 10000000,
+ bind(&name::Component::isSequenceNumber, _1)};
+ }
+};
+
+using ConventionTests = boost::mpl::vector<
+ NumberWithMarker,
+ Segment,
+ SegmentOffset,
+ Version,
+ Timestamp,
+ SequenceNumber
+>;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(Convention, T, ConventionTests)
+{
+ name::Component invalidComponent1;
+ name::Component invalidComponent2("1234567890");
+
+ auto test = T()();
+
+ const Name& expected = test.expected;
+ BOOST_TEST_MESSAGE("Check " << expected[0].toUri());
+
+ BOOST_CHECK_EQUAL(expected[0].isGeneric(), true);
+
+ name::Component actualComponent = test.makeComponent(test.value);
+ BOOST_CHECK_EQUAL(actualComponent, expected[0]);
+
+ Name actualName;
+ test.append(actualName, test.value);
+ BOOST_CHECK_EQUAL(actualName, expected);
+
+ BOOST_CHECK_EQUAL(test.isComponent(expected[0]), true);
+ BOOST_CHECK_EQUAL(test.getValue(expected[0]), test.value);
+
+ BOOST_CHECK_EQUAL(test.isComponent(invalidComponent1), false);
+ BOOST_CHECK_EQUAL(test.isComponent(invalidComponent2), false);
+
+ BOOST_CHECK_THROW(test.getValue(invalidComponent1), name::Component::Error);
+ BOOST_CHECK_THROW(test.getValue(invalidComponent2), name::Component::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // NamingConvention
+
BOOST_AUTO_TEST_SUITE_END() // TestNameComponent
} // namespace tests
diff --git a/tests/unit-tests/name.t.cpp b/tests/unit-tests/name.t.cpp
index 9840196..dff17e4 100644
--- a/tests/unit-tests/name.t.cpp
+++ b/tests/unit-tests/name.t.cpp
@@ -1,5 +1,5 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
* Copyright (c) 2013-2017 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
@@ -22,8 +22,6 @@
#include "name.hpp"
#include "boost-test.hpp"
-#include <boost/tuple/tuple.hpp>
-#include <boost/mpl/vector.hpp>
#include <unordered_map>
namespace ndn {
@@ -51,6 +49,8 @@
0x8, 0x3, // NameComponent
0x6e, 0x64, 0x6e};
+// ---- encoding, decoding ----
+
BOOST_AUTO_TEST_CASE(Basic)
{
Name name("/hello/world");
@@ -89,23 +89,6 @@
BOOST_CHECK_EQUAL(name.toUri(), "/local/ndn/prefix");
}
-BOOST_AUTO_TEST_CASE(AppendsAndMultiEncode)
-{
- Name name("/local");
-
- BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
- Name1, Name1 + sizeof(Name1));
-
- name.append("ndn");
-
- BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
- Name2, Name2 + sizeof(Name2));
-
- name.append("prefix");
- BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
- TestName, TestName+sizeof(TestName));
-}
-
BOOST_AUTO_TEST_CASE(ZeroLengthComponent)
{
static const uint8_t compOctets[] {0x08, 0x00};
@@ -130,183 +113,6 @@
BOOST_CHECK(name2Encoded == nameBlock);
}
-BOOST_AUTO_TEST_CASE(AppendNumber)
-{
- Name name;
- for (uint32_t i = 0; i < 10; i++)
- {
- name.appendNumber(i);
- }
-
- BOOST_CHECK_EQUAL(name.size(), 10);
-
- for (uint32_t i = 0; i < 10; i++)
- {
- BOOST_CHECK_EQUAL(name[i].toNumber(), i);
- }
-}
-
-class Numeric
-{
-public:
- typedef std::list<boost::tuple<function<name::Component(uint64_t)>,
- function<uint64_t(const name::Component&)>,
- function<Name&(Name&, uint64_t)>,
- Name/*expected*/,
- uint64_t/*value*/,
- function<bool(const name::Component&)> > > Dataset;
-
- Numeric()
- {
- dataset.push_back(boost::make_tuple(bind(&name::Component::fromNumberWithMarker,
- 0xAA, _1),
- bind(&name::Component::toNumberWithMarker, _1, 0xAA),
- bind(&Name::appendNumberWithMarker, _1, 0xAA, _2),
- Name("/%AA%03%E8"),
- 1000,
- bind(&name::Component::isNumberWithMarker, _1, 0xAA)));
- dataset.push_back(boost::make_tuple(&name::Component::fromSegment,
- bind(&name::Component::toSegment, _1),
- bind(&Name::appendSegment, _1, _2),
- Name("/%00%27%10"),
- 10000,
- bind(&name::Component::isSegment, _1)));
- dataset.push_back(boost::make_tuple(&name::Component::fromSegmentOffset,
- bind(&name::Component::toSegmentOffset, _1),
- bind(&Name::appendSegmentOffset, _1, _2),
- Name("/%FB%00%01%86%A0"),
- 100000,
- bind(&name::Component::isSegmentOffset, _1)));
- dataset.push_back(boost::make_tuple(&name::Component::fromVersion,
- bind(&name::Component::toVersion, _1),
- bind(static_cast<Name&(Name::*)(uint64_t)>(
- &Name::appendVersion), _1, _2),
- Name("/%FD%00%0FB%40"),
- 1000000,
- bind(&name::Component::isVersion, _1)));
- dataset.push_back(boost::make_tuple(&name::Component::fromSequenceNumber,
- bind(&name::Component::toSequenceNumber, _1),
- bind(&Name::appendSequenceNumber, _1, _2),
- Name("/%FE%00%98%96%80"),
- 10000000,
- bind(&name::Component::isSequenceNumber, _1)));
- }
-
- Dataset dataset;
-};
-
-class Timestamp
-{
-public:
- typedef std::list<boost::tuple<function<name::Component(const time::system_clock::TimePoint&)>,
- function<time::system_clock::TimePoint(const name::Component&)>,
- function<Name&(Name&, const time::system_clock::TimePoint&)>,
- Name/*expected*/,
- time::system_clock::TimePoint/*value*/,
- function<bool(const name::Component&)> > > Dataset;
- Timestamp()
- {
- dataset.push_back(boost::make_tuple(&name::Component::fromTimestamp,
- ndn::bind(&name::Component::toTimestamp, _1),
- ndn::bind(&Name::appendTimestamp, _1, _2),
- Name("/%FC%00%04%7BE%E3%1B%00%00"),
- time::getUnixEpoch() + time::days(14600/*40 years*/),
- bind(&name::Component::isTimestamp, _1)));
- }
-
- Dataset dataset;
-};
-
-typedef boost::mpl::vector<Numeric, Timestamp> ConventionsDatasets;
-
-BOOST_FIXTURE_TEST_CASE_TEMPLATE(NamingConventions, T, ConventionsDatasets, T)
-{
- // // These octets are obtained by the snippet below.
- // // This check is intended to detect unexpected encoding change in the future.
- // for (typename T::Dataset::const_iterator it = this->dataset.begin();
- // it != this->dataset.end(); ++it) {
- // Name name;
- // name.append(it->template get<0>()(it->template get<4>()));
- // std::cout << name << std::endl;
- // }
-
- name::Component invalidComponent1;
- name::Component invalidComponent2("1234567890");
-
- for (typename T::Dataset::const_iterator it = this->dataset.begin();
- it != this->dataset.end(); ++it) {
- const Name& expected = it->template get<3>();
- BOOST_TEST_MESSAGE("Check " << expected[0].toUri());
-
- BOOST_CHECK_EQUAL(expected[0].isGeneric(), true);
-
- name::Component actualComponent = it->template get<0>()(it->template get<4>());
- BOOST_CHECK_EQUAL(actualComponent, expected[0]);
-
- Name actualName;
- it->template get<2>()(actualName, it->template get<4>());
- BOOST_CHECK_EQUAL(actualName, expected);
-
- BOOST_CHECK_EQUAL(it->template get<5>()(expected[0]), true);
- BOOST_REQUIRE_NO_THROW(it->template get<1>()(expected[0]));
- BOOST_CHECK_EQUAL(it->template get<1>()(expected[0]), it->template get<4>());
-
- BOOST_CHECK_EQUAL(it->template get<5>()(invalidComponent1), false);
- BOOST_CHECK_EQUAL(it->template get<5>()(invalidComponent2), false);
-
- BOOST_REQUIRE_THROW(it->template get<1>()(invalidComponent1), name::Component::Error);
- BOOST_REQUIRE_THROW(it->template get<1>()(invalidComponent2), name::Component::Error);
- }
-}
-
-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_CASE(Markers)
-{
- Name name;
- uint64_t number;
-
- BOOST_REQUIRE_NO_THROW(number = name.appendSegment(30923).at(-1).toSegment());
- BOOST_CHECK_EQUAL(number, 30923);
-
- BOOST_REQUIRE_NO_THROW(number = name.appendSegmentOffset(589).at(-1).toSegmentOffset());
- BOOST_CHECK_EQUAL(number, 589);
-
- BOOST_REQUIRE_NO_THROW(number = name.appendVersion().at(-1).toVersion());
-
- BOOST_REQUIRE_NO_THROW(number = name.appendVersion(25912).at(-1).toVersion());
- BOOST_CHECK_EQUAL(number, 25912);
-
- const time::system_clock::TimePoint tp = time::system_clock::now();
- time::system_clock::TimePoint tp2;
- BOOST_REQUIRE_NO_THROW(tp2 = name.appendTimestamp(tp).at(-1).toTimestamp());
- BOOST_CHECK_LE(std::abs(time::duration_cast<time::microseconds>(tp2 - tp).count()), 1);
-
- BOOST_REQUIRE_NO_THROW(number = name.appendSequenceNumber(11676).at(-1).toSequenceNumber());
- BOOST_CHECK_EQUAL(number, 11676);
-}
-
-BOOST_AUTO_TEST_CASE(UnorderedMap)
-{
- std::unordered_map<Name, int> map;
- Name name1("/1");
- Name name2("/2");
- Name name3("/3");
- map[name1] = 1;
- map[name2] = 2;
- map[name3] = 3;
-
- BOOST_CHECK_EQUAL(map[name1], 1);
- BOOST_CHECK_EQUAL(map[name2], 2);
- BOOST_CHECK_EQUAL(map[name3], 3);
-}
-
BOOST_AUTO_TEST_CASE(ImplicitSha256Digest)
{
Name n;
@@ -361,54 +167,6 @@
BOOST_CHECK(n2.get(1).isGeneric());
}
-BOOST_AUTO_TEST_CASE(Compare)
-{
- BOOST_CHECK_EQUAL(Name("/A") .compare(Name("/A")), 0);
- BOOST_CHECK_EQUAL(Name("/A") .compare(Name("/A")), 0);
- BOOST_CHECK_LT (Name("/A") .compare(Name("/B")), 0);
- BOOST_CHECK_GT (Name("/B") .compare(Name("/A")), 0);
- BOOST_CHECK_LT (Name("/A") .compare(Name("/AA")), 0);
- BOOST_CHECK_GT (Name("/AA") .compare(Name("/A")), 0);
- BOOST_CHECK_LT (Name("/A") .compare(Name("/A/C")), 0);
- BOOST_CHECK_GT (Name("/A/C").compare(Name("/A")), 0);
-
- BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/A")), 0);
- BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/A")), 0);
- BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/B")), 0);
- BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/A")), 0);
- BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/AA")), 0);
- BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/A")), 0);
- BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/A/C")), 0);
- BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/A")), 0);
-
- BOOST_CHECK_EQUAL(Name("/Z/A") .compare(1, Name::npos, Name("/A")), 0);
- BOOST_CHECK_EQUAL(Name("/Z/A") .compare(1, Name::npos, Name("/A")), 0);
- BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/B")), 0);
- BOOST_CHECK_GT (Name("/Z/B") .compare(1, Name::npos, Name("/A")), 0);
- BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/AA")), 0);
- BOOST_CHECK_GT (Name("/Z/AA") .compare(1, Name::npos, Name("/A")), 0);
- BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/A/C")), 0);
- BOOST_CHECK_GT (Name("/Z/A/C").compare(1, Name::npos, Name("/A")), 0);
-
- BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0);
- BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0);
- BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/B/W"), 1, 1), 0);
- BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0);
- BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/AA/W"), 1, 1), 0);
- BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0);
- BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/A/C/W"), 1, 2), 0);
- BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/X/A/W"), 1, 1), 0);
-
- BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A"), 1), 0);
- BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A"), 1), 0);
- BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/B"), 1), 0);
- BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/X/A"), 1), 0);
- BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/AA"), 1), 0);
- BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/X/A"), 1), 0);
- BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/A/C"), 1), 0);
- BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/X/A"), 1), 0);
-}
-
BOOST_AUTO_TEST_CASE(NameWithSpaces)
{
Name name("/ hello\t/\tworld \r\n");
@@ -417,6 +175,62 @@
BOOST_CHECK_THROW(Name("/hello//world"), name::Component::Error);
}
+BOOST_AUTO_TEST_CASE(DeepCopy)
+{
+ Name n1("/hello/world");
+ Name n2 = n1.deepCopy();
+
+ BOOST_CHECK_EQUAL(n1, n2);
+ BOOST_CHECK_NE(&n1.wireEncode(), &n2.wireEncode());
+
+ EncodingBuffer buffer(1024, 0);
+ n1.wireEncode(buffer);
+ Name n3(buffer.block());
+
+ BOOST_CHECK_EQUAL(n1, n3);
+ BOOST_CHECK_EQUAL(n3.wireEncode().getBuffer()->size(), 1024);
+ n3 = n3.deepCopy();
+
+ BOOST_CHECK_LT(n3.wireEncode().size(), 1024);
+ BOOST_CHECK_EQUAL(n3.wireEncode().getBuffer()->size(), n3.wireEncode().size());
+}
+
+// ---- iterators ----
+
+BOOST_AUTO_TEST_CASE(ForwardIterator)
+{
+ name::Component comps[] {
+ name::Component("A"),
+ name::Component("B"),
+ name::Component("C"),
+ name::Component("D")
+ };
+
+ Name n0;
+ BOOST_CHECK_EQUAL_COLLECTIONS(n0.begin(), n0.end(), comps, comps + 0);
+
+ Name n4("/A/B/C/D");
+ BOOST_CHECK_EQUAL_COLLECTIONS(n4.begin(), n4.end(), comps, comps + 4);
+}
+
+BOOST_AUTO_TEST_CASE(ReverseIterator)
+{
+ name::Component comps[] {
+ name::Component("D"),
+ name::Component("C"),
+ name::Component("B"),
+ name::Component("A")
+ };
+
+ Name n0;
+ BOOST_CHECK_EQUAL_COLLECTIONS(n0.rbegin(), n0.rend(), comps, comps + 0);
+
+ Name n4("/A/B/C/D");
+ BOOST_CHECK_EQUAL_COLLECTIONS(n4.rbegin(), n4.rend(), comps, comps + 4);
+}
+
+// ---- modifiers ----
+
BOOST_AUTO_TEST_CASE(Append)
{
PartialName toAppend("/and");
@@ -436,6 +250,126 @@
}
}
+BOOST_AUTO_TEST_CASE(AppendsAndMultiEncode)
+{
+ Name name("/local");
+ BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
+ Name1, Name1 + sizeof(Name1));
+
+ name.append("ndn");
+ BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
+ Name2, Name2 + sizeof(Name2));
+
+ name.append("prefix");
+ BOOST_CHECK_EQUAL_COLLECTIONS(name.wireEncode().begin(), name.wireEncode().end(),
+ TestName, TestName+sizeof(TestName));
+}
+
+BOOST_AUTO_TEST_CASE(AppendNumber)
+{
+ Name name;
+ for (uint32_t i = 0; i < 10; i++) {
+ name.appendNumber(i);
+ }
+
+ BOOST_CHECK_EQUAL(name.size(), 10);
+
+ for (uint32_t i = 0; i < 10; i++) {
+ BOOST_CHECK_EQUAL(name[i].toNumber(), i);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(Markers)
+{
+ // TestNameComponent/NamingConvention provides additional coverage for these methods,
+ // including verifications of the wire format.
+
+ Name name;
+ uint64_t number;
+
+ BOOST_REQUIRE_NO_THROW(number = name.appendSegment(30923).at(-1).toSegment());
+ BOOST_CHECK_EQUAL(number, 30923);
+
+ BOOST_REQUIRE_NO_THROW(number = name.appendSegmentOffset(589).at(-1).toSegmentOffset());
+ BOOST_CHECK_EQUAL(number, 589);
+
+ BOOST_REQUIRE_NO_THROW(number = name.appendVersion().at(-1).toVersion());
+
+ BOOST_REQUIRE_NO_THROW(number = name.appendVersion(25912).at(-1).toVersion());
+ BOOST_CHECK_EQUAL(number, 25912);
+
+ const time::system_clock::TimePoint tp = time::system_clock::now();
+ time::system_clock::TimePoint tp2;
+ BOOST_REQUIRE_NO_THROW(tp2 = name.appendTimestamp(tp).at(-1).toTimestamp());
+ BOOST_CHECK_LE(std::abs(time::duration_cast<time::microseconds>(tp2 - tp).count()), 1);
+
+ BOOST_REQUIRE_NO_THROW(number = name.appendSequenceNumber(11676).at(-1).toSequenceNumber());
+ BOOST_CHECK_EQUAL(number, 11676);
+}
+
+BOOST_AUTO_TEST_CASE(Clear)
+{
+ Name n("/A");
+ BOOST_CHECK_EQUAL(n.empty(), false);
+
+ n.clear();
+ BOOST_CHECK_EQUAL(n.empty(), true);
+ BOOST_CHECK_EQUAL(n.size(), 0);
+}
+
+// ---- algorithms ----
+
+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_CASE(Compare)
+{
+ BOOST_CHECK_EQUAL(Name("/A") .compare(Name("/A")), 0);
+ BOOST_CHECK_LT (Name("/A") .compare(Name("/B")), 0);
+ BOOST_CHECK_GT (Name("/B") .compare(Name("/A")), 0);
+ BOOST_CHECK_LT (Name("/A") .compare(Name("/AA")), 0);
+ BOOST_CHECK_GT (Name("/AA") .compare(Name("/A")), 0);
+ BOOST_CHECK_LT (Name("/A") .compare(Name("/A/C")), 0);
+ BOOST_CHECK_GT (Name("/A/C").compare(Name("/A")), 0);
+
+ BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/A")), 0);
+ BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/B")), 0);
+ BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/A")), 0);
+ BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/AA")), 0);
+ BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/A")), 0);
+ BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/A/C")), 0);
+ BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/A")), 0);
+
+ BOOST_CHECK_EQUAL(Name("/Z/A") .compare(1, Name::npos, Name("/A")), 0);
+ BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/B")), 0);
+ BOOST_CHECK_GT (Name("/Z/B") .compare(1, Name::npos, Name("/A")), 0);
+ BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/AA")), 0);
+ BOOST_CHECK_GT (Name("/Z/AA") .compare(1, Name::npos, Name("/A")), 0);
+ BOOST_CHECK_LT (Name("/Z/A") .compare(1, Name::npos, Name("/A/C")), 0);
+ BOOST_CHECK_GT (Name("/Z/A/C").compare(1, Name::npos, Name("/A")), 0);
+
+ BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0);
+ BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/B/W"), 1, 1), 0);
+ BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0);
+ BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/AA/W"), 1, 1), 0);
+ BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/X/A/W"), 1, 1), 0);
+ BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/A/C/W"), 1, 2), 0);
+ BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/X/A/W"), 1, 1), 0);
+
+ BOOST_CHECK_EQUAL(Name("/Z/A/Y") .compare(1, 1, Name("/X/A"), 1), 0);
+ BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/B"), 1), 0);
+ BOOST_CHECK_GT (Name("/Z/B/Y") .compare(1, 1, Name("/X/A"), 1), 0);
+ BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/AA"), 1), 0);
+ BOOST_CHECK_GT (Name("/Z/AA/Y") .compare(1, 1, Name("/X/A"), 1), 0);
+ BOOST_CHECK_LT (Name("/Z/A/Y") .compare(1, 1, Name("/X/A/C"), 1), 0);
+ BOOST_CHECK_GT (Name("/Z/A/C/Y").compare(1, 2, Name("/X/A"), 1), 0);
+}
+
BOOST_AUTO_TEST_CASE(SubName)
{
Name name("/hello/world");
@@ -474,24 +408,19 @@
BOOST_CHECK_EQUAL("/first/second/last", name.getSubName(-10, 10));
}
-BOOST_AUTO_TEST_CASE(DeepCopy)
+BOOST_AUTO_TEST_CASE(UnorderedMap)
{
- Name n1("/hello/world");
- Name n2 = n1.deepCopy();
+ std::unordered_map<Name, int> map;
+ Name name1("/1");
+ Name name2("/2");
+ Name name3("/3");
+ map[name1] = 1;
+ map[name2] = 2;
+ map[name3] = 3;
- BOOST_CHECK_EQUAL(n1, n2);
- BOOST_CHECK_NE(&n1.wireEncode(), &n2.wireEncode());
-
- EncodingBuffer buffer(1024, 0);
- n1.wireEncode(buffer);
- Name n3(buffer.block());
-
- BOOST_CHECK_EQUAL(n1, n3);
- BOOST_CHECK_EQUAL(n3.wireEncode().getBuffer()->size(), 1024);
- n3 = n3.deepCopy();
-
- BOOST_CHECK_LT(n3.wireEncode().size(), 1024);
- BOOST_CHECK_EQUAL(n3.wireEncode().getBuffer()->size(), n3.wireEncode().size());
+ BOOST_CHECK_EQUAL(map[name1], 1);
+ BOOST_CHECK_EQUAL(map[name2], 2);
+ BOOST_CHECK_EQUAL(map[name3], 3);
}
BOOST_AUTO_TEST_SUITE_END() // TestName