blob: 0febb758a7da9b3f78e6aa6be0e1bb25ef5ac0cc [file] [log] [blame]
Eric Newberry261dbc22015-07-22 23:18:18 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2015 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_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 /**
49 * \brief append packet to encoder
50 */
51 template<encoding::Tag TAG>
52 size_t
53 wireEncode(EncodingImpl<TAG>& encoder) const;
54
55 /**
56 * \brief encode packet into wire format
57 */
58 const Block&
59 wireEncode() const;
60
61 /**
62 * \brief decode packet from wire format
63 */
64 void
65 wireDecode(const Block& wire);
66
67public: // field access
68 /**
69 * \return true if FIELD occurs one or more times
70 * \detail This is equivalent to count()>0
71 */
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 {
86 m_wire.parse();
87
88 return std::count_if(m_wire.elements_begin(), m_wire.elements_end(),
89 [] (const Block& block) {
90 return block.type() == FIELD::TlvType::value; });
91 }
92
93 /**
94 * \return value of index-th occurrence of FIELD
95 * \throw std::out_of_range if index>=count()
96 */
97 template<typename FIELD>
98 typename FIELD::ValueType
99 get(size_t index = 0) const
100 {
101 m_wire.parse();
102
103 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
125 m_wire.parse();
126
127 for (const Block& element : m_wire.elements()) {
128 if (element.type() != FIELD::TlvType::value) {
129 continue;
130 }
131 output.push_back(FIELD::decode(element));
132 }
133
134 return output;
135 }
136
137 /**
138 * \brief remove all occurrences of FIELD, and add a FIELD with value
139 * \detail This equivalent to clear() followed by add(value)
140 */
141 template<typename FIELD>
142 Packet&
143 set(const typename FIELD::ValueType& value)
144 {
145 clear<FIELD>();
146 return add<FIELD>(value);
147 }
148
149 /**
150 * \brief add a FIELD with value
151 * \throw std::length_error if field already exists and is not repeatable
152 */
153 template<typename FIELD>
154 Packet&
155 add(const typename FIELD::ValueType& value)
156 {
157 if (!FIELD::IsRepeatable::value && has<FIELD>()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700158 BOOST_THROW_EXCEPTION(std::length_error("Field cannot be repeated"));
Eric Newberry261dbc22015-07-22 23:18:18 -0700159 }
160
161 EncodingEstimator estimator;
162 size_t estimatedSize = FIELD::encode(estimator, value);
163 EncodingBuffer buffer(estimatedSize, 0);
164 FIELD::encode(buffer, value);
165 Block block = buffer.block();
166
167 Block::element_const_iterator pos = std::lower_bound(m_wire.elements_begin(),
168 m_wire.elements_end(),
169 FIELD::TlvType::value,
170 comparePos);
171 m_wire.insert(pos, block);
172
173 return *this;
174 }
175
176 /**
177 * \brief remove the index-th occurrence of FIELD
178 * \throw std::out_of_range if index>=count()
179 */
180 template<typename FIELD>
181 Packet&
182 remove(size_t index = 0)
183 {
184 m_wire.parse();
185
186 size_t count = 0;
187 for (Block::element_const_iterator it = m_wire.elements_begin(); it != m_wire.elements_end();
188 ++it) {
189 if (it->type() == FIELD::TlvType::value) {
190 if (count == index) {
191 m_wire.erase(it);
192 return *this;
193 }
194 count++;
195 }
196 }
197
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700198 BOOST_THROW_EXCEPTION(std::out_of_range("Index out of range"));
Eric Newberry261dbc22015-07-22 23:18:18 -0700199 }
200
201 /**
202 * \brief remove all occurrences of FIELD
203 */
204 template<typename FIELD>
205 Packet&
206 clear()
207 {
208 m_wire.parse();
209 m_wire.remove(FIELD::TlvType::value);
210 return *this;
211 }
212
213private:
214 static bool
215 comparePos(const Block& first, const uint64_t second);
216
217private:
218 mutable Block m_wire;
219};
220
221} // namespace lp
222} // namespace ndn
223
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700224#endif // NDN_CXX_LP_PACKET_HPP