blob: 76a6260e23c662acd123ddf66df0951b17d6d712 [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/**
Alexander Afanasyev74633892015-02-08 18:08:46 -08003 * Copyright (c) 2013-2015 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"
Junxiao Shic2b8d242014-11-04 08:35:29 -070025#include "util/concepts.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 Shic2b8d242014-11-04 08:35:29 -070031BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Exclude>));
32BOOST_CONCEPT_ASSERT((WireEncodable<Exclude>));
33BOOST_CONCEPT_ASSERT((WireDecodable<Exclude>));
34static_assert(std::is_base_of<tlv::Error, Exclude::Error>::value,
35 "Exclude::Error must inherit from tlv::Error");
Junxiao Shi7284a402014-09-12 13:42:16 -070036
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -070037Exclude::Exclude()
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -080038{
39}
40
Junxiao Shi75203022014-09-11 10:01:50 -070041Exclude::Exclude(const Block& wire)
42{
43 wireDecode(wire);
44}
45
Alexander Afanasyev74633892015-02-08 18:08:46 -080046template<encoding::Tag TAG>
Junxiao Shi75203022014-09-11 10:01:50 -070047size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -080048Exclude::wireEncode(EncodingImpl<TAG>& block) const
Junxiao Shi75203022014-09-11 10:01:50 -070049{
Junxiao Shi7284a402014-09-12 13:42:16 -070050 if (m_exclude.empty()) {
51 throw Error("Exclude filter cannot be empty");
52 }
53
Junxiao Shi75203022014-09-11 10:01:50 -070054 size_t totalLength = 0;
55
56 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
57 // Any ::= ANY-TYPE TLV-LENGTH(=0)
58
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -070059 for (const auto& item : m_exclude) {
60 if (item.second) {
61 totalLength += prependBooleanBlock(block, tlv::Any);
Junxiao Shi75203022014-09-11 10:01:50 -070062 }
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -070063 if (!item.first.empty() || !item.second) {
64 totalLength += item.first.wireEncode(block);
65 }
66 }
Junxiao Shi75203022014-09-11 10:01:50 -070067
68 totalLength += block.prependVarNumber(totalLength);
69 totalLength += block.prependVarNumber(tlv::Exclude);
70 return totalLength;
71}
72
73template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -080074Exclude::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& block) const;
Junxiao Shi75203022014-09-11 10:01:50 -070075
76template size_t
Alexander Afanasyev74633892015-02-08 18:08:46 -080077Exclude::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& block) const;
Junxiao Shi75203022014-09-11 10:01:50 -070078
79const Block&
80Exclude::wireEncode() const
81{
82 if (m_wire.hasWire())
83 return m_wire;
84
85 EncodingEstimator estimator;
86 size_t estimatedSize = wireEncode(estimator);
87
88 EncodingBuffer buffer(estimatedSize, 0);
89 wireEncode(buffer);
90
91 m_wire = buffer.block();
92 return m_wire;
93}
94
95void
96Exclude::wireDecode(const Block& wire)
97{
Alexander Afanasyevba096052014-09-19 15:36:37 -070098 clear();
99
Junxiao Shi7284a402014-09-12 13:42:16 -0700100 if (wire.type() != tlv::Exclude)
101 throw tlv::Error("Unexpected TLV type when decoding Exclude");
102
Junxiao Shi75203022014-09-11 10:01:50 -0700103 m_wire = wire;
104 m_wire.parse();
105
Junxiao Shi7284a402014-09-12 13:42:16 -0700106 if (m_wire.elements_size() == 0) {
107 throw Error("Exclude element cannot be empty");
108 }
109
Junxiao Shi75203022014-09-11 10:01:50 -0700110 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
111 // Any ::= ANY-TYPE TLV-LENGTH(=0)
112
113 Block::element_const_iterator i = m_wire.elements_begin();
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700114 if (i->type() == tlv::Any) {
115 appendExclude(name::Component(), true);
116 ++i;
117 }
118
119 while (i != m_wire.elements_end()) {
120 name::Component excludedComponent;
121 try {
122 excludedComponent = std::move(name::Component(*i));
123 }
124 catch (const name::Component::Error&) {
125 throw Error("Incorrect format of Exclude filter");
Junxiao Shi75203022014-09-11 10:01:50 -0700126 }
127
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700128 ++i;
Junxiao Shi75203022014-09-11 10:01:50 -0700129
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700130 if (i != m_wire.elements_end()) {
131 if (i->type() == tlv::Any) {
132 appendExclude(excludedComponent, true);
133 ++i;
134 }
135 else {
136 appendExclude(excludedComponent, false);
137 }
Junxiao Shi75203022014-09-11 10:01:50 -0700138 }
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700139 else {
140 appendExclude(excludedComponent, false);
141 }
142 }
Junxiao Shi75203022014-09-11 10:01:50 -0700143}
144
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800145// example: ANY /b /d ANY /f
146//
147// ordered in map as:
148//
149// /f (false); /d (true); /b (false); / (true)
150//
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700151// lower_bound(/) -> / (true) <-- excluded (equal)
152// lower_bound(/a) -> / (true) <-- excluded (any)
153// lower_bound(/b) -> /b (false) <--- excluded (equal)
154// lower_bound(/c) -> /b (false) <--- not excluded (not equal and no ANY)
155// lower_bound(/d) -> /d (true) <- excluded
156// lower_bound(/e) -> /d (true) <- excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800157bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700158Exclude::isExcluded(const name::Component& comp) const
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800159{
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700160 const_iterator lowerBound = m_exclude.lower_bound(comp);
161 if (lowerBound == end())
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800162 return false;
163
164 if (lowerBound->second)
165 return true;
166 else
167 return lowerBound->first == comp;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800168}
169
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700170Exclude&
171Exclude::excludeOne(const name::Component& comp)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800172{
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700173 if (!isExcluded(comp)) {
174 m_exclude.insert(std::make_pair(comp, false));
175 m_wire.reset();
176 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800177 return *this;
178}
179
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800180// example: ANY /b0 /d0 ANY /f0
181//
182// ordered in map as:
183//
184// /f0 (false); /d0 (true); /b0 (false); / (true)
185//
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700186// lower_bound(/) -> / (true) <-- excluded (equal)
187// lower_bound(/a0) -> / (true) <-- excluded (any)
188// lower_bound(/b0) -> /b0 (false) <--- excluded (equal)
189// lower_bound(/c0) -> /b0 (false) <--- not excluded (not equal and no ANY)
190// lower_bound(/d0) -> /d0 (true) <- excluded
191// lower_bound(/e0) -> /d0 (true) <- excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800192
193
194// examples with desired outcomes
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700195// excludeRange(/, /f0) -> ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800196// /f0 (false); / (true)
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700197// excludeRange(/, /f1) -> ANY /f1
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800198// /f1 (false); / (true)
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700199// excludeRange(/a0, /e0) -> ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800200// /f0 (false); / (true)
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700201// excludeRange(/a0, /e0) -> ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800202// /f0 (false); / (true)
203
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700204// excludeRange(/b1, /c0) -> ANY /b0 /b1 ANY /c0 /d0 ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800205// /f0 (false); /d0 (true); /c0 (false); /b1 (true); /b0 (false); / (true)
206
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700207Exclude&
208Exclude::excludeRange(const name::Component& from, const name::Component& to)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800209{
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700210 if (from >= to) {
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700211 throw Error("Invalid exclude range [" + from.toUri() + ", " + to.toUri() + "] "
212 "(for single name exclude use Exclude::excludeOne)");
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700213 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800214
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700215 iterator newFrom = m_exclude.lower_bound(from);
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700216 if (newFrom == end() || !newFrom->second /*without ANY*/) {
217 std::pair<iterator, bool> fromResult = m_exclude.insert(std::make_pair(from, true));
218 newFrom = fromResult.first;
219 if (!fromResult.second) {
220 // this means that the lower bound is equal to the item itself. So, just update ANY flag
221 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800222 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700223 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800224 // else
225 // nothing special if start of the range already exists with ANY flag set
226
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700227 iterator newTo = m_exclude.lower_bound(to); // !newTo cannot be end()
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700228 if (newTo == newFrom || !newTo->second) {
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700229 std::pair<iterator, bool> toResult = m_exclude.insert(std::make_pair(to, false));
230 newTo = toResult.first;
231 ++ newTo;
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700232 }
233 // else
234 // nothing to do really
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800235
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700236 m_exclude.erase(newTo, newFrom); // remove any intermediate node, since all of the are excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800237
Alexander Afanasyevba096052014-09-19 15:36:37 -0700238 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800239 return *this;
240}
241
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700242Exclude&
243Exclude::excludeAfter(const name::Component& from)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800244{
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700245 iterator newFrom = m_exclude.lower_bound(from);
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700246 if (newFrom == end() || !newFrom->second /*without ANY*/) {
247 std::pair<iterator, bool> fromResult = m_exclude.insert(std::make_pair(from, true));
248 newFrom = fromResult.first;
249 if (!fromResult.second) {
250 // this means that the lower bound is equal to the item itself. So, just update ANY flag
251 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800252 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700253 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800254 // else
255 // nothing special if start of the range already exists with ANY flag set
256
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700257 if (newFrom != m_exclude.begin()) {
258 // remove any intermediate node, since all of the are excluded
259 m_exclude.erase(m_exclude.begin(), newFrom);
260 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800261
Alexander Afanasyevba096052014-09-19 15:36:37 -0700262 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800263 return *this;
264}
265
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800266std::ostream&
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700267operator<<(std::ostream& os, const Exclude& exclude)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800268{
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700269 bool isFirst = true;
270 for (const auto& item : exclude | boost::adaptors::reversed) {
271 if (!item.first.empty() || !item.second) {
272 if (!isFirst)
273 os << ",";
274 os << item.first.toUri();
275 isFirst = false;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800276 }
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700277 if (item.second) {
278 if (!isFirst)
279 os << ",";
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700280 os << "*";
Alexander Afanasyevc076e6d2015-04-02 20:07:13 -0700281 isFirst = false;
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700282 }
283 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800284 return os;
285}
286
Alexander Afanasyevba096052014-09-19 15:36:37 -0700287std::string
288Exclude::toUri() const
289{
290 std::ostringstream os;
291 os << *this;
292 return os.str();
293}
294
295bool
296Exclude::operator==(const Exclude& other) const
297{
298 if (empty() && other.empty())
299 return true;
300 if (empty() || other.empty())
301 return false;
302
303 return wireEncode() == other.wireEncode();
304}
305
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700306} // namespace ndn