blob: 8e44e1a53cc89e4ec4575bbedb0743a66dbfeef9 [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 Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 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 Afanasyevb3a6af42014-01-03 13:08:28 -080025
Junxiao Shi7284a402014-09-12 13:42:16 -070026#include <boost/static_assert.hpp>
Alexander Afanasyevba096052014-09-19 15:36:37 -070027#include <boost/type_traits.hpp>
Junxiao Shi7284a402014-09-12 13:42:16 -070028
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -070029namespace ndn {
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -080030
Junxiao Shi7284a402014-09-12 13:42:16 -070031BOOST_STATIC_ASSERT((boost::is_base_of<tlv::Error, Exclude::Error>::value));
32
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -070033Exclude::Exclude()
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -080034{
35}
36
Junxiao Shi75203022014-09-11 10:01:50 -070037Exclude::Exclude(const Block& wire)
38{
39 wireDecode(wire);
40}
41
42template<bool T>
43size_t
44Exclude::wireEncode(EncodingImpl<T>& block) const
45{
Junxiao Shi7284a402014-09-12 13:42:16 -070046 if (m_exclude.empty()) {
47 throw Error("Exclude filter cannot be empty");
48 }
49
Junxiao Shi75203022014-09-11 10:01:50 -070050 size_t totalLength = 0;
51
52 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
53 // Any ::= ANY-TYPE TLV-LENGTH(=0)
54
55 for (Exclude::const_iterator i = m_exclude.begin(); i != m_exclude.end(); i++)
56 {
57 if (i->second)
58 {
59 totalLength += prependBooleanBlock(block, tlv::Any);
60 }
61 if (!i->first.empty())
62 {
63 totalLength += i->first.wireEncode(block);
64 }
65 }
66
67 totalLength += block.prependVarNumber(totalLength);
68 totalLength += block.prependVarNumber(tlv::Exclude);
69 return totalLength;
70}
71
72template size_t
73Exclude::wireEncode<true>(EncodingImpl<true>& block) const;
74
75template size_t
76Exclude::wireEncode<false>(EncodingImpl<false>& block) const;
77
78const Block&
79Exclude::wireEncode() const
80{
81 if (m_wire.hasWire())
82 return m_wire;
83
84 EncodingEstimator estimator;
85 size_t estimatedSize = wireEncode(estimator);
86
87 EncodingBuffer buffer(estimatedSize, 0);
88 wireEncode(buffer);
89
90 m_wire = buffer.block();
91 return m_wire;
92}
93
94void
95Exclude::wireDecode(const Block& wire)
96{
Alexander Afanasyevba096052014-09-19 15:36:37 -070097 clear();
98
Junxiao Shi7284a402014-09-12 13:42:16 -070099 if (wire.type() != tlv::Exclude)
100 throw tlv::Error("Unexpected TLV type when decoding Exclude");
101
Junxiao Shi75203022014-09-11 10:01:50 -0700102 m_wire = wire;
103 m_wire.parse();
104
Junxiao Shi7284a402014-09-12 13:42:16 -0700105 if (m_wire.elements_size() == 0) {
106 throw Error("Exclude element cannot be empty");
107 }
108
Junxiao Shi75203022014-09-11 10:01:50 -0700109 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
110 // Any ::= ANY-TYPE TLV-LENGTH(=0)
111
112 Block::element_const_iterator i = m_wire.elements_begin();
113 if (i->type() == tlv::Any)
114 {
115 appendExclude(name::Component(), true);
116 ++i;
117 }
118
119 while (i != m_wire.elements_end())
120 {
121 if (i->type() != tlv::NameComponent)
122 throw Error("Incorrect format of Exclude filter");
123
124 name::Component excludedComponent(i->value(), i->value_size());
125 ++i;
126
127 if (i != m_wire.elements_end())
128 {
129 if (i->type() == tlv::Any)
130 {
131 appendExclude(excludedComponent, true);
132 ++i;
133 }
134 else
135 {
136 appendExclude(excludedComponent, false);
137 }
138 }
139 else
140 {
141 appendExclude(excludedComponent, false);
142 }
143 }
144}
145
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800146// example: ANY /b /d ANY /f
147//
148// ordered in map as:
149//
150// /f (false); /d (true); /b (false); / (true)
151//
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700152// lower_bound(/) -> / (true) <-- excluded (equal)
153// lower_bound(/a) -> / (true) <-- excluded (any)
154// lower_bound(/b) -> /b (false) <--- excluded (equal)
155// lower_bound(/c) -> /b (false) <--- not excluded (not equal and no ANY)
156// lower_bound(/d) -> /d (true) <- excluded
157// lower_bound(/e) -> /d (true) <- excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800158bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700159Exclude::isExcluded(const name::Component& comp) const
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800160{
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700161 const_iterator lowerBound = m_exclude.lower_bound(comp);
162 if (lowerBound == end())
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800163 return false;
164
165 if (lowerBound->second)
166 return true;
167 else
168 return lowerBound->first == comp;
169
170 return false;
171}
172
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700173Exclude&
174Exclude::excludeOne(const name::Component& comp)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800175{
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700176 if (!isExcluded(comp))
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800177 {
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700178 m_exclude.insert(std::make_pair(comp, false));
Alexander Afanasyevba096052014-09-19 15:36:37 -0700179 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800180 }
181 return *this;
182}
183
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800184// example: ANY /b0 /d0 ANY /f0
185//
186// ordered in map as:
187//
188// /f0 (false); /d0 (true); /b0 (false); / (true)
189//
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700190// lower_bound(/) -> / (true) <-- excluded (equal)
191// lower_bound(/a0) -> / (true) <-- excluded (any)
192// lower_bound(/b0) -> /b0 (false) <--- excluded (equal)
193// lower_bound(/c0) -> /b0 (false) <--- not excluded (not equal and no ANY)
194// lower_bound(/d0) -> /d0 (true) <- excluded
195// lower_bound(/e0) -> /d0 (true) <- excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800196
197
198// examples with desired outcomes
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700199// excludeRange(/, /f0) -> ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800200// /f0 (false); / (true)
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700201// excludeRange(/, /f1) -> ANY /f1
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800202// /f1 (false); / (true)
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700203// excludeRange(/a0, /e0) -> ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800204// /f0 (false); / (true)
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700205// excludeRange(/a0, /e0) -> ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800206// /f0 (false); / (true)
207
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700208// excludeRange(/b1, /c0) -> ANY /b0 /b1 ANY /c0 /d0 ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800209// /f0 (false); /d0 (true); /c0 (false); /b1 (true); /b0 (false); / (true)
210
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700211Exclude&
212Exclude::excludeRange(const name::Component& from, const name::Component& to)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800213{
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700214 if (from >= to) {
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700215 throw Error("Invalid exclude range [" + from.toUri() + ", " + to.toUri() + "] "
216 "(for single name exclude use Exclude::excludeOne)");
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700217 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800218
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700219 iterator newFrom = m_exclude.lower_bound(from);
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700220 if (newFrom == end() || !newFrom->second /*without ANY*/) {
221 std::pair<iterator, bool> fromResult = m_exclude.insert(std::make_pair(from, true));
222 newFrom = fromResult.first;
223 if (!fromResult.second) {
224 // this means that the lower bound is equal to the item itself. So, just update ANY flag
225 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800226 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700227 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800228 // else
229 // nothing special if start of the range already exists with ANY flag set
230
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700231 iterator newTo = m_exclude.lower_bound(to); // !newTo cannot be end()
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700232 if (newTo == newFrom || !newTo->second) {
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700233 std::pair<iterator, bool> toResult = m_exclude.insert(std::make_pair(to, false));
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800234 newTo = toResult.first;
235 ++ newTo;
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700236 }
237 // else
238 // nothing to do really
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800239
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700240 m_exclude.erase(newTo, newFrom); // remove any intermediate node, since all of the are excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800241
Alexander Afanasyevba096052014-09-19 15:36:37 -0700242 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800243 return *this;
244}
245
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700246Exclude&
247Exclude::excludeAfter(const name::Component& from)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800248{
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700249 iterator newFrom = m_exclude.lower_bound(from);
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700250 if (newFrom == end() || !newFrom->second /*without ANY*/) {
251 std::pair<iterator, bool> fromResult = m_exclude.insert(std::make_pair(from, true));
252 newFrom = fromResult.first;
253 if (!fromResult.second) {
254 // this means that the lower bound is equal to the item itself. So, just update ANY flag
255 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800256 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700257 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800258 // else
259 // nothing special if start of the range already exists with ANY flag set
260
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700261 if (newFrom != m_exclude.begin()) {
262 // remove any intermediate node, since all of the are excluded
263 m_exclude.erase(m_exclude.begin(), newFrom);
264 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800265
Alexander Afanasyevba096052014-09-19 15:36:37 -0700266 m_wire.reset();
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800267 return *this;
268}
269
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800270std::ostream&
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700271operator<<(std::ostream& os, const Exclude& exclude)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800272{
273 bool empty = true;
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700274 for (Exclude::const_reverse_iterator i = exclude.rbegin(); i != exclude.rend(); i++) {
275 if (!i->first.empty()) {
276 if (!empty) os << ",";
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700277 os << i->first.toUri();
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700278 empty = false;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800279 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700280 if (i->second) {
281 if (!empty) os << ",";
282 os << "*";
283 empty = false;
284 }
285 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800286 return os;
287}
288
Alexander Afanasyevba096052014-09-19 15:36:37 -0700289std::string
290Exclude::toUri() const
291{
292 std::ostringstream os;
293 os << *this;
294 return os.str();
295}
296
297bool
298Exclude::operator==(const Exclude& other) const
299{
300 if (empty() && other.empty())
301 return true;
302 if (empty() || other.empty())
303 return false;
304
305 return wireEncode() == other.wireEncode();
306}
307
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700308} // namespace ndn