blob: f3529485d94e270cf943b15a2086e9d633ec3da5 [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
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 }
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700197 ++i;
Junxiao Shi75203022014-09-11 10:01:50 -0700198
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000199 if (i != m_wire.elements_end() && i->type() == tlv::Any) {
200 this->appendEntry(component, true);
201 ++i;
Junxiao Shi75203022014-09-11 10:01:50 -0700202 }
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700203 else {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000204 this->appendEntry(component, false);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700205 }
206 }
Junxiao Shi75203022014-09-11 10:01:50 -0700207}
208
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000209template<typename T>
210void
211Exclude::appendEntry(const T& component, bool hasAny)
212{
213 m_entries.emplace_hint(m_entries.begin(), std::piecewise_construct,
214 std::forward_as_tuple(component),
215 std::forward_as_tuple(hasAny));
216}
217
218// example: ANY "b" "d" ANY "f"
219// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800220//
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000221// lower_bound("") -> -Inf (true) <-- excluded (ANY)
222// lower_bound("a") -> -Inf (true) <-- excluded (ANY)
223// lower_bound("b") -> "b" (false) <--- excluded (equal)
224// lower_bound("c") -> "b" (false) <--- not excluded (not equal and no ANY)
225// lower_bound("d") -> "d" (true) <- excluded
226// lower_bound("e") -> "d" (true) <- excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800227bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700228Exclude::isExcluded(const name::Component& comp) const
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800229{
Junxiao Shib80e9472016-07-20 13:45:24 +0000230 ExcludeMap::const_iterator lb = m_entries.lower_bound(comp);
231 return lb != m_entries.end() && // if false, comp is less than the first excluded component
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000232 (lb->second || // comp matches an ANY range
233 (!lb->first.isNegInf && lb->first.component == comp)); // comp equals an exact excluded component
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800234}
235
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700236Exclude&
237Exclude::excludeOne(const name::Component& comp)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800238{
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700239 if (!isExcluded(comp)) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000240 this->appendEntry(comp, false);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700241 m_wire.reset();
242 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800243 return *this;
244}
245
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000246Exclude&
247Exclude::excludeBefore(const name::Component& to)
248{
249 return excludeRange(ExcludeComponent(true), to);
250}
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800251
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700252Exclude&
253Exclude::excludeRange(const name::Component& from, const name::Component& to)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800254{
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000255 return excludeRange(ExcludeComponent(from), to);
256}
257
258// example: ANY "b" "d" ANY "g"
259// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true)
260// possible sequence of operations:
261// excludeBefore("a") -> excludeRange(-Inf, "a") -> ANY "a"
262// "a" (false); -Inf (true)
263// excludeBefore("b") -> excludeRange(-Inf, "b") -> ANY "b"
264// "b" (false); -Inf (true)
265// excludeRange("e", "g") -> ANY "b" "e" ANY "g"
266// "g" (false); "e" (true); "b" (false); -Inf (true)
267// excludeRange("d", "f") -> ANY "b" "d" ANY "g"
268// "g" (false); "d" (true); "b" (false); -Inf (true)
269
270Exclude&
271Exclude::excludeRange(const ExcludeComponent& from, const name::Component& to)
272{
273 if (!from.isNegInf && from.component >= to) {
274 BOOST_THROW_EXCEPTION(Error("Invalid exclude range [" + from.component.toUri() + ", " + to.toUri() + "] "
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700275 "(for single name exclude use Exclude::excludeOne)"));
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700276 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800277
Junxiao Shib80e9472016-07-20 13:45:24 +0000278 ExcludeMap::iterator newFrom = m_entries.lower_bound(from);
279 if (newFrom == m_entries.end() || !newFrom->second /*without ANY*/) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000280 bool isNewEntry = false;
281 std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true);
282 if (!isNewEntry) {
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700283 // this means that the lower bound is equal to the item itself. So, just update ANY flag
284 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800285 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700286 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800287 // else
288 // nothing special if start of the range already exists with ANY flag set
289
Junxiao Shib80e9472016-07-20 13:45:24 +0000290 ExcludeMap::iterator newTo = m_entries.lower_bound(to);
291 BOOST_ASSERT(newTo != m_entries.end());
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700292 if (newTo == newFrom || !newTo->second) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000293 newTo = m_entries.emplace_hint(newTo, to, false);
294 ++newTo;
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700295 }
296 // else
297 // nothing to do really
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800298
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000299 // remove any intermediate entries, since all of the are excluded
300 m_entries.erase(newTo, newFrom);
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800301
Alexander Afanasyevba096052014-09-19 15:36:37 -0700302 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800303 return *this;
304}
305
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700306Exclude&
307Exclude::excludeAfter(const name::Component& from)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800308{
Junxiao Shib80e9472016-07-20 13:45:24 +0000309 ExcludeMap::iterator newFrom = m_entries.lower_bound(from);
310 if (newFrom == m_entries.end() || !newFrom->second /*without ANY*/) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000311 bool isNewEntry = false;
312 std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true);
313 if (!isNewEntry) {
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700314 // this means that the lower bound is equal to the item itself. So, just update ANY flag
315 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800316 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700317 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800318 // else
319 // nothing special if start of the range already exists with ANY flag set
320
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000321 // remove any intermediate node, since all of the are excluded
322 m_entries.erase(m_entries.begin(), newFrom);
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800323
Alexander Afanasyevba096052014-09-19 15:36:37 -0700324 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800325 return *this;
326}
327
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800328std::ostream&
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700329operator<<(std::ostream& os, const Exclude& exclude)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800330{
Davide Pesaventocf415762017-02-25 23:46:47 -0500331 auto join = make_ostream_joiner(os, ',');
Junxiao Shib80e9472016-07-20 13:45:24 +0000332 for (const Exclude::Entry& entry : exclude.m_entries | boost::adaptors::reversed) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000333 if (!entry.first.isNegInf) {
Davide Pesaventocf415762017-02-25 23:46:47 -0500334 join = entry.first.component;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800335 }
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000336 if (entry.second) {
Davide Pesaventocf415762017-02-25 23:46:47 -0500337 join = '*';
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700338 }
339 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800340 return os;
341}
342
Alexander Afanasyevba096052014-09-19 15:36:37 -0700343std::string
344Exclude::toUri() const
345{
346 std::ostringstream os;
347 os << *this;
348 return os.str();
349}
350
351bool
352Exclude::operator==(const Exclude& other) const
353{
Junxiao Shib80e9472016-07-20 13:45:24 +0000354 return m_entries == other.m_entries;
355}
Alexander Afanasyevba096052014-09-19 15:36:37 -0700356
Junxiao Shib80e9472016-07-20 13:45:24 +0000357size_t
358Exclude::size() const
359{
360 return std::distance(begin(), end());
361}
362
363void
364Exclude::clear()
365{
366 m_entries.clear();
367 m_wire.reset();
368}
369
370Exclude::const_iterator::const_iterator(ExcludeMap::const_reverse_iterator it,
371 ExcludeMap::const_reverse_iterator rend)
372 : m_it(it)
373 , m_rend(rend)
374{
375 this->update();
376}
377
378Exclude::const_iterator&
379Exclude::const_iterator::operator++()
380{
381 bool wasInRange = m_it->second;
382 ++m_it;
383 if (wasInRange && m_it != m_rend) {
384 BOOST_ASSERT(m_it->second == false); // consecutive ranges should have been combined
385 ++m_it; // skip over range high limit
386 }
387 this->update();
388 return *this;
389}
390
391Exclude::const_iterator
392Exclude::const_iterator::operator++(int)
393{
394 const_iterator i = *this;
395 this->operator++();
396 return i;
397}
398
399void
400Exclude::const_iterator::update()
401{
402 if (m_it == m_rend) {
403 return;
404 }
405
406 if (m_it->second) { // range
407 if (m_it->first.isNegInf) {
408 m_range.fromInfinity = true;
409 }
410 else {
411 m_range.fromInfinity = false;
412 m_range.from = m_it->first.component;
413 }
414
415 auto next = std::next(m_it);
416 if (next == m_rend) {
417 m_range.toInfinity = true;
418 }
419 else {
420 m_range.toInfinity = false;
421 m_range.to = next->first.component;
422 }
423 }
424 else { // single
425 BOOST_ASSERT(!m_it->first.isNegInf);
426 m_range.fromInfinity = m_range.toInfinity = false;
427 m_range.from = m_range.to = m_it->first.component;
428 }
Alexander Afanasyevba096052014-09-19 15:36:37 -0700429}
430
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700431} // namespace ndn