blob: 7f069eb1a0a3e02925bce62ac9582c0ec6bec151 [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 Afanasyeve2dcdfd2014-02-07 15:53:28 -080024#include "common.hpp"
25
Alexander Afanasyev09c613f2014-01-29 00:23:58 -080026#include "exclude.hpp"
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -080027
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -070028namespace ndn {
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -080029
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -070030Exclude::Exclude()
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -080031{
32}
33
Junxiao Shi75203022014-09-11 10:01:50 -070034Exclude::Exclude(const Block& wire)
35{
36 wireDecode(wire);
37}
38
39template<bool T>
40size_t
41Exclude::wireEncode(EncodingImpl<T>& block) const
42{
43 size_t totalLength = 0;
44
45 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
46 // Any ::= ANY-TYPE TLV-LENGTH(=0)
47
48 for (Exclude::const_iterator i = m_exclude.begin(); i != m_exclude.end(); i++)
49 {
50 if (i->second)
51 {
52 totalLength += prependBooleanBlock(block, tlv::Any);
53 }
54 if (!i->first.empty())
55 {
56 totalLength += i->first.wireEncode(block);
57 }
58 }
59
60 totalLength += block.prependVarNumber(totalLength);
61 totalLength += block.prependVarNumber(tlv::Exclude);
62 return totalLength;
63}
64
65template size_t
66Exclude::wireEncode<true>(EncodingImpl<true>& block) const;
67
68template size_t
69Exclude::wireEncode<false>(EncodingImpl<false>& block) const;
70
71const Block&
72Exclude::wireEncode() const
73{
74 if (m_wire.hasWire())
75 return m_wire;
76
77 EncodingEstimator estimator;
78 size_t estimatedSize = wireEncode(estimator);
79
80 EncodingBuffer buffer(estimatedSize, 0);
81 wireEncode(buffer);
82
83 m_wire = buffer.block();
84 return m_wire;
85}
86
87void
88Exclude::wireDecode(const Block& wire)
89{
90 m_wire = wire;
91 m_wire.parse();
92
93 // Exclude ::= EXCLUDE-TYPE TLV-LENGTH Any? (NameComponent (Any)?)+
94 // Any ::= ANY-TYPE TLV-LENGTH(=0)
95
96 Block::element_const_iterator i = m_wire.elements_begin();
97 if (i->type() == tlv::Any)
98 {
99 appendExclude(name::Component(), true);
100 ++i;
101 }
102
103 while (i != m_wire.elements_end())
104 {
105 if (i->type() != tlv::NameComponent)
106 throw Error("Incorrect format of Exclude filter");
107
108 name::Component excludedComponent(i->value(), i->value_size());
109 ++i;
110
111 if (i != m_wire.elements_end())
112 {
113 if (i->type() == tlv::Any)
114 {
115 appendExclude(excludedComponent, true);
116 ++i;
117 }
118 else
119 {
120 appendExclude(excludedComponent, false);
121 }
122 }
123 else
124 {
125 appendExclude(excludedComponent, false);
126 }
127 }
128}
129
130
131
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800132// example: ANY /b /d ANY /f
133//
134// ordered in map as:
135//
136// /f (false); /d (true); /b (false); / (true)
137//
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700138// lower_bound(/) -> / (true) <-- excluded (equal)
139// lower_bound(/a) -> / (true) <-- excluded (any)
140// lower_bound(/b) -> /b (false) <--- excluded (equal)
141// lower_bound(/c) -> /b (false) <--- not excluded (not equal and no ANY)
142// lower_bound(/d) -> /d (true) <- excluded
143// lower_bound(/e) -> /d (true) <- excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800144bool
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700145Exclude::isExcluded(const name::Component& comp) const
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800146{
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700147 const_iterator lowerBound = m_exclude.lower_bound(comp);
148 if (lowerBound == end())
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800149 return false;
150
151 if (lowerBound->second)
152 return true;
153 else
154 return lowerBound->first == comp;
155
156 return false;
157}
158
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700159Exclude&
160Exclude::excludeOne(const name::Component& comp)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800161{
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700162 if (!isExcluded(comp))
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800163 {
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700164 m_exclude.insert(std::make_pair(comp, false));
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800165 }
166 return *this;
167}
168
169
170// example: ANY /b0 /d0 ANY /f0
171//
172// ordered in map as:
173//
174// /f0 (false); /d0 (true); /b0 (false); / (true)
175//
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700176// lower_bound(/) -> / (true) <-- excluded (equal)
177// lower_bound(/a0) -> / (true) <-- excluded (any)
178// lower_bound(/b0) -> /b0 (false) <--- excluded (equal)
179// lower_bound(/c0) -> /b0 (false) <--- not excluded (not equal and no ANY)
180// lower_bound(/d0) -> /d0 (true) <- excluded
181// lower_bound(/e0) -> /d0 (true) <- excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800182
183
184// examples with desired outcomes
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700185// excludeRange(/, /f0) -> ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800186// /f0 (false); / (true)
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700187// excludeRange(/, /f1) -> ANY /f1
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800188// /f1 (false); / (true)
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700189// excludeRange(/a0, /e0) -> ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800190// /f0 (false); / (true)
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700191// excludeRange(/a0, /e0) -> ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800192// /f0 (false); / (true)
193
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700194// excludeRange(/b1, /c0) -> ANY /b0 /b1 ANY /c0 /d0 ANY /f0
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800195// /f0 (false); /d0 (true); /c0 (false); /b1 (true); /b0 (false); / (true)
196
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700197Exclude&
198Exclude::excludeRange(const name::Component& from, const name::Component& to)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800199{
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700200 if (from >= to) {
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700201 throw Error("Invalid exclude range [" + from.toUri() + ", " + to.toUri() + "] "
202 "(for single name exclude use Exclude::excludeOne)");
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700203 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800204
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700205 iterator newFrom = m_exclude.lower_bound(from);
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700206 if (newFrom == end() || !newFrom->second /*without ANY*/) {
207 std::pair<iterator, bool> fromResult = m_exclude.insert(std::make_pair(from, true));
208 newFrom = fromResult.first;
209 if (!fromResult.second) {
210 // this means that the lower bound is equal to the item itself. So, just update ANY flag
211 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800212 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700213 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800214 // else
215 // nothing special if start of the range already exists with ANY flag set
216
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700217 iterator newTo = m_exclude.lower_bound(to); // !newTo cannot be end()
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700218 if (newTo == newFrom || !newTo->second) {
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700219 std::pair<iterator, bool> toResult = m_exclude.insert(std::make_pair(to, false));
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800220 newTo = toResult.first;
221 ++ newTo;
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700222 }
223 // else
224 // nothing to do really
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800225
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700226 m_exclude.erase(newTo, newFrom); // remove any intermediate node, since all of the are excluded
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800227
228 return *this;
229}
230
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700231Exclude&
232Exclude::excludeAfter(const name::Component& from)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800233{
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700234 iterator newFrom = m_exclude.lower_bound(from);
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700235 if (newFrom == end() || !newFrom->second /*without ANY*/) {
236 std::pair<iterator, bool> fromResult = m_exclude.insert(std::make_pair(from, true));
237 newFrom = fromResult.first;
238 if (!fromResult.second) {
239 // this means that the lower bound is equal to the item itself. So, just update ANY flag
240 newFrom->second = true;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800241 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700242 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800243 // else
244 // nothing special if start of the range already exists with ANY flag set
245
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700246 if (newFrom != m_exclude.begin()) {
247 // remove any intermediate node, since all of the are excluded
248 m_exclude.erase(m_exclude.begin(), newFrom);
249 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800250
251 return *this;
252}
253
254
255std::ostream&
Alexander Afanasyevff2d08f2014-04-07 18:28:25 -0700256operator<<(std::ostream& os, const Exclude& exclude)
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800257{
258 bool empty = true;
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700259 for (Exclude::const_reverse_iterator i = exclude.rbegin(); i != exclude.rend(); i++) {
260 if (!i->first.empty()) {
261 if (!empty) os << ",";
Alexander Afanasyev9c578182014-05-14 17:28:28 -0700262 os << i->first.toUri();
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700263 empty = false;
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800264 }
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700265 if (i->second) {
266 if (!empty) os << ",";
267 os << "*";
268 empty = false;
269 }
270 }
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800271 return os;
272}
273
Alexander Afanasyevb3a6af42014-01-03 13:08:28 -0800274
Alexander Afanasyev3aeeaeb2014-04-22 23:34:23 -0700275} // namespace ndn