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-2017 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/algorithm/string/trim.hpp>
34 #include <boost/functional/hash.hpp>
35 #include <boost/range/adaptor/reversed.hpp>
36 #include <boost/range/concepts.hpp>
37 
38 namespace ndn {
39 
40 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Name>));
41 BOOST_CONCEPT_ASSERT((WireEncodable<Name>));
42 BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Name>));
43 BOOST_CONCEPT_ASSERT((WireDecodable<Name>));
44 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::iterator>));
45 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::const_iterator>));
46 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::reverse_iterator>));
47 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::const_reverse_iterator>));
48 BOOST_CONCEPT_ASSERT((boost::RandomAccessRangeConcept<Name>));
49 static_assert(std::is_base_of<tlv::Error, Name::Error>::value,
50  "Name::Error must inherit from tlv::Error");
51 
52 const size_t Name::npos = std::numeric_limits<size_t>::max();
53 
54 // ---- constructors, encoding, decoding ----
55 
57  : m_wire(tlv::Name)
58 {
59 }
60 
61 Name::Name(const Block& wire)
62  : m_wire(wire)
63 {
64  m_wire.parse();
65 }
66 
67 Name::Name(const char* uri)
68  : Name(std::string(uri))
69 {
70 }
71 
72 Name::Name(std::string uri)
73 {
74  boost::algorithm::trim(uri);
75  if (uri.empty())
76  return;
77 
78  size_t iColon = uri.find(':');
79  if (iColon != std::string::npos) {
80  // Make sure the colon came before a '/'.
81  size_t iFirstSlash = uri.find('/');
82  if (iFirstSlash == std::string::npos || iColon < iFirstSlash) {
83  // Omit the leading protocol such as ndn:
84  uri.erase(0, iColon + 1);
85  boost::algorithm::trim(uri);
86  }
87  }
88 
89  // Trim the leading slash and possibly the authority.
90  if (uri[0] == '/') {
91  if (uri.size() >= 2 && uri[1] == '/') {
92  // Strip the authority following "//".
93  size_t iAfterAuthority = uri.find('/', 2);
94  if (iAfterAuthority == std::string::npos)
95  // Unusual case: there was only an authority.
96  return;
97  else {
98  uri.erase(0, iAfterAuthority + 1);
99  boost::algorithm::trim(uri);
100  }
101  }
102  else {
103  uri.erase(0, 1);
104  boost::algorithm::trim(uri);
105  }
106  }
107 
108  size_t iComponentStart = 0;
109 
110  // Unescape the components.
111  while (iComponentStart < uri.size()) {
112  size_t iComponentEnd = uri.find("/", iComponentStart);
113  if (iComponentEnd == std::string::npos)
114  iComponentEnd = uri.size();
115 
116  append(Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd));
117  iComponentStart = iComponentEnd + 1;
118  }
119 }
120 
121 std::string
122 Name::toUri() const
123 {
124  std::ostringstream os;
125  os << *this;
126  return os.str();
127 }
128 
129 template<encoding::Tag TAG>
130 size_t
131 Name::wireEncode(EncodingImpl<TAG>& encoder) const
132 {
133  size_t totalLength = 0;
134  for (const Component& comp : *this | boost::adaptors::reversed) {
135  totalLength += comp.wireEncode(encoder);
136  }
137 
138  totalLength += encoder.prependVarNumber(totalLength);
139  totalLength += encoder.prependVarNumber(tlv::Name);
140  return totalLength;
141 }
142 
144 
145 const Block&
147 {
148  if (m_wire.hasWire())
149  return m_wire;
150 
151  EncodingEstimator estimator;
152  size_t estimatedSize = wireEncode(estimator);
153 
154  EncodingBuffer buffer(estimatedSize, 0);
155  wireEncode(buffer);
156 
157  m_wire = buffer.block();
158  m_wire.parse();
159 
160  return m_wire;
161 }
162 
163 void
165 {
166  if (wire.type() != tlv::Name)
167  BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Name"));
168 
169  m_wire = wire;
170  m_wire.parse();
171 }
172 
173 Name
175 {
176  Name copiedName(*this);
177  copiedName.m_wire.resetWire();
178  copiedName.wireEncode(); // "compress" the underlying buffer
179  return copiedName;
180 }
181 
182 // ---- accessors ----
183 
184 const name::Component&
185 Name::at(ssize_t i) const
186 {
187  if (i < 0) {
188  i = size() + i;
189  }
190 
191  if (i < 0 || static_cast<size_t>(i) >= size()) {
192  BOOST_THROW_EXCEPTION(Error("Requested component does not exist (out of bounds)"));
193  }
194 
195  return reinterpret_cast<const Component&>(m_wire.elements()[i]);
196 }
197 
199 Name::getSubName(ssize_t iStartComponent, size_t nComponents) const
200 {
201  PartialName result;
202 
203  ssize_t iStart = iStartComponent < 0 ? this->size() + iStartComponent : iStartComponent;
204  size_t iEnd = this->size();
205 
206  iStart = std::max(iStart, static_cast<ssize_t>(0));
207 
208  if (nComponents != npos)
209  iEnd = std::min(this->size(), iStart + nComponents);
210 
211  for (size_t i = iStart; i < iEnd; ++i)
212  result.append(at(i));
213 
214  return result;
215 }
216 
217 // ---- modifiers ----
218 
219 Name&
221 {
223 }
224 
225 Name&
227 {
229 }
230 
231 Name&
233 {
234  if (&name == this)
235  // Copying from this name, so need to make a copy first.
236  return append(PartialName(name));
237 
238  for (size_t i = 0; i < name.size(); ++i)
239  append(name.at(i));
240 
241  return *this;
242 }
243 
244 // ---- algorithms ----
245 
246 Name
248 {
249  if (empty()) {
250  static uint8_t firstValue[] {0};
251  Name firstName;
252  firstName.append(firstValue, 1);
253  return firstName;
254  }
255 
256  return getPrefix(-1).append(get(-1).getSuccessor());
257 }
258 
259 bool
260 Name::isPrefixOf(const Name& other) const
261 {
262  // This name is longer than the name we are checking against.
263  if (size() > other.size())
264  return false;
265 
266  // Check if at least one of given components doesn't match.
267  for (size_t i = 0; i < size(); ++i) {
268  if (get(i) != other.get(i))
269  return false;
270  }
271 
272  return true;
273 }
274 
275 bool
276 Name::equals(const Name& other) const
277 {
278  if (size() != other.size())
279  return false;
280 
281  for (size_t i = 0; i < size(); ++i) {
282  if (get(i) != other.get(i))
283  return false;
284  }
285 
286  return true;
287 }
288 
289 int
290 Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const
291 {
292  count1 = std::min(count1, this->size() - pos1);
293  count2 = std::min(count2, other.size() - pos2);
294  size_t count = std::min(count1, count2);
295 
296  for (size_t i = 0; i < count; ++i) {
297  int comp = get(pos1 + i).compare(other.get(pos2 + i));
298  if (comp != 0) { // i-th component differs
299  return comp;
300  }
301  }
302  // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name
303  return count1 - count2;
304 }
305 
306 // ---- stream operators ----
307 
308 std::ostream&
309 operator<<(std::ostream& os, const Name& name)
310 {
311  if (name.empty()) {
312  os << "/";
313  }
314  else {
315  for (const auto& component : name) {
316  os << "/";
317  component.toUri(os);
318  }
319  }
320  return os;
321 }
322 
323 std::istream&
324 operator>>(std::istream& is, Name& name)
325 {
326  std::string inputString;
327  is >> inputString;
328  name = Name(inputString);
329 
330  return is;
331 }
332 
333 } // namespace ndn
334 
335 namespace std {
336 
337 size_t
338 hash<ndn::Name>::operator()(const ndn::Name& name) const
339 {
340  return boost::hash_range(name.wireEncode().wire(),
341  name.wireEncode().wire() + name.wireEncode().size());
342 }
343 
344 } // 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:226
const element_container & elements() const
Get container of sub elements.
Definition: block.hpp:347
static Component fromEscapedString(const char *escapedString, size_t beginOffset, size_t endOffset)
Create name::Component by decoding the escapedString between beginOffset and endOffset according to t...
Name getSuccessor() const
Get the successor of a name.
Definition: name.cpp:247
std::ostream & operator<<(std::ostream &os, const Data &data)
Definition: data.cpp:274
static const size_t npos
indicates "until the end" in getSubName and compare
Definition: name.hpp:537
STL namespace.
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Fast encoding or block size estimation.
Definition: name.cpp:131
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:266
std::string toUri() const
Get URI representation of the name.
Definition: name.cpp:122
const Block & wireEncode() const
Perform wire encoding, or return existing wire encoding.
Definition: name.cpp:146
bool equals(const Name &other) const
Check if this name equals another name.
Definition: name.cpp:276
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:324
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:260
const Component & at(ssize_t i) const
Get the component at the given index.
Definition: name.cpp:185
void parse() const
Parse TLV-VALUE into sub elements.
Definition: block.cpp:335
uint32_t type() const
Get TLV-TYPE.
Definition: block.hpp:235
Component holds a read-only name component value.
int compare(const Name &other) const
Compare this to the other Name using NDN canonical ordering.
Definition: name.hpp:520
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:174
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:251
PartialName getSubName(ssize_t iStartComponent, size_t nComponents=npos) const
Extract some components as a sub-name (PartialName)
Definition: name.cpp:199
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:164
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:220
Name()
Create an empty name.
Definition: name.cpp:56
represents an error in TLV encoding or decoding
EncodingImpl< EstimatorTag > EncodingEstimator