blob: a5cf58a5c0cdefd781e568c8c71dfcdfeddb9269 [file] [log] [blame]
Junxiao Shi688a6412017-06-22 10:12:07 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shibb8d4a32017-07-13 02:40:09 +00002/*
Junxiao Shi688a6412017-06-22 10:12:07 +00003 * Copyright (c) 2013-2017 Regents of the University of California.
4 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * 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.
20 */
21
22#ifndef NDN_DELEGATION_LIST_HPP
23#define NDN_DELEGATION_LIST_HPP
24
25#include "delegation.hpp"
Junxiao Shid21abd32017-06-30 02:56:40 +000026#include <initializer_list>
Junxiao Shi688a6412017-06-22 10:12:07 +000027
28namespace ndn {
29
30/** \brief represents a list of Delegations
31 * \sa https://named-data.net/doc/ndn-tlv/link.html
32 *
33 * Delegations are stored in an std::vector, under the assumption that there is usually only a
34 * small number of Delegations, so that copying is acceptable when they are modified.
35 */
36class DelegationList
37{
38public:
39 class Error : public tlv::Error
40 {
41 public:
42 explicit
43 Error(const std::string& what);
44
45 Error(const std::string& what, const std::exception& innerException);
46 };
47
48 /** \brief construct an empty DelegationList
49 */
50 DelegationList();
51
Junxiao Shid21abd32017-06-30 02:56:40 +000052 /** \brief construct a sorted DelegationList with specified delegations
53 *
54 * This is equivalent to inserting each delegation into an empty DelegationList with INS_REPLACE
55 * conflict resolution.
56 */
57 DelegationList(std::initializer_list<Delegation> dels);
58
Junxiao Shi688a6412017-06-22 10:12:07 +000059 /** \brief decode a DelegationList
60 * \sa wireDecode
61 */
62 explicit
63 DelegationList(const Block& block, bool wantSort = true);
64
65 /** \brief encode into wire format
66 * \param encoder either an EncodingBuffer or an EncodingEstimator
Junxiao Shi7d3c14b2017-08-05 16:34:39 +000067 * \param type TLV-TYPE number, either Content (for \p Link) or ForwardingHint
Junxiao Shi688a6412017-06-22 10:12:07 +000068 * \throw std::invalid_argument \p type is invalid
69 * \throw Error there is no Delegation
70 */
71 template<encoding::Tag TAG>
72 size_t
73 wireEncode(EncodingImpl<TAG>& encoder, uint32_t type = tlv::ForwardingHint) const;
74
75 /** \brief decode a DelegationList
76 * \param block either a Content block (from \p Link) or a ForwardingHint block
77 * \param wantSort if true, delegations are sorted
78 * \throw Error the block cannot be parsed as a list of Delegations
79 */
80 void
81 wireDecode(const Block& block, bool wantSort = true);
82
83 bool
Junxiao Shibb8d4a32017-07-13 02:40:09 +000084 isSorted() const noexcept
Junxiao Shi688a6412017-06-22 10:12:07 +000085 {
86 return m_isSorted;
87 }
88
89 using const_iterator = std::vector<Delegation>::const_iterator;
90
91 const_iterator
Junxiao Shibb8d4a32017-07-13 02:40:09 +000092 begin() const noexcept
Junxiao Shi688a6412017-06-22 10:12:07 +000093 {
94 return m_dels.begin();
95 }
96
97 const_iterator
Junxiao Shibb8d4a32017-07-13 02:40:09 +000098 end() const noexcept
Junxiao Shi688a6412017-06-22 10:12:07 +000099 {
100 return m_dels.end();
101 }
102
Junxiao Shibb8d4a32017-07-13 02:40:09 +0000103 bool
104 empty() const noexcept
105 {
106 return m_dels.empty();
107 }
108
Junxiao Shi688a6412017-06-22 10:12:07 +0000109 size_t
Junxiao Shibb8d4a32017-07-13 02:40:09 +0000110 size() const noexcept
Junxiao Shi688a6412017-06-22 10:12:07 +0000111 {
112 return m_dels.size();
113 }
114
115 /** \brief get the i-th delegation
116 * \pre i < size()
117 */
118 const Delegation&
119 operator[](size_t i) const
120 {
121 BOOST_ASSERT(i < size());
122 return m_dels[i];
123 }
124
125 /** \brief get the i-th delegation
126 * \throw std::out_of_range i >= size()
127 */
128 const Delegation&
129 at(size_t i) const
130 {
131 return m_dels.at(i);
132 }
133
134public: // modifiers
135 /** \brief sort the delegation list
136 * \post isSorted() == true
137 * \post Delegations are sorted in increasing preference order.
138 *
139 * A DelegationList can be constructed as sorted or unsorted. In most cases, it is recommended
140 * to use a sorted DelegationList. An unsorted DelegationList is useful for extracting the i-th
141 * delegation from a received ForwardingHint or Link object.
142 *
143 * This method turns an unsorted DelegationList into a sorted DelegationList.
144 * If access to unsorted DelegationList is not needed, it is more efficient to sort the
145 * DelegationList in wireDecode.
146 */
147 void
148 sort();
149
150 /** \brief what to do when inserting a duplicate name
151 */
152 enum InsertConflictResolution {
153 /** \brief existing delegation(s) with the same name are replaced with the new delegation
154 */
155 INS_REPLACE,
156
157 /** \brief multiple delegations with the same name are kept in the DelegationList
158 * \note This is NOT RECOMMENDED by Link specification.
159 */
160 INS_APPEND,
161
162 /** \brief new delegation is not inserted if an existing delegation has the same name
163 */
164 INS_SKIP
165 };
166
167 /** \brief insert Delegation
168 * \return whether inserted
169 */
170 bool
171 insert(uint64_t preference, const Name& name,
172 InsertConflictResolution onConflict = INS_REPLACE);
173
174 /** \brief insert Delegation
175 * \return whether inserted
176 */
177 bool
178 insert(const Delegation& del, InsertConflictResolution onConflict = INS_REPLACE)
179 {
180 return this->insert(del.preference, del.name, onConflict);
181 }
182
183 /** \brief delete Delegation(s) with specified preference and name
184 * \return count of erased Delegation(s)
185 */
186 size_t
187 erase(uint64_t preference, const Name& name)
188 {
189 return this->eraseImpl(preference, name);
190 }
191
192 /** \brief delete Delegation(s) with matching preference and name
193 * \return count of erased Delegation(s)
194 */
195 size_t
196 erase(const Delegation& del)
197 {
198 return this->eraseImpl(del.preference, del.name);
199 }
200
201 /** \brief erase Delegation(s) with specified name
202 * \return count of erased Delegation(s)
203 */
204 size_t
205 erase(const Name& name)
206 {
207 return this->eraseImpl(nullopt, name);
208 }
209
210private:
211 static bool
212 isValidTlvType(uint32_t type);
213
214 void
215 insertImpl(uint64_t preference, const Name& name);
216
217 size_t
218 eraseImpl(optional<uint64_t> preference, const Name& name);
219
220private:
221 bool m_isSorted;
222
223 /** \brief delegation container; its contents are sorted when \p m_isSorted is true
224 * \note This container is a member field rather than a base class, in order to ensure contents
225 * are sorted when \p m_isSorted is true.
226 * \note A vector is chosen instead of a std::set, so that the container can be unsorted when
227 * \p m_isSorted is false. This container is expected to have less than seven items, and
228 * therefore the overhead of moving items during insertion and deletion is small.
229 */
230 std::vector<Delegation> m_dels;
231
232 friend bool operator==(const DelegationList&, const DelegationList&);
233};
234
Davide Pesavento88a0d812017-08-19 21:31:42 -0400235#ifndef DOXYGEN
236extern template size_t
237DelegationList::wireEncode<encoding::EncoderTag>(EncodingBuffer&, uint32_t) const;
238
239extern template size_t
240DelegationList::wireEncode<encoding::EstimatorTag>(EncodingEstimator&, uint32_t) const;
241#endif
242
Junxiao Shi688a6412017-06-22 10:12:07 +0000243/** \brief compare whether two DelegationLists are equal
244 * \note Order matters! If two DelegationLists contain the same Delegations but at least one is
245 * unsorted, they may compare unequal if the Delegations appear in different order.
246 */
247bool
248operator==(const DelegationList& lhs, const DelegationList& rhs);
249
250inline bool
251operator!=(const DelegationList& lhs, const DelegationList& rhs)
252{
253 return !(lhs == rhs);
254}
255
256std::ostream&
257operator<<(std::ostream& os, const DelegationList& dl);
258
259} // namespace ndn
260
261#endif // NDN_DELEGATION_LIST_HPP