blob: 872af589c14b7a8f657554ac144add9349b71503 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013-2018 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received copies of the GNU General Public License and GNU Lesser
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
* <http://www.gnu.org/licenses/>.
*
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
*/
#ifndef NDN_CXX_LP_PACKET_HPP
#define NDN_CXX_LP_PACKET_HPP
#include "fields.hpp"
namespace ndn {
namespace lp {
class Packet
{
public:
class Error : public ndn::tlv::Error
{
public:
using ndn::tlv::Error::Error;
};
Packet();
explicit
Packet(const Block& wire);
/**
* \brief encode packet into wire format
*/
Block
wireEncode() const;
/**
* \brief decode packet from wire format
* \throws Error unknown TLV-TYPE
*/
void
wireDecode(const Block& wire);
/**
* \retval true packet has no field
* \retval false packet has one or more fields
*/
bool
empty() const
{
return m_wire.elements_size() == 0;
}
public: // field access
/**
* \return true if FIELD occurs one or more times
* \details This is equivalent to count() > 0
*/
template<typename FIELD>
bool
has() const
{
return count<FIELD>() > 0;
}
/**
* \return number of occurrences of FIELD
*/
template<typename FIELD>
size_t
count() const
{
return std::count_if(m_wire.elements_begin(), m_wire.elements_end(),
[] (const Block& block) {
return block.type() == FIELD::TlvType::value; });
}
/**
* \return value of index-th occurrence of FIELD
* \throw std::out_of_range if index>=count()
*/
template<typename FIELD>
typename FIELD::ValueType
get(size_t index = 0) const
{
size_t count = 0;
for (const Block& element : m_wire.elements()) {
if (element.type() != FIELD::TlvType::value) {
continue;
}
if (count++ == index) {
return FIELD::decode(element);
}
}
BOOST_THROW_EXCEPTION(std::out_of_range("Index out of range"));
}
/**
* \return values of all occurrences of FIELD
*/
template<typename FIELD>
std::vector<typename FIELD::ValueType>
list() const
{
std::vector<typename FIELD::ValueType> output;
for (const Block& element : m_wire.elements()) {
if (element.type() != FIELD::TlvType::value) {
continue;
}
output.push_back(FIELD::decode(element));
}
return output;
}
/**
* \brief remove all occurrences of FIELD, and add a FIELD with value
* \details This equivalent to clear() followed by add(value)
*/
template<typename FIELD>
Packet&
set(const typename FIELD::ValueType& value)
{
clear<FIELD>();
return add<FIELD>(value);
}
/**
* \brief add a FIELD with value
* \throw std::length_error if field already exists and is not repeatable
*/
template<typename FIELD>
Packet&
add(const typename FIELD::ValueType& value)
{
if (!FIELD::IsRepeatable::value && has<FIELD>()) {
BOOST_THROW_EXCEPTION(std::length_error("Field cannot be repeated"));
}
EncodingEstimator estimator;
size_t estimatedSize = FIELD::encode(estimator, value);
EncodingBuffer buffer(estimatedSize, 0);
FIELD::encode(buffer, value);
Block block = buffer.block();
auto pos = std::upper_bound(m_wire.elements_begin(), m_wire.elements_end(),
FIELD::TlvType::value, comparePos);
m_wire.insert(pos, block);
return *this;
}
/**
* \brief remove the index-th occurrence of FIELD
* \throw std::out_of_range if index>=count()
*/
template<typename FIELD>
Packet&
remove(size_t index = 0)
{
size_t count = 0;
for (auto it = m_wire.elements_begin(); it != m_wire.elements_end(); ++it) {
if (it->type() == FIELD::TlvType::value) {
if (count == index) {
m_wire.erase(it);
return *this;
}
count++;
}
}
BOOST_THROW_EXCEPTION(std::out_of_range("Index out of range"));
}
/**
* \brief remove all occurrences of FIELD
*/
template<typename FIELD>
Packet&
clear()
{
m_wire.remove(FIELD::TlvType::value);
return *this;
}
private:
static bool
comparePos(uint64_t first, const Block& second) noexcept;
private:
mutable Block m_wire;
};
} // namespace lp
} // namespace ndn
#endif // NDN_CXX_LP_PACKET_HPP