name.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2018 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later version.
10  *
11  * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14  *
15  * You should have received copies of the GNU General Public License and GNU Lesser
16  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17  * <http://www.gnu.org/licenses/>.
18  *
19  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20  *
21  * @author Jeff Thompson <jefft0@remap.ucla.edu>
22  * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
23  * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
24  */
25 
26 #include "name.hpp"
27 
28 #include "encoding/block.hpp"
30 #include "util/time.hpp"
31 
32 #include <sstream>
33 #include <boost/functional/hash.hpp>
34 #include <boost/range/adaptor/reversed.hpp>
35 #include <boost/range/concepts.hpp>
36 
37 namespace ndn {
38 
39 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Name>));
40 BOOST_CONCEPT_ASSERT((WireEncodable<Name>));
41 BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Name>));
42 BOOST_CONCEPT_ASSERT((WireDecodable<Name>));
43 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::iterator>));
44 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::const_iterator>));
45 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::reverse_iterator>));
46 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::const_reverse_iterator>));
47 BOOST_CONCEPT_ASSERT((boost::RandomAccessRangeConcept<Name>));
48 static_assert(std::is_base_of<tlv::Error, Name::Error>::value,
49  "Name::Error must inherit from tlv::Error");
50 
51 const size_t Name::npos = std::numeric_limits<size_t>::max();
52 
53 // ---- constructors, encoding, decoding ----
54 
56  : m_wire(tlv::Name)
57 {
58 }
59 
60 Name::Name(const Block& wire)
61  : m_wire(wire)
62 {
63  m_wire.parse();
64 }
65 
66 Name::Name(const char* uri)
67  : Name(std::string(uri))
68 {
69 }
70 
71 Name::Name(std::string uri)
72 {
73  if (uri.empty())
74  return;
75 
76  size_t iColon = uri.find(':');
77  if (iColon != std::string::npos) {
78  // Make sure the colon came before a '/'.
79  size_t iFirstSlash = uri.find('/');
80  if (iFirstSlash == std::string::npos || iColon < iFirstSlash) {
81  // Omit the leading protocol such as ndn:
82  uri.erase(0, iColon + 1);
83  }
84  }
85 
86  // Trim the leading slash and possibly the authority.
87  if (uri[0] == '/') {
88  if (uri.size() >= 2 && uri[1] == '/') {
89  // Strip the authority following "//".
90  size_t iAfterAuthority = uri.find('/', 2);
91  if (iAfterAuthority == std::string::npos)
92  // Unusual case: there was only an authority.
93  return;
94  else {
95  uri.erase(0, iAfterAuthority + 1);
96  }
97  }
98  else {
99  uri.erase(0, 1);
100  }
101  }
102 
103  size_t iComponentStart = 0;
104 
105  // Unescape the components.
106  while (iComponentStart < uri.size()) {
107  size_t iComponentEnd = uri.find("/", iComponentStart);
108  if (iComponentEnd == std::string::npos)
109  iComponentEnd = uri.size();
110 
111  append(Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd));
112  iComponentStart = iComponentEnd + 1;
113  }
114 }
115 
116 std::string
117 Name::toUri() const
118 {
119  std::ostringstream os;
120  os << *this;
121  return os.str();
122 }
123 
124 template<encoding::Tag TAG>
125 size_t
126 Name::wireEncode(EncodingImpl<TAG>& encoder) const
127 {
128  size_t totalLength = 0;
129  for (const Component& comp : *this | boost::adaptors::reversed) {
130  totalLength += comp.wireEncode(encoder);
131  }
132 
133  totalLength += encoder.prependVarNumber(totalLength);
134  totalLength += encoder.prependVarNumber(tlv::Name);
135  return totalLength;
136 }
137 
139 
140 const Block&
142 {
143  if (m_wire.hasWire())
144  return m_wire;
145 
146  EncodingEstimator estimator;
147  size_t estimatedSize = wireEncode(estimator);
148 
149  EncodingBuffer buffer(estimatedSize, 0);
150  wireEncode(buffer);
151 
152  m_wire = buffer.block();
153  m_wire.parse();
154 
155  return m_wire;
156 }
157 
158 void
160 {
161  if (wire.type() != tlv::Name)
162  BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Name"));
163 
164  m_wire = wire;
165  m_wire.parse();
166 }
167 
168 Name
170 {
171  Name copiedName(*this);
172  copiedName.m_wire.resetWire();
173  copiedName.wireEncode(); // "compress" the underlying buffer
174  return copiedName;
175 }
176 
177 // ---- accessors ----
178 
179 const name::Component&
180 Name::at(ssize_t i) const
181 {
182  if (i < 0) {
183  i = size() + i;
184  }
185 
186  if (i < 0 || static_cast<size_t>(i) >= size()) {
187  BOOST_THROW_EXCEPTION(Error("Requested component does not exist (out of bounds)"));
188  }
189 
190  return reinterpret_cast<const Component&>(m_wire.elements()[i]);
191 }
192 
194 Name::getSubName(ssize_t iStartComponent, size_t nComponents) const
195 {
196  PartialName result;
197 
198  ssize_t iStart = iStartComponent < 0 ? this->size() + iStartComponent : iStartComponent;
199  size_t iEnd = this->size();
200 
201  iStart = std::max(iStart, static_cast<ssize_t>(0));
202 
203  if (nComponents != npos)
204  iEnd = std::min(this->size(), iStart + nComponents);
205 
206  for (size_t i = iStart; i < iEnd; ++i)
207  result.append(at(i));
208 
209  return result;
210 }
211 
212 // ---- modifiers ----
213 
214 Name&
216 {
218 }
219 
220 Name&
222 {
224 }
225 
226 Name&
228 {
229  if (&name == this)
230  // Copying from this name, so need to make a copy first.
231  return append(PartialName(name));
232 
233  for (size_t i = 0; i < name.size(); ++i)
234  append(name.at(i));
235 
236  return *this;
237 }
238 
239 // ---- algorithms ----
240 
241 Name
243 {
244  if (empty()) {
245  static uint8_t firstValue[] {0};
246  Name firstName;
247  firstName.append(firstValue, 1);
248  return firstName;
249  }
250 
251  return getPrefix(-1).append(get(-1).getSuccessor());
252 }
253 
254 bool
255 Name::isPrefixOf(const Name& other) const
256 {
257  // This name is longer than the name we are checking against.
258  if (size() > other.size())
259  return false;
260 
261  // Check if at least one of given components doesn't match.
262  for (size_t i = 0; i < size(); ++i) {
263  if (get(i) != other.get(i))
264  return false;
265  }
266 
267  return true;
268 }
269 
270 bool
271 Name::equals(const Name& other) const
272 {
273  if (size() != other.size())
274  return false;
275 
276  for (size_t i = 0; i < size(); ++i) {
277  if (get(i) != other.get(i))
278  return false;
279  }
280 
281  return true;
282 }
283 
284 int
285 Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const
286 {
287  count1 = std::min(count1, this->size() - pos1);
288  count2 = std::min(count2, other.size() - pos2);
289  size_t count = std::min(count1, count2);
290 
291  for (size_t i = 0; i < count; ++i) {
292  int comp = get(pos1 + i).compare(other.get(pos2 + i));
293  if (comp != 0) { // i-th component differs
294  return comp;
295  }
296  }
297  // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name
298  return count1 - count2;
299 }
300 
301 // ---- stream operators ----
302 
303 std::ostream&
304 operator<<(std::ostream& os, const Name& name)
305 {
306  if (name.empty()) {
307  os << "/";
308  }
309  else {
310  for (const auto& component : name) {
311  os << "/";
312  component.toUri(os);
313  }
314  }
315  return os;
316 }
317 
318 std::istream&
319 operator>>(std::istream& is, Name& name)
320 {
321  std::string inputString;
322  is >> inputString;
323  name = Name(inputString);
324 
325  return is;
326 }
327 
328 } // namespace ndn
329 
330 namespace std {
331 
332 size_t
333 hash<ndn::Name>::operator()(const ndn::Name& name) const
334 {
335  return boost::hash_range(name.wireEncode().wire(),
336  name.wireEncode().wire() + name.wireEncode().size());
337 }
338 
339 } // namespace std
Copyright (c) 2013-2017 Regents of the University of California.
Definition: common.hpp:66
Name & appendTimestamp()
Append a timestamp component based on current time.
Definition: name.cpp:221
const element_container & elements() const
Get container of sub elements.
Definition: block.hpp:347
Name getSuccessor() const
Get the successor of a name.
Definition: name.cpp:242
std::ostream & operator<<(std::ostream &os, const Data &data)
Definition: data.cpp:337
static const size_t npos
indicates "until the end" in getSubName and compare
Definition: name.hpp:557
STL namespace.
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Fast encoding or block size estimation.
Definition: name.cpp:126
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
static time_point now() noexcept
Definition: time.cpp:46
Name & append(const Component &component)
Append a component.
Definition: name.hpp:256
void resetWire()
Reset wire buffer but keep TLV-TYPE and sub elements (if any)
Definition: block.cpp:267
std::string toUri() const
Get URI representation of the name.
Definition: name.cpp:117
const Block & wireEncode() const
Perform wire encoding, or return existing wire encoding.
Definition: name.cpp:141
bool equals(const Name &other) const
Check if this name equals another name.
Definition: name.cpp:271
static Component fromEscapedString(const char *input, size_t beginOffset, size_t endOffset)
Decode NameComponent from a URI component.
Name PartialName
Represents an arbitrary sequence of name components.
Definition: name.hpp:38
#define NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ClassName)
size_t size() const
Get number of components.
Definition: name.hpp:154
std::istream & operator>>(std::istream &is, Name &name)
Parse URI from stream as Name.
Definition: name.cpp:319
Represents an absolute name.
Definition: name.hpp:42
bool isPrefixOf(const Name &other) const
Check if this name is a prefix of another name.
Definition: name.cpp:255
const Component & at(ssize_t i) const
Get the component at the given index.
Definition: name.cpp:180
void parse() const
Parse TLV-VALUE into sub elements.
Definition: block.cpp:336
uint32_t type() const
Get TLV-TYPE.
Definition: block.hpp:235
Represents a name component.
int compare(const Name &other) const
Compare this to the other Name using NDN canonical ordering.
Definition: name.hpp:540
milliseconds toUnixTimestamp(const system_clock::TimePoint &point)
Convert system_clock::TimePoint to UNIX timestamp.
Definition: time.cpp:113
Name deepCopy() const
Make a deep copy of the name, reallocating the underlying memory buffer.
Definition: name.cpp:169
bool empty() const
Check if name is empty.
Definition: name.hpp:146
bool hasWire() const
Check if the Block has fully encoded wire.
Definition: block.cpp:252
PartialName getSubName(ssize_t iStartComponent, size_t nComponents=npos) const
Extract some components as a sub-name (PartialName)
Definition: name.cpp:194
PartialName getPrefix(ssize_t nComponents) const
Extract a prefix of the name.
Definition: name.hpp:210
void wireDecode(const Block &wire)
Decode name from wire encoding.
Definition: name.cpp:159
const Component & get(ssize_t i) const
Get the component at the given index.
Definition: name.hpp:164
EncodingImpl< EncoderTag > EncodingBuffer
Name & appendVersion()
Append a version component based on current time.
Definition: name.cpp:215
Name()
Create an empty name.
Definition: name.cpp:55
represents an error in TLV encoding or decoding
EncodingImpl< EstimatorTag > EncodingEstimator