blob: bf6bfef5282bd57149708a2fa995e94c2c205d26 [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/*
Junxiao Shicf4ac5b2018-03-28 22:46:06 +00003 * Copyright (c) 2013-2018 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>
Davide Pesaventoa84f4642017-08-23 16:14:51 -040028#include <sstream>
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -070029
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -070030namespace ndn {
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -080031
Junxiao Shidf4b24e2016-07-14 21:41:43 +000032Exclude::ExcludeComponent::ExcludeComponent(const name::Component& component1)
33 : isNegInf(false)
34 , component(component1)
35{
36}
37
38Exclude::ExcludeComponent::ExcludeComponent(bool isNegInf1)
39 : isNegInf(true)
40{
41 BOOST_ASSERT(isNegInf1 == true);
42}
43
44bool
Junxiao Shib80e9472016-07-20 13:45:24 +000045operator==(const Exclude::ExcludeComponent& a, const Exclude::ExcludeComponent& b)
46{
47 return (a.isNegInf && b.isNegInf) ||
48 (a.isNegInf == b.isNegInf && a.component == b.component);
49}
50
51bool
Junxiao Shidf4b24e2016-07-14 21:41:43 +000052operator>(const Exclude::ExcludeComponent& a, const Exclude::ExcludeComponent& b)
53{
54 return a.isNegInf < b.isNegInf ||
55 (a.isNegInf == b.isNegInf && a.component > b.component);
56}
57
Junxiao Shi4f756902017-07-18 03:05:02 +000058Exclude::Range::Range()
59 : fromInfinity(false)
60 , toInfinity(false)
61{
62}
63
64Exclude::Range::Range(bool fromInfinity, const name::Component& from, bool toInfinity, const name::Component& to)
65 : fromInfinity(fromInfinity)
66 , from(from)
67 , toInfinity(toInfinity)
68 , to(to)
69{
70}
71
Junxiao Shib80e9472016-07-20 13:45:24 +000072bool
73Exclude::Range::operator==(const Exclude::Range& other) const
74{
75 return this->fromInfinity == other.fromInfinity && this->toInfinity == other.toInfinity &&
76 (this->fromInfinity || this->from == other.from) &&
77 (this->toInfinity || this->to == other.to);
78}
79
80std::ostream&
81operator<<(std::ostream& os, const Exclude::Range& range)
82{
83 if (range.isSingular()) {
84 return os << '{' << range.from << '}';
85 }
86
87 if (range.fromInfinity) {
88 os << "(-∞";
89 }
90 else {
91 os << '[' << range.from;
92 }
93
94 os << ",";
95
96 if (range.toInfinity) {
97 os << "+∞)";
98 }
99 else {
100 os << range.to << ']';
101 }
102
103 return os;
104}
105
Junxiao Shic2b8d242014-11-04 08:35:29 -0700106BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Exclude>));
107BOOST_CONCEPT_ASSERT((WireEncodable<Exclude>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700108BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Exclude>));
Junxiao Shic2b8d242014-11-04 08:35:29 -0700109BOOST_CONCEPT_ASSERT((WireDecodable<Exclude>));
110static_assert(std::is_base_of<tlv::Error, Exclude::Error>::value,
111 "Exclude::Error must inherit from tlv::Error");
Junxiao Shi7284a402014-09-12 13:42:16 -0700112
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000113Exclude::Exclude() = default;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800114
Junxiao Shi75203022014-09-11 10:01:50 -0700115Exclude::Exclude(const Block& wire)
116{
117 wireDecode(wire);
118}
119
Alexander Afanasyev74633892015-02-08 18:08:46 -0800120template<encoding::Tag TAG>
Junxiao Shi75203022014-09-11 10:01:50 -0700121size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700122Exclude::wireEncode(EncodingImpl<TAG>& encoder) const
Junxiao Shi75203022014-09-11 10:01:50 -0700123{
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000124 if (m_entries.empty()) {
125 BOOST_THROW_EXCEPTION(Error("cannot encode empty Exclude selector"));
Junxiao Shi7284a402014-09-12 13:42:16 -0700126 }
127
Junxiao Shi75203022014-09-11 10:01:50 -0700128 size_t totalLength = 0;
129
130 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
131 // Any ::= ANY-TYPE TLV-LENGTH(=0)
132
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000133 for (const Entry& entry : m_entries) {
134 if (entry.second) {
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700135 totalLength += prependEmptyBlock(encoder, tlv::Any);
Junxiao Shi75203022014-09-11 10:01:50 -0700136 }
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000137 if (!entry.first.isNegInf) {
138 totalLength += entry.first.component.wireEncode(encoder);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700139 }
140 }
Junxiao Shi75203022014-09-11 10:01:50 -0700141
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700142 totalLength += encoder.prependVarNumber(totalLength);
143 totalLength += encoder.prependVarNumber(tlv::Exclude);
Junxiao Shi75203022014-09-11 10:01:50 -0700144 return totalLength;
145}
146
Davide Pesavento88a0d812017-08-19 21:31:42 -0400147NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Exclude);
Junxiao Shi75203022014-09-11 10:01:50 -0700148
149const Block&
150Exclude::wireEncode() const
151{
152 if (m_wire.hasWire())
153 return m_wire;
154
155 EncodingEstimator estimator;
156 size_t estimatedSize = wireEncode(estimator);
157
158 EncodingBuffer buffer(estimatedSize, 0);
159 wireEncode(buffer);
160
161 m_wire = buffer.block();
162 return m_wire;
163}
164
165void
166Exclude::wireDecode(const Block& wire)
167{
Alexander Afanasyevba096052014-09-19 15:36:37 -0700168 clear();
169
Junxiao Shi7284a402014-09-12 13:42:16 -0700170 if (wire.type() != tlv::Exclude)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700171 BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Exclude"));
Junxiao Shi7284a402014-09-12 13:42:16 -0700172
Junxiao Shi75203022014-09-11 10:01:50 -0700173 m_wire = wire;
174 m_wire.parse();
175
Junxiao Shi7284a402014-09-12 13:42:16 -0700176 if (m_wire.elements_size() == 0) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700177 BOOST_THROW_EXCEPTION(Error("Exclude element cannot be empty"));
Junxiao Shi7284a402014-09-12 13:42:16 -0700178 }
179
Junxiao Shi75203022014-09-11 10:01:50 -0700180 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
181 // Any ::= ANY-TYPE TLV-LENGTH(=0)
182
183 Block::element_const_iterator i = m_wire.elements_begin();
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700184 if (i->type() == tlv::Any) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000185 this->appendEntry(true, true);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700186 ++i;
187 }
188
189 while (i != m_wire.elements_end()) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000190 name::Component component;
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700191 try {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000192 component = name::Component(*i);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700193 }
194 catch (const name::Component::Error&) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700195 BOOST_THROW_EXCEPTION(Error("Incorrect format of Exclude filter"));
Junxiao Shi75203022014-09-11 10:01:50 -0700196 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000197 if (!component.isGeneric() && !component.isImplicitSha256Digest()) {
198 BOOST_THROW_EXCEPTION(Error("Excluded component must be generic or ImplicitSha256Digest"));
199 }
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