blob: 88e51db7c8d37da4c40c83cf9717b1f11793ffd0 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi4f756902017-07-18 03:05:02 +00002/*
Davide Pesaventocf415762017-02-25 23:46:47 -05003 * Copyright (c) 2013-2017 Regents of the University of California.
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -08004 *
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07005 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -08006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * 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.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -080022 */
23
Alexander Afanasyev09c613f2014-01-29 00:23:58 -080024#include "exclude.hpp"
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070025#include "encoding/block-helpers.hpp"
Junxiao Shi7284a402014-09-12 13:42:16 -070026
Davide Pesaventocf415762017-02-25 23:46:47 -050027#include <boost/range/adaptor/reversed.hpp>
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -070028
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -070029namespace ndn {
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -080030
Junxiao Shidf4b24e2016-07-14 21:41:43 +000031Exclude::ExcludeComponent::ExcludeComponent(const name::Component& component1)
32 : isNegInf(false)
33 , component(component1)
34{
35}
36
37Exclude::ExcludeComponent::ExcludeComponent(bool isNegInf1)
38 : isNegInf(true)
39{
40 BOOST_ASSERT(isNegInf1 == true);
41}
42
43bool
Junxiao Shib80e9472016-07-20 13:45:24 +000044operator==(const Exclude::ExcludeComponent& a, const Exclude::ExcludeComponent& b)
45{
46 return (a.isNegInf && b.isNegInf) ||
47 (a.isNegInf == b.isNegInf && a.component == b.component);
48}
49
50bool
Junxiao Shidf4b24e2016-07-14 21:41:43 +000051operator>(const Exclude::ExcludeComponent& a, const Exclude::ExcludeComponent& b)
52{
53 return a.isNegInf < b.isNegInf ||
54 (a.isNegInf == b.isNegInf && a.component > b.component);
55}
56
Junxiao Shi4f756902017-07-18 03:05:02 +000057Exclude::Range::Range()
58 : fromInfinity(false)
59 , toInfinity(false)
60{
61}
62
63Exclude::Range::Range(bool fromInfinity, const name::Component& from, bool toInfinity, const name::Component& to)
64 : fromInfinity(fromInfinity)
65 , from(from)
66 , toInfinity(toInfinity)
67 , to(to)
68{
69}
70
Junxiao Shib80e9472016-07-20 13:45:24 +000071bool
72Exclude::Range::operator==(const Exclude::Range& other) const
73{
74 return this->fromInfinity == other.fromInfinity && this->toInfinity == other.toInfinity &&
75 (this->fromInfinity || this->from == other.from) &&
76 (this->toInfinity || this->to == other.to);
77}
78
79std::ostream&
80operator<<(std::ostream& os, const Exclude::Range& range)
81{
82 if (range.isSingular()) {
83 return os << '{' << range.from << '}';
84 }
85
86 if (range.fromInfinity) {
87 os << "(-∞";
88 }
89 else {
90 os << '[' << range.from;
91 }
92
93 os << ",";
94
95 if (range.toInfinity) {
96 os << "+∞)";
97 }
98 else {
99 os << range.to << ']';
100 }
101
102 return os;
103}
104
Junxiao Shic2b8d242014-11-04 08:35:29 -0700105BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Exclude>));
106BOOST_CONCEPT_ASSERT((WireEncodable<Exclude>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700107BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Exclude>));
Junxiao Shic2b8d242014-11-04 08:35:29 -0700108BOOST_CONCEPT_ASSERT((WireDecodable<Exclude>));
109static_assert(std::is_base_of<tlv::Error, Exclude::Error>::value,
110 "Exclude::Error must inherit from tlv::Error");
Junxiao Shi7284a402014-09-12 13:42:16 -0700111
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000112Exclude::Exclude() = default;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800113
Junxiao Shi75203022014-09-11 10:01:50 -0700114Exclude::Exclude(const Block& wire)
115{
116 wireDecode(wire);
117}
118
Alexander Afanasyev74633892015-02-08 18:08:46 -0800119template<encoding::Tag TAG>
Junxiao Shi75203022014-09-11 10:01:50 -0700120size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700121Exclude::wireEncode(EncodingImpl<TAG>& encoder) const
Junxiao Shi75203022014-09-11 10:01:50 -0700122{
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000123 if (m_entries.empty()) {
124 BOOST_THROW_EXCEPTION(Error("cannot encode empty Exclude selector"));
Junxiao Shi7284a402014-09-12 13:42:16 -0700125 }
126
Junxiao Shi75203022014-09-11 10:01:50 -0700127 size_t totalLength = 0;
128
129 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
130 // Any ::= ANY-TYPE TLV-LENGTH(=0)
131
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000132 for (const Entry& entry : m_entries) {
133 if (entry.second) {
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700134 totalLength += prependEmptyBlock(encoder, tlv::Any);
Junxiao Shi75203022014-09-11 10:01:50 -0700135 }
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000136 if (!entry.first.isNegInf) {
137 totalLength += entry.first.component.wireEncode(encoder);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700138 }
139 }
Junxiao Shi75203022014-09-11 10:01:50 -0700140
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700141 totalLength += encoder.prependVarNumber(totalLength);
142 totalLength += encoder.prependVarNumber(tlv::Exclude);
Junxiao Shi75203022014-09-11 10:01:50 -0700143 return totalLength;
144}
145
146template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700147Exclude::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
Junxiao Shi75203022014-09-11 10:01:50 -0700148
149template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700150Exclude::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
Junxiao Shi75203022014-09-11 10:01:50 -0700151
152const Block&
153Exclude::wireEncode() const
154{
155 if (m_wire.hasWire())
156 return m_wire;
157
158 EncodingEstimator estimator;
159 size_t estimatedSize = wireEncode(estimator);
160
161 EncodingBuffer buffer(estimatedSize, 0);
162 wireEncode(buffer);
163
164 m_wire = buffer.block();
165 return m_wire;
166}
167
168void
169Exclude::wireDecode(const Block& wire)
170{
Alexander Afanasyevba096052014-09-19 15:36:37 -0700171 clear();
172
Junxiao Shi7284a402014-09-12 13:42:16 -0700173 if (wire.type() != tlv::Exclude)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700174 BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Exclude"));
Junxiao Shi7284a402014-09-12 13:42:16 -0700175
Junxiao Shi75203022014-09-11 10:01:50 -0700176 m_wire = wire;
177 m_wire.parse();
178
Junxiao Shi7284a402014-09-12 13:42:16 -0700179 if (m_wire.elements_size() == 0) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700180 BOOST_THROW_EXCEPTION(Error("Exclude element cannot be empty"));
Junxiao Shi7284a402014-09-12 13:42:16 -0700181 }
182
Junxiao Shi75203022014-09-11 10:01:50 -0700183 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
184 // Any ::= ANY-TYPE TLV-LENGTH(=0)
185
186 Block::element_const_iterator i = m_wire.elements_begin();
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700187 if (i->type() == tlv::Any) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000188 this->appendEntry(true, true);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700189 ++i;
190 }
191
192 while (i != m_wire.elements_end()) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000193 name::Component component;
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700194 try {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000195 component = name::Component(*i);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700196 }
197 catch (const name::Component::Error&) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700198 BOOST_THROW_EXCEPTION(Error("Incorrect format of Exclude filter"));
Junxiao Shi75203022014-09-11 10:01:50 -0700199 }
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700200 ++i;
Junxiao Shi75203022014-09-11 10:01:50 -0700201
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000202 if (i != m_wire.elements_end() && i->type() == tlv::Any) {
203 this->appendEntry(component, true);
204 ++i;
Junxiao Shi75203022014-09-11 10:01:50 -0700205 }
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700206 else {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000207 this->appendEntry(component, false);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700208 }
209 }
Junxiao Shi75203022014-09-11 10:01:50 -0700210}
211
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000212template<typename T>
213void
214Exclude::appendEntry(const T& component, bool hasAny)
215{
216 m_entries.emplace_hint(m_entries.begin(), std::piecewise_construct,
217 std::forward_as_tuple(component),
218 std::forward_as_tuple(hasAny));
219}
220
221// example: ANY "b" "d" ANY "f"
222// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800223//
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000224// lower_bound("") -> -Inf (true) <-- excluded (ANY)
225// lower_bound("a") -> -Inf (true) <-- excluded (ANY)
226// lower_bound("b") -> "b" (false) <--- excluded (equal)
227// lower_bound("c") -> "b" (false) <--- not excluded (not equal and no ANY)
228// lower_bound("d") -> "d" (true) <- excluded
229// lower_bound("e") -> "d" (true) <- excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800230bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700231Exclude::isExcluded(const name::Component& comp) const
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800232{
Junxiao Shib80e9472016-07-20 13:45:24 +0000233 ExcludeMap::const_iterator lb = m_entries.lower_bound(comp);
234 return lb != m_entries.end() && // if false, comp is less than the first excluded component
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000235 (lb->second || // comp matches an ANY range
236 (!lb->first.isNegInf && lb->first.component == comp)); // comp equals an exact excluded component
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800237}
238
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700239Exclude&
240Exclude::excludeOne(const name::Component& comp)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800241{
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700242 if (!isExcluded(comp)) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000243 this->appendEntry(comp, false);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700244 m_wire.reset();
245 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800246 return *this;
247}
248
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000249Exclude&
250Exclude::excludeBefore(const name::Component& to)
251{
252 return excludeRange(ExcludeComponent(true), to);
253}
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800254
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700255Exclude&
256Exclude::excludeRange(const name::Component& from, const name::Component& to)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800257{
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000258 return excludeRange(ExcludeComponent(from), to);
259}
260
261// example: ANY "b" "d" ANY "g"
262// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true)
263// possible sequence of operations:
264// excludeBefore("a") -> excludeRange(-Inf, "a") -> ANY "a"
265// "a" (false); -Inf (true)
266// excludeBefore("b") -> excludeRange(-Inf, "b") -> ANY "b"
267// "b" (false); -Inf (true)
268// excludeRange("e", "g") -> ANY "b" "e" ANY "g"
269// "g" (false); "e" (true); "b" (false); -Inf (true)
270// excludeRange("d", "f") -> ANY "b" "d" ANY "g"
271// "g" (false); "d" (true); "b" (false); -Inf (true)
272
273Exclude&
274Exclude::excludeRange(const ExcludeComponent& from, const name::Component& to)
275{
276 if (!from.isNegInf && from.component >= to) {
277 BOOST_THROW_EXCEPTION(Error("Invalid exclude range [" + from.component.toUri() + ", " + to.toUri() + "] "
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700278 "(for single name exclude use Exclude::excludeOne)"));
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700279 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800280
Junxiao Shib80e9472016-07-20 13:45:24 +0000281 ExcludeMap::iterator newFrom = m_entries.lower_bound(from);
282 if (newFrom == m_entries.end() || !newFrom->second /*without ANY*/) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000283 bool isNewEntry = false;
284 std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true);
285 if (!isNewEntry) {
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700286 // this means that the lower bound is equal to the item itself. So, just update ANY flag
287 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800288 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700289 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800290 // else
291 // nothing special if start of the range already exists with ANY flag set
292
Junxiao Shib80e9472016-07-20 13:45:24 +0000293 ExcludeMap::iterator newTo = m_entries.lower_bound(to);
294 BOOST_ASSERT(newTo != m_entries.end());
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700295 if (newTo == newFrom || !newTo->second) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000296 newTo = m_entries.emplace_hint(newTo, to, false);
297 ++newTo;
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700298 }
299 // else
300 // nothing to do really
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800301
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000302 // remove any intermediate entries, since all of the are excluded
303 m_entries.erase(newTo, newFrom);
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800304
Alexander Afanasyevba096052014-09-19 15:36:37 -0700305 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800306 return *this;
307}
308
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700309Exclude&
310Exclude::excludeAfter(const name::Component& from)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800311{
Junxiao Shib80e9472016-07-20 13:45:24 +0000312 ExcludeMap::iterator newFrom = m_entries.lower_bound(from);
313 if (newFrom == m_entries.end() || !newFrom->second /*without ANY*/) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000314 bool isNewEntry = false;
315 std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true);
316 if (!isNewEntry) {
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700317 // this means that the lower bound is equal to the item itself. So, just update ANY flag
318 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800319 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700320 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800321 // else
322 // nothing special if start of the range already exists with ANY flag set
323
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000324 // remove any intermediate node, since all of the are excluded
325 m_entries.erase(m_entries.begin(), newFrom);
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800326
Alexander Afanasyevba096052014-09-19 15:36:37 -0700327 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800328 return *this;
329}
330
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800331std::ostream&
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700332operator<<(std::ostream& os, const Exclude& exclude)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800333{
Davide Pesaventocf415762017-02-25 23:46:47 -0500334 auto join = make_ostream_joiner(os, ',');
Junxiao Shib80e9472016-07-20 13:45:24 +0000335 for (const Exclude::Entry& entry : exclude.m_entries | boost::adaptors::reversed) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000336 if (!entry.first.isNegInf) {
Davide Pesaventocf415762017-02-25 23:46:47 -0500337 join = entry.first.component;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800338 }
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000339 if (entry.second) {
Davide Pesaventocf415762017-02-25 23:46:47 -0500340 join = '*';
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700341 }
342 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800343 return os;
344}
345
Alexander Afanasyevba096052014-09-19 15:36:37 -0700346std::string
347Exclude::toUri() const
348{
349 std::ostringstream os;
350 os << *this;
351 return os.str();
352}
353
354bool
355Exclude::operator==(const Exclude& other) const
356{
Junxiao Shib80e9472016-07-20 13:45:24 +0000357 return m_entries == other.m_entries;
358}
Alexander Afanasyevba096052014-09-19 15:36:37 -0700359
Junxiao Shib80e9472016-07-20 13:45:24 +0000360size_t
361Exclude::size() const
362{
363 return std::distance(begin(), end());
364}
365
366void
367Exclude::clear()
368{
369 m_entries.clear();
370 m_wire.reset();
371}
372
373Exclude::const_iterator::const_iterator(ExcludeMap::const_reverse_iterator it,
374 ExcludeMap::const_reverse_iterator rend)
375 : m_it(it)
376 , m_rend(rend)
377{
378 this->update();
379}
380
381Exclude::const_iterator&
382Exclude::const_iterator::operator++()
383{
384 bool wasInRange = m_it->second;
385 ++m_it;
386 if (wasInRange && m_it != m_rend) {
387 BOOST_ASSERT(m_it->second == false); // consecutive ranges should have been combined
388 ++m_it; // skip over range high limit
389 }
390 this->update();
391 return *this;
392}
393
394Exclude::const_iterator
395Exclude::const_iterator::operator++(int)
396{
397 const_iterator i = *this;
398 this->operator++();
399 return i;
400}
401
402void
403Exclude::const_iterator::update()
404{
405 if (m_it == m_rend) {
406 return;
407 }
408
409 if (m_it->second) { // range
410 if (m_it->first.isNegInf) {
411 m_range.fromInfinity = true;
412 }
413 else {
414 m_range.fromInfinity = false;
415 m_range.from = m_it->first.component;
416 }
417
418 auto next = std::next(m_it);
419 if (next == m_rend) {
420 m_range.toInfinity = true;
421 }
422 else {
423 m_range.toInfinity = false;
424 m_range.to = next->first.component;
425 }
426 }
427 else { // single
428 BOOST_ASSERT(!m_it->first.isNegInf);
429 m_range.fromInfinity = m_range.toInfinity = false;
430 m_range.from = m_range.to = m_it->first.component;
431 }
Alexander Afanasyevba096052014-09-19 15:36:37 -0700432}
433
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700434} // namespace ndn