blob: 19091f40ce8317453195ab66f8bb441c1542f1e9 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07002/**
Junxiao Shidf4b24e2016-07-14 21:41:43 +00003 * Copyright (c) 2013-2016 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
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -070027#include <boost/range/adaptors.hpp>
28
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
44operator>(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
Junxiao Shic2b8d242014-11-04 08:35:29 -070050BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Exclude>));
51BOOST_CONCEPT_ASSERT((WireEncodable<Exclude>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070052BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Exclude>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070053BOOST_CONCEPT_ASSERT((WireDecodable<Exclude>));
54static_assert(std::is_base_of<tlv::Error, Exclude::Error>::value,
55 "Exclude::Error must inherit from tlv::Error");
Junxiao Shi7284a402014-09-12 13:42:16 -070056
Junxiao Shidf4b24e2016-07-14 21:41:43 +000057Exclude::Exclude() = default;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -080058
Junxiao Shi75203022014-09-11 10:01:50 -070059Exclude::Exclude(const Block& wire)
60{
61 wireDecode(wire);
62}
63
Alexander Afanasyev74633892015-02-08 18:08:46 -080064template<encoding::Tag TAG>
Junxiao Shi75203022014-09-11 10:01:50 -070065size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070066Exclude::wireEncode(EncodingImpl<TAG>& encoder) const
Junxiao Shi75203022014-09-11 10:01:50 -070067{
Junxiao Shidf4b24e2016-07-14 21:41:43 +000068 if (m_entries.empty()) {
69 BOOST_THROW_EXCEPTION(Error("cannot encode empty Exclude selector"));
Junxiao Shi7284a402014-09-12 13:42:16 -070070 }
71
Junxiao Shi75203022014-09-11 10:01:50 -070072 size_t totalLength = 0;
73
74 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
75 // Any ::= ANY-TYPE TLV-LENGTH(=0)
76
Junxiao Shidf4b24e2016-07-14 21:41:43 +000077 for (const Entry& entry : m_entries) {
78 if (entry.second) {
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070079 totalLength += prependEmptyBlock(encoder, tlv::Any);
Junxiao Shi75203022014-09-11 10:01:50 -070080 }
Junxiao Shidf4b24e2016-07-14 21:41:43 +000081 if (!entry.first.isNegInf) {
82 totalLength += entry.first.component.wireEncode(encoder);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -070083 }
84 }
Junxiao Shi75203022014-09-11 10:01:50 -070085
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070086 totalLength += encoder.prependVarNumber(totalLength);
87 totalLength += encoder.prependVarNumber(tlv::Exclude);
Junxiao Shi75203022014-09-11 10:01:50 -070088 return totalLength;
89}
90
91template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070092Exclude::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
Junxiao Shi75203022014-09-11 10:01:50 -070093
94template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070095Exclude::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
Junxiao Shi75203022014-09-11 10:01:50 -070096
97const Block&
98Exclude::wireEncode() const
99{
100 if (m_wire.hasWire())
101 return m_wire;
102
103 EncodingEstimator estimator;
104 size_t estimatedSize = wireEncode(estimator);
105
106 EncodingBuffer buffer(estimatedSize, 0);
107 wireEncode(buffer);
108
109 m_wire = buffer.block();
110 return m_wire;
111}
112
113void
114Exclude::wireDecode(const Block& wire)
115{
Alexander Afanasyevba096052014-09-19 15:36:37 -0700116 clear();
117
Junxiao Shi7284a402014-09-12 13:42:16 -0700118 if (wire.type() != tlv::Exclude)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700119 BOOST_THROW_EXCEPTION(tlv::Error("Unexpected TLV type when decoding Exclude"));
Junxiao Shi7284a402014-09-12 13:42:16 -0700120
Junxiao Shi75203022014-09-11 10:01:50 -0700121 m_wire = wire;
122 m_wire.parse();
123
Junxiao Shi7284a402014-09-12 13:42:16 -0700124 if (m_wire.elements_size() == 0) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700125 BOOST_THROW_EXCEPTION(Error("Exclude element cannot be empty"));
Junxiao Shi7284a402014-09-12 13:42:16 -0700126 }
127
Junxiao Shi75203022014-09-11 10:01:50 -0700128 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
129 // Any ::= ANY-TYPE TLV-LENGTH(=0)
130
131 Block::element_const_iterator i = m_wire.elements_begin();
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700132 if (i->type() == tlv::Any) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000133 this->appendEntry(true, true);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700134 ++i;
135 }
136
137 while (i != m_wire.elements_end()) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000138 name::Component component;
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700139 try {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000140 component = name::Component(*i);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700141 }
142 catch (const name::Component::Error&) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700143 BOOST_THROW_EXCEPTION(Error("Incorrect format of Exclude filter"));
Junxiao Shi75203022014-09-11 10:01:50 -0700144 }
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700145 ++i;
Junxiao Shi75203022014-09-11 10:01:50 -0700146
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000147 if (i != m_wire.elements_end() && i->type() == tlv::Any) {
148 this->appendEntry(component, true);
149 ++i;
Junxiao Shi75203022014-09-11 10:01:50 -0700150 }
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700151 else {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000152 this->appendEntry(component, false);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700153 }
154 }
Junxiao Shi75203022014-09-11 10:01:50 -0700155}
156
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000157template<typename T>
158void
159Exclude::appendEntry(const T& component, bool hasAny)
160{
161 m_entries.emplace_hint(m_entries.begin(), std::piecewise_construct,
162 std::forward_as_tuple(component),
163 std::forward_as_tuple(hasAny));
164}
165
166// example: ANY "b" "d" ANY "f"
167// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800168//
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000169// lower_bound("") -> -Inf (true) <-- excluded (ANY)
170// lower_bound("a") -> -Inf (true) <-- excluded (ANY)
171// lower_bound("b") -> "b" (false) <--- excluded (equal)
172// lower_bound("c") -> "b" (false) <--- not excluded (not equal and no ANY)
173// lower_bound("d") -> "d" (true) <- excluded
174// lower_bound("e") -> "d" (true) <- excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800175bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700176Exclude::isExcluded(const name::Component& comp) const
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800177{
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000178 const_iterator lb = m_entries.lower_bound(comp);
179 return lb != end() && // lb==end() means comp is less than the first excluded component
180 (lb->second || // comp matches an ANY range
181 (!lb->first.isNegInf && lb->first.component == comp)); // comp equals an exact excluded component
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800182}
183
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700184Exclude&
185Exclude::excludeOne(const name::Component& comp)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800186{
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700187 if (!isExcluded(comp)) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000188 this->appendEntry(comp, false);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700189 m_wire.reset();
190 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800191 return *this;
192}
193
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000194Exclude&
195Exclude::excludeBefore(const name::Component& to)
196{
197 return excludeRange(ExcludeComponent(true), to);
198}
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800199
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700200Exclude&
201Exclude::excludeRange(const name::Component& from, const name::Component& to)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800202{
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000203 return excludeRange(ExcludeComponent(from), to);
204}
205
206// example: ANY "b" "d" ANY "g"
207// ordered in map as: "f" (false); "d" (true); "b" (false); -Inf (true)
208// possible sequence of operations:
209// excludeBefore("a") -> excludeRange(-Inf, "a") -> ANY "a"
210// "a" (false); -Inf (true)
211// excludeBefore("b") -> excludeRange(-Inf, "b") -> ANY "b"
212// "b" (false); -Inf (true)
213// excludeRange("e", "g") -> ANY "b" "e" ANY "g"
214// "g" (false); "e" (true); "b" (false); -Inf (true)
215// excludeRange("d", "f") -> ANY "b" "d" ANY "g"
216// "g" (false); "d" (true); "b" (false); -Inf (true)
217
218Exclude&
219Exclude::excludeRange(const ExcludeComponent& from, const name::Component& to)
220{
221 if (!from.isNegInf && from.component >= to) {
222 BOOST_THROW_EXCEPTION(Error("Invalid exclude range [" + from.component.toUri() + ", " + to.toUri() + "] "
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700223 "(for single name exclude use Exclude::excludeOne)"));
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700224 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800225
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000226 iterator newFrom = m_entries.lower_bound(from);
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700227 if (newFrom == end() || !newFrom->second /*without ANY*/) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000228 bool isNewEntry = false;
229 std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true);
230 if (!isNewEntry) {
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700231 // this means that the lower bound is equal to the item itself. So, just update ANY flag
232 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800233 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700234 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800235 // else
236 // nothing special if start of the range already exists with ANY flag set
237
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000238 iterator newTo = m_entries.lower_bound(to);
239 BOOST_ASSERT(newTo != end());
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700240 if (newTo == newFrom || !newTo->second) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000241 newTo = m_entries.emplace_hint(newTo, to, false);
242 ++newTo;
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700243 }
244 // else
245 // nothing to do really
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800246
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000247 // remove any intermediate entries, since all of the are excluded
248 m_entries.erase(newTo, newFrom);
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800249
Alexander Afanasyevba096052014-09-19 15:36:37 -0700250 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800251 return *this;
252}
253
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700254Exclude&
255Exclude::excludeAfter(const name::Component& from)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800256{
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000257 iterator newFrom = m_entries.lower_bound(from);
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700258 if (newFrom == end() || !newFrom->second /*without ANY*/) {
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000259 bool isNewEntry = false;
260 std::tie(newFrom, isNewEntry) = m_entries.emplace(from, true);
261 if (!isNewEntry) {
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700262 // this means that the lower bound is equal to the item itself. So, just update ANY flag
263 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800264 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700265 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800266 // else
267 // nothing special if start of the range already exists with ANY flag set
268
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000269 // remove any intermediate node, since all of the are excluded
270 m_entries.erase(m_entries.begin(), newFrom);
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800271
Alexander Afanasyevba096052014-09-19 15:36:37 -0700272 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800273 return *this;
274}
275
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000276void
277Exclude::clear()
278{
279 m_entries.clear();
280 m_wire.reset();
281}
282
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800283std::ostream&
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700284operator<<(std::ostream& os, const Exclude& exclude)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800285{
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700286 bool isFirst = true;
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000287 for (const Exclude::Entry& entry : exclude | boost::adaptors::reversed) {
288 if (!entry.first.isNegInf) {
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700289 if (!isFirst)
290 os << ",";
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000291 entry.first.component.toUri(os);
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700292 isFirst = false;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800293 }
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000294 if (entry.second) {
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700295 if (!isFirst)
296 os << ",";
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700297 os << "*";
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700298 isFirst = false;
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700299 }
300 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800301 return os;
302}
303
Alexander Afanasyevba096052014-09-19 15:36:37 -0700304std::string
305Exclude::toUri() const
306{
307 std::ostringstream os;
308 os << *this;
309 return os.str();
310}
311
312bool
313Exclude::operator==(const Exclude& other) const
314{
315 if (empty() && other.empty())
316 return true;
317 if (empty() || other.empty())
318 return false;
319
320 return wireEncode() == other.wireEncode();
321}
322
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700323} // namespace ndn