blob: 388bac5596ce3ca1b49b2de80ce4e66d58a8d949 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2013, Regents of the University of California
*
* BSD license, See the LICENSE file for more information
*
* Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
*/
#ifndef NDN_BLOCK_HPP
#define NDN_BLOCK_HPP
#include "../common.hpp"
#include "buffer.hpp"
#include "tlv.hpp"
namespace ndn {
template<bool> class EncodingImpl;
typedef EncodingImpl<true> EncodingBuffer;
/**
* @brief Class representing wire element of the NDN packet
*/
class Block
{
public:
typedef std::vector<Block> element_container;
typedef element_container::iterator element_iterator;
typedef element_container::const_iterator element_const_iterator;
/// @brief Error that can be thrown from the block
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
};
/**
* @brief Default constructor to create an empty Block
*/
Block();
/**
* @brief Create block based on EncodingBuffer object
*/
explicit
Block(const EncodingBuffer& buffer);
/**
* @brief A helper version of a constructor to create Block from the raw buffer (type and value-length parsing)
*
* This constructor provides ability of implicit conversion from ConstBufferPtr to Block
*/
Block(const ConstBufferPtr& buffer);
/**
* @brief Another helper to create block from a buffer, directly specifying boundaries
* of the block within the buffer
*
* This version will automatically detect type and position of the value within the block
*/
Block(const ConstBufferPtr& buffer,
const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
bool verifyLength = true);
/**
* @brief A helper version of a constructor to create Block from the raw buffer (type and value-length parsing)
*/
Block(const uint8_t* buffer, size_t maxlength);
Block(const void* buffer, size_t maxlength);
/*
* @brief A helper version of a constructor to create Block from the stream.
*/
explicit
Block(std::istream& is);
/**
* @brief Create Block from the wire buffer (no parsing)
*
* This version of the constructor does not do any parsing
*/
Block(const ConstBufferPtr& wire,
uint32_t type,
const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd);
/**
* @brief Create Block of a specific type with empty wire buffer
*/
explicit
Block(uint32_t type);
/**
* @brief Create Block of a specific type with the specified value
*
* The underlying buffer hold only value, additional operations are needed
* to construct wire encoding, one need to prepend the wire buffer with type
* and value-length VAR-NUMBERs
*/
Block(uint32_t type, const ConstBufferPtr& value);
/**
* @brief Create nested Block of a specific type with the specified value
*
* The underlying buffer hold only value, additional operations are needed
* to construct wire encoding, one need to prepend the wire buffer with type
* and value-length VAR-NUMBERs
*/
explicit
Block(uint32_t type, const Block& value);
/**
* @brief Try to construct block from Buffer, referencing data block pointed by wire
*
* @throws This method never throws an exception
*
* @returns true if Block successfully created, false if block cannot be created
*/
static bool
fromBuffer(const ConstBufferPtr& wire, size_t offset, Block& block);
/**
* @brief Try to construct block from Buffer, referencing data block pointed by wire
*
* @throws This method never throws an exception
*
* @returns true if Block successfully created, false if block cannot be created
*/
static bool
fromBuffer(const uint8_t* buffer, size_t maxSize, Block& block);
/**
* @brief Check if the Block is empty
*/
bool
empty() const;
/**
* @brief Check if the Block has fully encoded wire
*/
bool
hasWire() const;
/**
* @brief Check if the Block has value block (no type and length are encoded)
*/
bool
hasValue() const;
/**
* @brief Reset wire buffer of the element
*/
void
reset();
/**
* @brief Reset wire buffer but keep sub elements (if any)
*/
void
resetWire();
/**
* @brief Parse wire buffer into subblocks
*
* This method is not really const, but it does not modify any data. It simply
* parses contents of the buffer into subblocks
*/
void
parse() const;
/**
* @brief Encode subblocks into wire buffer
*/
void
encode();
uint32_t
type() const;
/**
* @brief Get the first subelement of the requested type
*/
const Block&
get(uint32_t type) const;
element_const_iterator
find(uint32_t type) const;
void
remove(uint32_t type);
element_iterator
erase(element_iterator position);
element_iterator
erase(element_iterator first, element_iterator last);
void
push_back(const Block& element);
Buffer::const_iterator
begin() const;
Buffer::const_iterator
end() const;
const uint8_t*
wire() const;
size_t
size() const;
Buffer::const_iterator
value_begin() const;
Buffer::const_iterator
value_end() const;
const uint8_t*
value() const;
size_t
value_size() const;
/**
* @brief Get all subelements
*/
const element_container&
elements() const;
element_const_iterator
elements_begin() const;
element_const_iterator
elements_end() const;
size_t
elements_size() const;
Block
blockFromValue() const;
public: // EqualityComparable concept
bool
operator==(const Block& other) const;
bool
operator!=(const Block& other) const;
protected:
ConstBufferPtr m_buffer;
uint32_t m_type;
Buffer::const_iterator m_begin;
Buffer::const_iterator m_end;
uint32_t m_size;
Buffer::const_iterator m_value_begin;
Buffer::const_iterator m_value_end;
mutable element_container m_subBlocks;
friend class EncodingImpl<true>;
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
inline bool
Block::empty() const
{
return m_type == std::numeric_limits<uint32_t>::max();
}
inline bool
Block::hasWire() const
{
return m_buffer && (m_begin != m_end);
}
inline bool
Block::hasValue() const
{
return static_cast<bool>(m_buffer);
}
inline void
Block::reset()
{
m_buffer.reset(); // reset of the shared_ptr
m_subBlocks.clear(); // remove all parsed subelements
m_type = std::numeric_limits<uint32_t>::max();
m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator();
}
inline void
Block::resetWire()
{
m_buffer.reset(); // reset of the shared_ptr
// keep subblocks
// keep type
m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator();
}
inline uint32_t
Block::type() const
{
return m_type;
}
inline const Block&
Block::get(uint32_t type) const
{
for (element_const_iterator i = m_subBlocks.begin();
i != m_subBlocks.end();
i++)
{
if (i->type() == type)
{
return *i;
}
}
throw Error("(Block::get) Requested a non-existed type [" +
boost::lexical_cast<std::string>(type) + "] from Block");
}
inline Block::element_const_iterator
Block::find(uint32_t type) const
{
for (element_const_iterator i = m_subBlocks.begin();
i != m_subBlocks.end();
i++)
{
if (i->type() == type)
{
return i;
}
}
return m_subBlocks.end();
}
inline void
Block::remove(uint32_t type)
{
resetWire();
element_container newContainer;
newContainer.reserve(m_subBlocks.size());
for (element_iterator i = m_subBlocks.begin();
i != m_subBlocks.end();
++i)
{
if (i->type() != type)
newContainer.push_back(*i);
}
m_subBlocks.swap(newContainer);
}
inline Block::element_iterator
Block::erase(Block::element_iterator position)
{
resetWire();
return m_subBlocks.erase(position);
}
inline Block::element_iterator
Block::erase(Block::element_iterator first, Block::element_iterator last)
{
resetWire();
return m_subBlocks.erase(first, last);
}
inline void
Block::push_back(const Block& element)
{
resetWire();
m_subBlocks.push_back(element);
}
inline Buffer::const_iterator
Block::begin() const
{
if (!hasWire())
throw Error("Underlying wire buffer is empty");
return m_begin;
}
inline Buffer::const_iterator
Block::end() const
{
if (!hasWire())
throw Error("Underlying wire buffer is empty");
return m_end;
}
inline size_t
Block::size() const
{
if (hasWire() || hasValue()) {
return m_size;
}
else
throw Error("Block size cannot be determined (undefined block size)");
}
inline Buffer::const_iterator
Block::value_begin() const
{
return m_value_begin;
}
inline Buffer::const_iterator
Block::value_end() const
{
return m_value_end;
}
inline const uint8_t*
Block::wire() const
{
if (!hasWire())
throw Error("(Block::wire) Underlying wire buffer is empty");
return &*m_begin;
}
inline const uint8_t*
Block::value() const
{
if (!hasValue())
return 0;
return &*m_value_begin;
}
inline size_t
Block::value_size() const
{
if (!hasValue())
return 0;
return m_value_end - m_value_begin;
}
inline const Block::element_container&
Block::elements() const
{
return m_subBlocks;
}
inline Block::element_const_iterator
Block::elements_begin() const
{
return m_subBlocks.begin();
}
inline Block::element_const_iterator
Block::elements_end() const
{
return m_subBlocks.end();
}
inline size_t
Block::elements_size() const
{
return m_subBlocks.size();
}
inline bool
Block::operator==(const Block& other) const
{
return (this->size() == other.size()) &&
std::equal(this->begin(), this->end(), other.begin());
}
inline bool
Block::operator!=(const Block& other) const
{
return !this->operator==(other);
}
} // ndn
#include "block-helpers.hpp"
#endif // NDN_BLOCK_HPP