Introduce Delegation and DelegationList
DelegationList will become the payload structure of ForwardingHint
and LinkContent in a later commit.
refs #4055
Change-Id: If29a39c47b779aafdd4aebb104092403f28e6653
diff --git a/src/delegation-list.hpp b/src/delegation-list.hpp
new file mode 100644
index 0000000..9f74399
--- /dev/null
+++ b/src/delegation-list.hpp
@@ -0,0 +1,239 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 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_DELEGATION_LIST_HPP
+#define NDN_DELEGATION_LIST_HPP
+
+#include "delegation.hpp"
+
+namespace ndn {
+
+/** \brief represents a list of Delegations
+ * \sa https://named-data.net/doc/ndn-tlv/link.html
+ *
+ * Delegations are stored in an std::vector, under the assumption that there is usually only a
+ * small number of Delegations, so that copying is acceptable when they are modified.
+ */
+class DelegationList
+{
+public:
+ class Error : public tlv::Error
+ {
+ public:
+ explicit
+ Error(const std::string& what);
+
+ Error(const std::string& what, const std::exception& innerException);
+ };
+
+ /** \brief construct an empty DelegationList
+ */
+ DelegationList();
+
+ /** \brief decode a DelegationList
+ * \sa wireDecode
+ */
+ explicit
+ DelegationList(const Block& block, bool wantSort = true);
+
+ /** \brief encode into wire format
+ * \param encoder either an EncodingBuffer or an EncodingEstimator
+ * \param type TLV-TYPE code, either Content (for \p Link) or ForwardingHint
+ * \throw std::invalid_argument \p type is invalid
+ * \throw Error there is no Delegation
+ */
+ template<encoding::Tag TAG>
+ size_t
+ wireEncode(EncodingImpl<TAG>& encoder, uint32_t type = tlv::ForwardingHint) const;
+
+ /** \brief decode a DelegationList
+ * \param block either a Content block (from \p Link) or a ForwardingHint block
+ * \param wantSort if true, delegations are sorted
+ * \throw Error the block cannot be parsed as a list of Delegations
+ */
+ void
+ wireDecode(const Block& block, bool wantSort = true);
+
+ bool
+ isSorted() const
+ {
+ return m_isSorted;
+ }
+
+ using const_iterator = std::vector<Delegation>::const_iterator;
+
+ const_iterator
+ begin() const
+ {
+ return m_dels.begin();
+ }
+
+ const_iterator
+ end() const
+ {
+ return m_dels.end();
+ }
+
+ size_t
+ size() const
+ {
+ return m_dels.size();
+ }
+
+ /** \brief get the i-th delegation
+ * \pre i < size()
+ */
+ const Delegation&
+ operator[](size_t i) const
+ {
+ BOOST_ASSERT(i < size());
+ return m_dels[i];
+ }
+
+ /** \brief get the i-th delegation
+ * \throw std::out_of_range i >= size()
+ */
+ const Delegation&
+ at(size_t i) const
+ {
+ return m_dels.at(i);
+ }
+
+public: // modifiers
+ /** \brief sort the delegation list
+ * \post isSorted() == true
+ * \post Delegations are sorted in increasing preference order.
+ *
+ * A DelegationList can be constructed as sorted or unsorted. In most cases, it is recommended
+ * to use a sorted DelegationList. An unsorted DelegationList is useful for extracting the i-th
+ * delegation from a received ForwardingHint or Link object.
+ *
+ * This method turns an unsorted DelegationList into a sorted DelegationList.
+ * If access to unsorted DelegationList is not needed, it is more efficient to sort the
+ * DelegationList in wireDecode.
+ */
+ void
+ sort();
+
+ /** \brief what to do when inserting a duplicate name
+ */
+ enum InsertConflictResolution {
+ /** \brief existing delegation(s) with the same name are replaced with the new delegation
+ */
+ INS_REPLACE,
+
+ /** \brief multiple delegations with the same name are kept in the DelegationList
+ * \note This is NOT RECOMMENDED by Link specification.
+ */
+ INS_APPEND,
+
+ /** \brief new delegation is not inserted if an existing delegation has the same name
+ */
+ INS_SKIP
+ };
+
+ /** \brief insert Delegation
+ * \return whether inserted
+ */
+ bool
+ insert(uint64_t preference, const Name& name,
+ InsertConflictResolution onConflict = INS_REPLACE);
+
+ /** \brief insert Delegation
+ * \return whether inserted
+ */
+ bool
+ insert(const Delegation& del, InsertConflictResolution onConflict = INS_REPLACE)
+ {
+ return this->insert(del.preference, del.name, onConflict);
+ }
+
+ /** \brief delete Delegation(s) with specified preference and name
+ * \return count of erased Delegation(s)
+ */
+ size_t
+ erase(uint64_t preference, const Name& name)
+ {
+ return this->eraseImpl(preference, name);
+ }
+
+ /** \brief delete Delegation(s) with matching preference and name
+ * \return count of erased Delegation(s)
+ */
+ size_t
+ erase(const Delegation& del)
+ {
+ return this->eraseImpl(del.preference, del.name);
+ }
+
+ /** \brief erase Delegation(s) with specified name
+ * \return count of erased Delegation(s)
+ */
+ size_t
+ erase(const Name& name)
+ {
+ return this->eraseImpl(nullopt, name);
+ }
+
+private:
+ static bool
+ isValidTlvType(uint32_t type);
+
+ void
+ insertImpl(uint64_t preference, const Name& name);
+
+ size_t
+ eraseImpl(optional<uint64_t> preference, const Name& name);
+
+private:
+ bool m_isSorted;
+
+ /** \brief delegation container; its contents are sorted when \p m_isSorted is true
+ * \note This container is a member field rather than a base class, in order to ensure contents
+ * are sorted when \p m_isSorted is true.
+ * \note A vector is chosen instead of a std::set, so that the container can be unsorted when
+ * \p m_isSorted is false. This container is expected to have less than seven items, and
+ * therefore the overhead of moving items during insertion and deletion is small.
+ */
+ std::vector<Delegation> m_dels;
+
+ friend bool operator==(const DelegationList&, const DelegationList&);
+};
+
+/** \brief compare whether two DelegationLists are equal
+ * \note Order matters! If two DelegationLists contain the same Delegations but at least one is
+ * unsorted, they may compare unequal if the Delegations appear in different order.
+ */
+bool
+operator==(const DelegationList& lhs, const DelegationList& rhs);
+
+inline bool
+operator!=(const DelegationList& lhs, const DelegationList& rhs)
+{
+ return !(lhs == rhs);
+}
+
+std::ostream&
+operator<<(std::ostream& os, const DelegationList& dl);
+
+} // namespace ndn
+
+#endif // NDN_DELEGATION_LIST_HPP