blob: 1aba8b1ee1da07c71d33a5f8a9bb38b638aaa10f [file] [log] [blame]
Eric Newberry261dbc22015-07-22 23:18:18 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shib6e276f2017-08-14 20:10:04 +00002/*
Davide Pesavento570b20d2018-07-15 21:53:14 -04003 * Copyright (c) 2013-2018 Regents of the University of California.
Eric Newberry261dbc22015-07-22 23:18:18 -07004 *
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_CXX_LP_PACKET_HPP
23#define NDN_CXX_LP_PACKET_HPP
24
25#include "fields.hpp"
26
27namespace ndn {
28namespace lp {
29
30class Packet
31{
32public:
33 class Error : public ndn::tlv::Error
34 {
35 public:
36 explicit
37 Error(const std::string& what)
38 : ndn::tlv::Error(what)
39 {
40 }
41 };
42
43 Packet();
44
45 explicit
46 Packet(const Block& wire);
47
48 /**
Eric Newberry261dbc22015-07-22 23:18:18 -070049 * \brief encode packet into wire format
50 */
Eric Newberry82838be2015-11-07 13:00:35 -070051 Block
Eric Newberry261dbc22015-07-22 23:18:18 -070052 wireEncode() const;
53
54 /**
55 * \brief decode packet from wire format
Eric Newberry43bf6bb2015-10-09 16:12:09 -070056 * \throws Error unknown TLV-TYPE
Eric Newberry261dbc22015-07-22 23:18:18 -070057 */
58 void
59 wireDecode(const Block& wire);
60
Junxiao Shib6e276f2017-08-14 20:10:04 +000061 /**
62 * \retval true packet has no field
63 * \retval false packet has one or more fields
64 */
65 bool
66 empty() const
67 {
68 return m_wire.elements_size() == 0;
69 }
70
Eric Newberry261dbc22015-07-22 23:18:18 -070071public: // field access
72 /**
73 * \return true if FIELD occurs one or more times
Davide Pesavento18cf81b2015-09-12 23:36:43 +020074 * \details This is equivalent to count() > 0
Eric Newberry261dbc22015-07-22 23:18:18 -070075 */
76 template<typename FIELD>
77 bool
78 has() const
79 {
80 return count<FIELD>() > 0;
81 }
82
83 /**
84 * \return number of occurrences of FIELD
85 */
86 template<typename FIELD>
87 size_t
88 count() const
89 {
Eric Newberry261dbc22015-07-22 23:18:18 -070090 return std::count_if(m_wire.elements_begin(), m_wire.elements_end(),
91 [] (const Block& block) {
92 return block.type() == FIELD::TlvType::value; });
93 }
94
95 /**
96 * \return value of index-th occurrence of FIELD
97 * \throw std::out_of_range if index>=count()
98 */
99 template<typename FIELD>
100 typename FIELD::ValueType
101 get(size_t index = 0) const
102 {
Eric Newberry261dbc22015-07-22 23:18:18 -0700103 size_t count = 0;
104 for (const Block& element : m_wire.elements()) {
105 if (element.type() != FIELD::TlvType::value) {
106 continue;
107 }
108 if (count++ == index) {
109 return FIELD::decode(element);
110 }
111 }
112
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700113 BOOST_THROW_EXCEPTION(std::out_of_range("Index out of range"));
Eric Newberry261dbc22015-07-22 23:18:18 -0700114 }
115
116 /**
117 * \return values of all occurrences of FIELD
118 */
119 template<typename FIELD>
120 std::vector<typename FIELD::ValueType>
121 list() const
122 {
123 std::vector<typename FIELD::ValueType> output;
124
Eric Newberry261dbc22015-07-22 23:18:18 -0700125 for (const Block& element : m_wire.elements()) {
126 if (element.type() != FIELD::TlvType::value) {
127 continue;
128 }
129 output.push_back(FIELD::decode(element));
130 }
131
132 return output;
133 }
134
135 /**
136 * \brief remove all occurrences of FIELD, and add a FIELD with value
Davide Pesavento18cf81b2015-09-12 23:36:43 +0200137 * \details This equivalent to clear() followed by add(value)
Eric Newberry261dbc22015-07-22 23:18:18 -0700138 */
139 template<typename FIELD>
140 Packet&
141 set(const typename FIELD::ValueType& value)
142 {
143 clear<FIELD>();
144 return add<FIELD>(value);
145 }
146
147 /**
148 * \brief add a FIELD with value
149 * \throw std::length_error if field already exists and is not repeatable
150 */
151 template<typename FIELD>
152 Packet&
153 add(const typename FIELD::ValueType& value)
154 {
155 if (!FIELD::IsRepeatable::value && has<FIELD>()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700156 BOOST_THROW_EXCEPTION(std::length_error("Field cannot be repeated"));
Eric Newberry261dbc22015-07-22 23:18:18 -0700157 }
158
159 EncodingEstimator estimator;
160 size_t estimatedSize = FIELD::encode(estimator, value);
161 EncodingBuffer buffer(estimatedSize, 0);
162 FIELD::encode(buffer, value);
163 Block block = buffer.block();
164
Eric Newberry8422f572017-02-04 21:53:58 -0700165 auto pos = std::upper_bound(m_wire.elements_begin(), m_wire.elements_end(),
166 FIELD::TlvType::value, comparePos);
Eric Newberry261dbc22015-07-22 23:18:18 -0700167 m_wire.insert(pos, block);
168
169 return *this;
170 }
171
172 /**
173 * \brief remove the index-th occurrence of FIELD
174 * \throw std::out_of_range if index>=count()
175 */
176 template<typename FIELD>
177 Packet&
178 remove(size_t index = 0)
179 {
Eric Newberry261dbc22015-07-22 23:18:18 -0700180 size_t count = 0;
Eric Newberry2a890772017-06-26 12:06:15 -0700181 for (auto it = m_wire.elements_begin(); it != m_wire.elements_end(); ++it) {
Eric Newberry261dbc22015-07-22 23:18:18 -0700182 if (it->type() == FIELD::TlvType::value) {
183 if (count == index) {
184 m_wire.erase(it);
185 return *this;
186 }
187 count++;
188 }
189 }
190
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700191 BOOST_THROW_EXCEPTION(std::out_of_range("Index out of range"));
Eric Newberry261dbc22015-07-22 23:18:18 -0700192 }
193
194 /**
195 * \brief remove all occurrences of FIELD
196 */
197 template<typename FIELD>
198 Packet&
199 clear()
200 {
Eric Newberry261dbc22015-07-22 23:18:18 -0700201 m_wire.remove(FIELD::TlvType::value);
202 return *this;
203 }
204
205private:
206 static bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400207 comparePos(uint64_t first, const Block& second) noexcept;
Eric Newberry261dbc22015-07-22 23:18:18 -0700208
209private:
210 mutable Block m_wire;
211};
212
213} // namespace lp
214} // namespace ndn
215
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700216#endif // NDN_CXX_LP_PACKET_HPP