blob: 900d933c3be04c5ee53d92669664055ae4ab6d62 [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>
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
147template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700148Exclude::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
Junxiao Shi75203022014-09-11 10:01:50 -0700149
150template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700151Exclude::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
Junxiao Shi75203022014-09-11 10:01:50 -0700152
153const Block&
154Exclude::wireEncode() const
155{
156 if (m_wire.hasWire())
157 return m_wire;
158
159 EncodingEstimator estimator;
160 size_t estimatedSize = wireEncode(estimator);
161
162 EncodingBuffer buffer(estimatedSize, 0);
163 wireEncode(buffer);
164
165 m_wire = buffer.block();
166 return m_wire;
167}
168
169void
170Exclude::wireDecode(const Block& wire)
171{
Alexander Afanasyevba096052014-09-19 15:36:37 -0700172 clear();
173
Junxiao Shi7284a402014-09-12 13:42:16 -0700174 if (wire.type() != tlv::Exclude)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700175 BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Exclude"));
Junxiao Shi7284a402014-09-12 13:42:16 -0700176
Junxiao Shi75203022014-09-11 10:01:50 -0700177 m_wire = wire;
178 m_wire.parse();
179
Junxiao Shi7284a402014-09-12 13:42:16 -0700180 if (m_wire.elements_size() == 0) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700181 BOOST_THROW_EXCEPTION(Error("Exclude element cannot be empty"));
Junxiao Shi7284a402014-09-12 13:42:16 -0700182 }
183
Junxiao Shi75203022014-09-11 10:01:50 -0700184 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
185 // Any ::= ANY-TYPE TLV-LENGTH(=0)
186
187 Block::element_const_iterator i = m_wire.elements_begin();
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700188 if (i->type() == tlv::Any) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000189 this->appendEntry(true, true);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700190 ++i;
191 }
192
193 while (i != m_wire.elements_end()) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000194 name::Component component;
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700195 try {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000196 component = name::Component(*i);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700197 }
198 catch (const name::Component::Error&) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700199 BOOST_THROW_EXCEPTION(Error("Incorrect format of Exclude filter"));
Junxiao Shi75203022014-09-11 10:01:50 -0700200 }
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700201 ++i;
Junxiao Shi75203022014-09-11 10:01:50 -0700202
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000203 if (i != m_wire.elements_end() && i->type() == tlv::Any) {
204 this->appendEntry(component, true);
205 ++i;
Junxiao Shi75203022014-09-11 10:01:50 -0700206 }
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700207 else {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000208 this->appendEntry(component, false);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700209 }
210 }
Junxiao Shi75203022014-09-11 10:01:50 -0700211}
212
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000213template<typename T>
214void
215Exclude::appendEntry(const T& component, bool hasAny)
216{
217 m_entries.emplace_hint(m_entries.begin(), std::piecewise_construct,
218 std::forward_as_tuple(component),
219 std::forward_as_tuple(hasAny));
220}
221
222// example: ANY "b" "d" ANY "f"
223// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800224//
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000225// lower_bound("") -> -Inf (true) <-- excluded (ANY)
226// lower_bound("a") -> -Inf (true) <-- excluded (ANY)
227// lower_bound("b") -> "b" (false) <--- excluded (equal)
228// lower_bound("c") -> "b" (false) <--- not excluded (not equal and no ANY)
229// lower_bound("d") -> "d" (true) <- excluded
230// lower_bound("e") -> "d" (true) <- excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800231bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700232Exclude::isExcluded(const name::Component& comp) const
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800233{
Junxiao Shib80e9472016-07-20 13:45:24 +0000234 ExcludeMap::const_iterator lb = m_entries.lower_bound(comp);
235 return lb != m_entries.end() && // if false, comp is less than the first excluded component
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000236 (lb->second || // comp matches an ANY range
237 (!lb->first.isNegInf && lb->first.component == comp)); // comp equals an exact excluded component
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800238}
239
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700240Exclude&
241Exclude::excludeOne(const name::Component& comp)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800242{
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700243 if (!isExcluded(comp)) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000244 this->appendEntry(comp, false);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700245 m_wire.reset();
246 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800247 return *this;
248}
249
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000250Exclude&
251Exclude::excludeBefore(const name::Component& to)
252{
253 return excludeRange(ExcludeComponent(true), to);
254}
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800255
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700256Exclude&
257Exclude::excludeRange(const name::Component& from, const name::Component& to)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800258{
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000259 return excludeRange(ExcludeComponent(from), to);
260}
261
262// example: ANY "b" "d" ANY "g"
263// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true)
264// possible sequence of operations:
265// excludeBefore("a") -> excludeRange(-Inf, "a") -> ANY "a"
266// "a" (false); -Inf (true)
267// excludeBefore("b") -> excludeRange(-Inf, "b") -> ANY "b"
268// "b" (false); -Inf (true)
269// excludeRange("e", "g") -> ANY "b" "e" ANY "g"
270// "g" (false); "e" (true); "b" (false); -Inf (true)
271// excludeRange("d", "f") -> ANY "b" "d" ANY "g"
272// "g" (false); "d" (true); "b" (false); -Inf (true)
273
274Exclude&
275Exclude::excludeRange(const ExcludeComponent& from, const name::Component& to)
276{
277 if (!from.isNegInf && from.component >= to) {
278 BOOST_THROW_EXCEPTION(Error("Invalid exclude range [" + from.component.toUri() + ", " + to.toUri() + "] "
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700279 "(for single name exclude use Exclude::excludeOne)"));
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700280 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800281
Junxiao Shib80e9472016-07-20 13:45:24 +0000282 ExcludeMap::iterator newFrom = m_entries.lower_bound(from);
283 if (newFrom == m_entries.end() || !newFrom->second /*without ANY*/) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000284 bool isNewEntry = false;
285 std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true);
286 if (!isNewEntry) {
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700287 // this means that the lower bound is equal to the item itself. So, just update ANY flag
288 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800289 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700290 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800291 // else
292 // nothing special if start of the range already exists with ANY flag set
293
Junxiao Shib80e9472016-07-20 13:45:24 +0000294 ExcludeMap::iterator newTo = m_entries.lower_bound(to);
295 BOOST_ASSERT(newTo != m_entries.end());
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700296 if (newTo == newFrom || !newTo->second) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000297 newTo = m_entries.emplace_hint(newTo, to, false);
298 ++newTo;
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700299 }
300 // else
301 // nothing to do really
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800302
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000303 // remove any intermediate entries, since all of the are excluded
304 m_entries.erase(newTo, newFrom);
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800305
Alexander Afanasyevba096052014-09-19 15:36:37 -0700306 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800307 return *this;
308}
309
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700310Exclude&
311Exclude::excludeAfter(const name::Component& from)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800312{
Junxiao Shib80e9472016-07-20 13:45:24 +0000313 ExcludeMap::iterator newFrom = m_entries.lower_bound(from);
314 if (newFrom == m_entries.end() || !newFrom->second /*without ANY*/) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000315 bool isNewEntry = false;
316 std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true);
317 if (!isNewEntry) {
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700318 // this means that the lower bound is equal to the item itself. So, just update ANY flag
319 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800320 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700321 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800322 // else
323 // nothing special if start of the range already exists with ANY flag set
324
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000325 // remove any intermediate node, since all of the are excluded
326 m_entries.erase(m_entries.begin(), newFrom);
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800327
Alexander Afanasyevba096052014-09-19 15:36:37 -0700328 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800329 return *this;
330}
331
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800332std::ostream&
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700333operator<<(std::ostream& os, const Exclude& exclude)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800334{
Davide Pesaventocf415762017-02-25 23:46:47 -0500335 auto join = make_ostream_joiner(os, ',');
Junxiao Shib80e9472016-07-20 13:45:24 +0000336 for (const Exclude::Entry& entry : exclude.m_entries | boost::adaptors::reversed) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000337 if (!entry.first.isNegInf) {
Davide Pesaventocf415762017-02-25 23:46:47 -0500338 join = entry.first.component;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800339 }
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000340 if (entry.second) {
Davide Pesaventocf415762017-02-25 23:46:47 -0500341 join = '*';
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700342 }
343 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800344 return os;
345}
346
Alexander Afanasyevba096052014-09-19 15:36:37 -0700347std::string
348Exclude::toUri() const
349{
350 std::ostringstream os;
351 os << *this;
352 return os.str();
353}
354
355bool
356Exclude::operator==(const Exclude& other) const
357{
Junxiao Shib80e9472016-07-20 13:45:24 +0000358 return m_entries == other.m_entries;
359}
Alexander Afanasyevba096052014-09-19 15:36:37 -0700360
Junxiao Shib80e9472016-07-20 13:45:24 +0000361size_t
362Exclude::size() const
363{
364 return std::distance(begin(), end());
365}
366
367void
368Exclude::clear()
369{
370 m_entries.clear();
371 m_wire.reset();
372}
373
374Exclude::const_iterator::const_iterator(ExcludeMap::const_reverse_iterator it,
375 ExcludeMap::const_reverse_iterator rend)
376 : m_it(it)
377 , m_rend(rend)
378{
379 this->update();
380}
381
382Exclude::const_iterator&
383Exclude::const_iterator::operator++()
384{
385 bool wasInRange = m_it->second;
386 ++m_it;
387 if (wasInRange && m_it != m_rend) {
388 BOOST_ASSERT(m_it->second == false); // consecutive ranges should have been combined
389 ++m_it; // skip over range high limit
390 }
391 this->update();
392 return *this;
393}
394
395Exclude::const_iterator
396Exclude::const_iterator::operator++(int)
397{
398 const_iterator i = *this;
399 this->operator++();
400 return i;
401}
402
403void
404Exclude::const_iterator::update()
405{
406 if (m_it == m_rend) {
407 return;
408 }
409
410 if (m_it->second) { // range
411 if (m_it->first.isNegInf) {
412 m_range.fromInfinity = true;
413 }
414 else {
415 m_range.fromInfinity = false;
416 m_range.from = m_it->first.component;
417 }
418
419 auto next = std::next(m_it);
420 if (next == m_rend) {
421 m_range.toInfinity = true;
422 }
423 else {
424 m_range.toInfinity = false;
425 m_range.to = next->first.component;
426 }
427 }
428 else { // single
429 BOOST_ASSERT(!m_it->first.isNegInf);
430 m_range.fromInfinity = m_range.toInfinity = false;
431 m_range.from = m_range.to = m_it->first.component;
432 }
Alexander Afanasyevba096052014-09-19 15:36:37 -0700433}
434
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700435} // namespace ndn