blob: 872af589c14b7a8f657554ac144add9349b71503 [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:
Junxiao Shi68b53852018-07-25 13:56:38 -060036 using ndn::tlv::Error::Error;
Eric Newberry261dbc22015-07-22 23:18:18 -070037 };
38
39 Packet();
40
41 explicit
42 Packet(const Block& wire);
43
44 /**
Eric Newberry261dbc22015-07-22 23:18:18 -070045 * \brief encode packet into wire format
46 */
Eric Newberry82838be2015-11-07 13:00:35 -070047 Block
Eric Newberry261dbc22015-07-22 23:18:18 -070048 wireEncode() const;
49
50 /**
51 * \brief decode packet from wire format
Eric Newberry43bf6bb2015-10-09 16:12:09 -070052 * \throws Error unknown TLV-TYPE
Eric Newberry261dbc22015-07-22 23:18:18 -070053 */
54 void
55 wireDecode(const Block& wire);
56
Junxiao Shib6e276f2017-08-14 20:10:04 +000057 /**
58 * \retval true packet has no field
59 * \retval false packet has one or more fields
60 */
61 bool
62 empty() const
63 {
64 return m_wire.elements_size() == 0;
65 }
66
Eric Newberry261dbc22015-07-22 23:18:18 -070067public: // field access
68 /**
69 * \return true if FIELD occurs one or more times
Davide Pesavento18cf81b2015-09-12 23:36:43 +020070 * \details This is equivalent to count() > 0
Eric Newberry261dbc22015-07-22 23:18:18 -070071 */
72 template<typename FIELD>
73 bool
74 has() const
75 {
76 return count<FIELD>() > 0;
77 }
78
79 /**
80 * \return number of occurrences of FIELD
81 */
82 template<typename FIELD>
83 size_t
84 count() const
85 {
Eric Newberry261dbc22015-07-22 23:18:18 -070086 return std::count_if(m_wire.elements_begin(), m_wire.elements_end(),
87 [] (const Block& block) {
88 return block.type() == FIELD::TlvType::value; });
89 }
90
91 /**
92 * \return value of index-th occurrence of FIELD
93 * \throw std::out_of_range if index>=count()
94 */
95 template<typename FIELD>
96 typename FIELD::ValueType
97 get(size_t index = 0) const
98 {
Eric Newberry261dbc22015-07-22 23:18:18 -070099 size_t count = 0;
100 for (const Block& element : m_wire.elements()) {
101 if (element.type() != FIELD::TlvType::value) {
102 continue;
103 }
104 if (count++ == index) {
105 return FIELD::decode(element);
106 }
107 }
108
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700109 BOOST_THROW_EXCEPTION(std::out_of_range("Index out of range"));
Eric Newberry261dbc22015-07-22 23:18:18 -0700110 }
111
112 /**
113 * \return values of all occurrences of FIELD
114 */
115 template<typename FIELD>
116 std::vector<typename FIELD::ValueType>
117 list() const
118 {
119 std::vector<typename FIELD::ValueType> output;
120
Eric Newberry261dbc22015-07-22 23:18:18 -0700121 for (const Block& element : m_wire.elements()) {
122 if (element.type() != FIELD::TlvType::value) {
123 continue;
124 }
125 output.push_back(FIELD::decode(element));
126 }
127
128 return output;
129 }
130
131 /**
132 * \brief remove all occurrences of FIELD, and add a FIELD with value
Davide Pesavento18cf81b2015-09-12 23:36:43 +0200133 * \details This equivalent to clear() followed by add(value)
Eric Newberry261dbc22015-07-22 23:18:18 -0700134 */
135 template<typename FIELD>
136 Packet&
137 set(const typename FIELD::ValueType& value)
138 {
139 clear<FIELD>();
140 return add<FIELD>(value);
141 }
142
143 /**
144 * \brief add a FIELD with value
145 * \throw std::length_error if field already exists and is not repeatable
146 */
147 template<typename FIELD>
148 Packet&
149 add(const typename FIELD::ValueType& value)
150 {
151 if (!FIELD::IsRepeatable::value && has<FIELD>()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700152 BOOST_THROW_EXCEPTION(std::length_error("Field cannot be repeated"));
Eric Newberry261dbc22015-07-22 23:18:18 -0700153 }
154
155 EncodingEstimator estimator;
156 size_t estimatedSize = FIELD::encode(estimator, value);
157 EncodingBuffer buffer(estimatedSize, 0);
158 FIELD::encode(buffer, value);
159 Block block = buffer.block();
160
Eric Newberry8422f572017-02-04 21:53:58 -0700161 auto pos = std::upper_bound(m_wire.elements_begin(), m_wire.elements_end(),
162 FIELD::TlvType::value, comparePos);
Eric Newberry261dbc22015-07-22 23:18:18 -0700163 m_wire.insert(pos, block);
164
165 return *this;
166 }
167
168 /**
169 * \brief remove the index-th occurrence of FIELD
170 * \throw std::out_of_range if index>=count()
171 */
172 template<typename FIELD>
173 Packet&
174 remove(size_t index = 0)
175 {
Eric Newberry261dbc22015-07-22 23:18:18 -0700176 size_t count = 0;
Eric Newberry2a890772017-06-26 12:06:15 -0700177 for (auto it = m_wire.elements_begin(); it != m_wire.elements_end(); ++it) {
Eric Newberry261dbc22015-07-22 23:18:18 -0700178 if (it->type() == FIELD::TlvType::value) {
179 if (count == index) {
180 m_wire.erase(it);
181 return *this;
182 }
183 count++;
184 }
185 }
186
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700187 BOOST_THROW_EXCEPTION(std::out_of_range("Index out of range"));
Eric Newberry261dbc22015-07-22 23:18:18 -0700188 }
189
190 /**
191 * \brief remove all occurrences of FIELD
192 */
193 template<typename FIELD>
194 Packet&
195 clear()
196 {
Eric Newberry261dbc22015-07-22 23:18:18 -0700197 m_wire.remove(FIELD::TlvType::value);
198 return *this;
199 }
200
201private:
202 static bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400203 comparePos(uint64_t first, const Block& second) noexcept;
Eric Newberry261dbc22015-07-22 23:18:18 -0700204
205private:
206 mutable Block m_wire;
207};
208
209} // namespace lp
210} // namespace ndn
211
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700212#endif // NDN_CXX_LP_PACKET_HPP