fast-encoding: implement fast encoding for Name, NameComponent and FibManagementOptions, including test case.
refs: #1172
Change-Id: I80fa7cfbe7f9dee3c439febcc8f800c63a31eac3
diff --git a/src/encoding/encoding-buffer.hpp b/src/encoding/encoding-buffer.hpp
new file mode 100644
index 0000000..b3cfa65
--- /dev/null
+++ b/src/encoding/encoding-buffer.hpp
@@ -0,0 +1,382 @@
+/* -*- 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: Wentao Shang <wentao@cs.ucla.edu>
+ */
+
+#ifndef NDN_ENCODING_BUFFER_HPP
+#define NDN_ENCODING_BUFFER_HPP
+
+#include "../common.hpp"
+
+#include <list>
+#include <exception>
+#include <algorithm>
+
+#include "buffer.hpp"
+#include "tlv.hpp"
+
+#include <boost/lexical_cast.hpp>
+
+namespace ndn {
+
+/**
+ * @brief Class representing wire element of the NDN packet
+ */
+class EncodingBuffer
+{
+public:
+ /// @brief Error that can be thrown from the block
+ struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
+
+ enum
+ {
+ DefaultBufferSize = 8800,
+ BufferReservedSize = 400
+ };
+
+ /**
+ * @brief Default constructor to create a fix-sized EncodingBuffer
+ */
+ EncodingBuffer ()
+ : m_buffer (new Buffer ((size_t) DefaultBufferSize))
+ {
+ m_begin = m_end = m_buffer->end () - BufferReservedSize;
+ }
+
+ /**
+ * @brief Constructor to create a EncodingBuffer with user-specified size
+ */
+ EncodingBuffer (size_t size)
+ : m_buffer (new Buffer (size))
+ {
+ if (size <= BufferReservedSize)
+ m_begin = m_end = m_buffer->end ();
+ else
+ m_begin = m_end = m_buffer->end () - BufferReservedSize;
+ }
+
+ inline size_t
+ size () const;
+
+ inline size_t
+ capacity () const;
+
+ inline uint8_t*
+ buf ();
+
+ inline const uint8_t*
+ buf () const;
+
+ inline void
+ resize (size_t sz, bool addInFront);
+
+ inline Buffer::iterator
+ begin ();
+
+ inline Buffer::iterator
+ end ();
+
+ inline Buffer::const_iterator
+ begin () const;
+
+ inline Buffer::const_iterator
+ end () const;
+
+ inline size_t
+ prependByte (uint8_t val);
+
+ inline size_t
+ prependByteArray (const uint8_t *arr, size_t len);
+
+ inline size_t
+ prependBuffer (const Buffer& arr);
+
+ inline size_t
+ prependNonNegativeInteger (uint64_t varNumber);
+
+ inline size_t
+ prependVarNumber (uint64_t varNumber);
+
+ inline size_t
+ appendByte (uint8_t val);
+
+ inline size_t
+ appendByteArray (const uint8_t *arr, size_t len);
+
+ inline size_t
+ appendBuffer (const Buffer& arr);
+
+ inline size_t
+ appendNonNegativeInteger (uint64_t varNumber);
+
+ inline size_t
+ appendVarNumber (uint64_t varNumber);
+
+private:
+ BufferPtr m_buffer;
+
+ // invariant: m_begin always points to the position of last-written byte (if prepending data)
+ Buffer::iterator m_begin;
+ // invariant: m_end always points to the position of next unwritten byte (if appending data)
+ Buffer::iterator m_end;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+inline size_t
+EncodingBuffer::size () const
+{
+ return m_end - m_begin;
+}
+
+inline size_t
+EncodingBuffer::capacity () const
+{
+ return m_buffer->size ();
+}
+
+inline uint8_t*
+EncodingBuffer::buf ()
+{
+ return &(*m_begin);
+}
+
+inline const uint8_t*
+EncodingBuffer::buf () const
+{
+ return &(*m_begin);
+}
+
+inline void
+EncodingBuffer::resize (size_t sz, bool addInFront)
+{
+ if (addInFront)
+ {
+ size_t diff_end = m_buffer->end () - m_end;
+ size_t diff_begin = m_buffer->end () - m_begin;
+
+ Buffer* buf = new Buffer (sz);
+ std::copy_backward (m_buffer->begin (), m_buffer->end (), buf->end ());
+
+ m_buffer.reset (buf);
+
+ m_end = m_buffer->end () - diff_end;
+ m_begin = m_buffer->end () - diff_begin;
+ }
+ else
+ {
+ size_t diff_end = m_end - m_buffer->begin ();
+ size_t diff_begin = m_begin - m_buffer->begin ();
+
+ Buffer* buf = new Buffer (sz);
+ std::copy (m_buffer->begin (), m_buffer->end (), buf->begin ());
+
+ m_buffer.reset (buf);
+
+ m_end = m_buffer->begin () + diff_end;
+ m_begin = m_buffer->begin () + diff_begin;
+ }
+}
+
+inline Buffer::iterator
+EncodingBuffer::begin ()
+{
+ return m_begin;
+}
+
+inline Buffer::iterator
+EncodingBuffer::end ()
+{
+ return m_end;
+}
+
+inline Buffer::const_iterator
+EncodingBuffer::begin () const
+{
+ return m_begin;
+}
+
+inline Buffer::const_iterator
+EncodingBuffer::end () const
+{
+ return m_end;
+}
+
+
+//////////////////////////////////////////////////////////
+// Prepend to the back of the buffer. Resize if needed. //
+//////////////////////////////////////////////////////////
+
+inline size_t
+EncodingBuffer::prependByte (uint8_t val)
+{
+ if (m_begin == m_buffer->begin ())
+ resize (m_buffer->size () * 2, true);
+
+ m_begin--;
+ *m_begin = val;
+ return 1;
+}
+
+inline size_t
+EncodingBuffer::prependByteArray (const uint8_t *arr, size_t len)
+{
+ if ((m_buffer->begin () + len) > m_begin)
+ resize (m_buffer->size () * 2 + len, true);
+
+ m_begin -= len;
+ std::copy (arr, arr + len, m_begin);
+ return len;
+}
+
+inline size_t
+EncodingBuffer::prependBuffer (const Buffer& arr)
+{
+ if ((m_buffer->begin () + arr.size ()) > m_begin)
+ resize (m_buffer->size () * 2 + arr.size (), true);
+
+ m_begin -= arr.size ();
+ std::copy (arr.begin (), arr.end (), m_begin);
+ return arr.size ();
+}
+
+inline size_t
+EncodingBuffer::prependNonNegativeInteger (uint64_t varNumber)
+{
+ if (varNumber < 253) {
+ return prependByte (static_cast<uint8_t> (varNumber));
+ }
+ else if (varNumber <= std::numeric_limits<uint16_t>::max ()) {
+ uint16_t value = htobe16 (static_cast<uint16_t> (varNumber));
+ return prependByteArray (reinterpret_cast<const uint8_t*> (&value), 2);
+ }
+ else if (varNumber <= std::numeric_limits<uint32_t>::max ()) {
+ uint32_t value = htobe32 (static_cast<uint32_t> (varNumber));
+ return prependByteArray (reinterpret_cast<const uint8_t*> (&value), 4);
+ }
+ else {
+ uint64_t value = htobe64 (varNumber);
+ return prependByteArray (reinterpret_cast<const uint8_t*> (&value), 8);
+ }
+}
+
+inline size_t
+EncodingBuffer::prependVarNumber (uint64_t varNumber)
+{
+ if (varNumber < 253) {
+ prependByte (static_cast<uint8_t> (varNumber));
+ return 1;
+ }
+ else if (varNumber <= std::numeric_limits<uint16_t>::max ()) {
+ uint16_t value = htobe16 (static_cast<uint16_t> (varNumber));
+ prependByteArray (reinterpret_cast<const uint8_t*> (&value), 2);
+ prependByte (253);
+ return 3;
+ }
+ else if (varNumber <= std::numeric_limits<uint32_t>::max ()) {
+ uint32_t value = htobe32 (static_cast<uint32_t> (varNumber));
+ prependByteArray (reinterpret_cast<const uint8_t*> (&value), 4);
+ prependByte (254);
+ return 5;
+ }
+ else {
+ uint64_t value = htobe64 (varNumber);
+ prependByteArray (reinterpret_cast<const uint8_t*> (&value), 8);
+ prependByte (255);
+ return 9;
+ }
+}
+
+/////////////////////////////////////////////////////////
+// Append to the back of the buffer. Resize if needed. //
+/////////////////////////////////////////////////////////
+
+inline size_t
+EncodingBuffer::appendByte (uint8_t val)
+{
+ if (m_end == m_buffer->end ())
+ resize (m_buffer->size () * 2, false);
+
+ *m_end = val;
+ m_end++;
+ return 1;
+}
+
+inline size_t
+EncodingBuffer::appendByteArray (const uint8_t *arr, size_t len)
+{
+ if ((m_end + len) > m_buffer->end ())
+ resize (m_buffer->size () * 2 + len, false);
+
+ std::copy (arr, arr + len, m_end);
+ m_end += len;
+ return len;
+}
+
+inline size_t
+EncodingBuffer::appendBuffer (const Buffer& arr)
+{
+ if ((m_end + arr.size ()) > m_buffer->end ())
+ resize (m_buffer->size () * 2 + arr.size (), false);
+
+ std::copy (arr.begin (), arr.end (), m_end);
+ m_end -= arr.size ();
+ return arr.size ();
+}
+
+inline size_t
+EncodingBuffer::appendNonNegativeInteger (uint64_t varNumber)
+{
+ if (varNumber < 253) {
+ return appendByte (static_cast<uint8_t> (varNumber));
+ }
+ else if (varNumber <= std::numeric_limits<uint16_t>::max ()) {
+ uint16_t value = htobe16 (static_cast<uint16_t> (varNumber));
+ return appendByteArray (reinterpret_cast<const uint8_t*> (&value), 2);
+ }
+ else if (varNumber <= std::numeric_limits<uint32_t>::max ()) {
+ uint32_t value = htobe32 (static_cast<uint32_t> (varNumber));
+ return appendByteArray (reinterpret_cast<const uint8_t*> (&value), 4);
+ }
+ else {
+ uint64_t value = htobe64 (varNumber);
+ return appendByteArray (reinterpret_cast<const uint8_t*> (&value), 8);
+ }
+}
+
+inline size_t
+EncodingBuffer::appendVarNumber (uint64_t varNumber)
+{
+ if (varNumber < 253) {
+ appendByte (static_cast<uint8_t> (varNumber));
+ return 1;
+ }
+ else if (varNumber <= std::numeric_limits<uint16_t>::max ()) {
+ appendByte (253);
+ uint16_t value = htobe16 (static_cast<uint16_t> (varNumber));
+ appendByteArray (reinterpret_cast<const uint8_t*> (&value), 2);
+ return 3;
+ }
+ else if (varNumber <= std::numeric_limits<uint32_t>::max ()) {
+ appendByte (254);
+ uint32_t value = htobe32 (static_cast<uint32_t> (varNumber));
+ appendByteArray (reinterpret_cast<const uint8_t*> (&value), 4);
+ return 5;
+ }
+ else {
+ appendByte (255);
+ uint64_t value = htobe64 (varNumber);
+ appendByteArray (reinterpret_cast<const uint8_t*> (&value), 8);
+ return 9;
+ }
+}
+
+} // ndn
+
+#endif // NDN_ENCODING_BUFFER_HPP