table: make name_tree::Node the sole owner of name_tree::Entry

This commit also improves name_tree::Entry test coverage.

refs #3687

Change-Id: I92375f29fbebab82c67da7dff2ea7a2952ba2cca
diff --git a/daemon/table/fib-entry.cpp b/daemon/table/fib-entry.cpp
index cb37b0f..c2e299f 100644
--- a/daemon/table/fib-entry.cpp
+++ b/daemon/table/fib-entry.cpp
@@ -30,6 +30,7 @@
 
 Entry::Entry(const Name& prefix)
   : m_prefix(prefix)
+  , m_nameTreeEntry(nullptr)
 {
 }
 
@@ -77,6 +78,5 @@
             [] (const NextHop& a, const NextHop& b) { return a.getCost() < b.getCost(); });
 }
 
-
 } // namespace fib
 } // namespace nfd
diff --git a/daemon/table/fib-entry.hpp b/daemon/table/fib-entry.hpp
index 94f2331..cf372ac 100644
--- a/daemon/table/fib-entry.hpp
+++ b/daemon/table/fib-entry.hpp
@@ -31,10 +31,8 @@
 namespace nfd {
 
 namespace name_tree {
-class NameTree;
 class Entry;
 } // namespace name_tree
-using name_tree::NameTree;
 
 namespace fib {
 
@@ -48,8 +46,7 @@
  */
 typedef std::vector<fib::NextHop> NextHopList;
 
-/** \class Entry
- *  \brief represents a FIB entry
+/** \brief represents a FIB entry
  */
 class Entry : noncopyable
 {
@@ -58,15 +55,24 @@
   Entry(const Name& prefix);
 
   const Name&
-  getPrefix() const;
+  getPrefix() const
+  {
+    return m_prefix;
+  }
 
   const NextHopList&
-  getNextHops() const;
+  getNextHops() const
+  {
+    return m_nextHops;
+  }
 
   /** \return whether this Entry has any NextHop record
    */
   bool
-  hasNextHops() const;
+  hasNextHops() const
+  {
+    return !m_nextHops.empty();
+  }
 
   /** \return whether there is a NextHop record for \p face
    */
@@ -102,30 +108,11 @@
   Name m_prefix;
   NextHopList m_nextHops;
 
-  weak_ptr<name_tree::Entry> m_nameTreeEntry;
-  friend class nfd::NameTree;
-  friend class nfd::name_tree::Entry;
+  name_tree::Entry* m_nameTreeEntry;
+
+  friend class name_tree::Entry;
 };
 
-
-inline const Name&
-Entry::getPrefix() const
-{
-  return m_prefix;
-}
-
-inline const NextHopList&
-Entry::getNextHops() const
-{
-  return m_nextHops;
-}
-
-inline bool
-Entry::hasNextHops() const
-{
-  return !m_nextHops.empty();
-}
-
 } // namespace fib
 } // namespace nfd
 
diff --git a/daemon/table/measurements-entry.cpp b/daemon/table/measurements-entry.cpp
index 6858399..60138af 100644
--- a/daemon/table/measurements-entry.cpp
+++ b/daemon/table/measurements-entry.cpp
@@ -1,11 +1,12 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014  Regents of the University of California,
- *                     Arizona Board of Regents,
- *                     Colorado State University,
- *                     University Pierre & Marie Curie, Sorbonne University,
- *                     Washington University in St. Louis,
- *                     Beijing Institute of Technology
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
  *
  * This file is part of NFD (Named Data Networking Forwarding Daemon).
  * See AUTHORS.md for complete list of NFD authors and contributors.
@@ -20,7 +21,7 @@
  *
  * You should have received a copy of the GNU General Public License along with
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- **/
+ */
 
 #include "measurements-entry.hpp"
 
@@ -30,6 +31,7 @@
 Entry::Entry(const Name& name)
   : m_name(name)
   , m_expiry(time::steady_clock::TimePoint::min())
+  , m_nameTreeEntry(nullptr)
 {
 }
 
diff --git a/daemon/table/measurements-entry.hpp b/daemon/table/measurements-entry.hpp
index c0ec0f2..53f1a05 100644
--- a/daemon/table/measurements-entry.hpp
+++ b/daemon/table/measurements-entry.hpp
@@ -32,15 +32,11 @@
 namespace nfd {
 
 namespace name_tree {
-class NameTree;
 class Entry;
 } // namespace name_tree
-using name_tree::NameTree;
 
 namespace measurements {
 
-class Measurements;
-
 /** \brief represents a Measurements entry
  */
 class Entry : public StrategyInfoHost, noncopyable
@@ -50,27 +46,22 @@
   Entry(const Name& name);
 
   const Name&
-  getName() const;
+  getName() const
+  {
+    return m_name;
+  }
 
 private:
   Name m_name;
-
-private: // lifetime
   time::steady_clock::TimePoint m_expiry;
   scheduler::EventId m_cleanup;
-  weak_ptr<name_tree::Entry> m_nameTreeEntry;
 
-  friend class nfd::NameTree;
-  friend class nfd::name_tree::Entry;
+  name_tree::Entry* m_nameTreeEntry;
+
   friend class Measurements;
+  friend class name_tree::Entry;
 };
 
-inline const Name&
-Entry::getName() const
-{
-  return m_name;
-}
-
 } // namespace measurements
 } // namespace nfd
 
diff --git a/daemon/table/name-tree-entry.cpp b/daemon/table/name-tree-entry.cpp
index 77b66ef..5721e22 100644
--- a/daemon/table/name-tree-entry.cpp
+++ b/daemon/table/name-tree-entry.cpp
@@ -72,15 +72,15 @@
 void
 Entry::setFibEntry(unique_ptr<fib::Entry> fibEntry)
 {
-  BOOST_ASSERT(fibEntry == nullptr || fibEntry->m_nameTreeEntry.expired());
+  BOOST_ASSERT(fibEntry == nullptr || fibEntry->m_nameTreeEntry == nullptr);
 
   if (m_fibEntry != nullptr) {
-    m_fibEntry->m_nameTreeEntry.reset();
+    m_fibEntry->m_nameTreeEntry = nullptr;
   }
   m_fibEntry = std::move(fibEntry);
 
   if (m_fibEntry != nullptr) {
-    m_fibEntry->m_nameTreeEntry = this->shared_from_this();
+    m_fibEntry->m_nameTreeEntry = this;
   }
 }
 
@@ -88,53 +88,53 @@
 Entry::insertPitEntry(shared_ptr<pit::Entry> pitEntry)
 {
   BOOST_ASSERT(pitEntry != nullptr);
-  BOOST_ASSERT(pitEntry->m_nameTreeEntry.expired());
+  BOOST_ASSERT(pitEntry->m_nameTreeEntry == nullptr);
 
   m_pitEntries.push_back(pitEntry);
-  pitEntry->m_nameTreeEntry = this->shared_from_this();
+  pitEntry->m_nameTreeEntry = this;
 }
 
 void
 Entry::erasePitEntry(shared_ptr<pit::Entry> pitEntry)
 {
   BOOST_ASSERT(pitEntry != nullptr);
-  BOOST_ASSERT(pitEntry->m_nameTreeEntry.lock().get() == this);
+  BOOST_ASSERT(pitEntry->m_nameTreeEntry == this);
 
   auto it = std::find(m_pitEntries.begin(), m_pitEntries.end(), pitEntry);
   BOOST_ASSERT(it != m_pitEntries.end());
 
   *it = m_pitEntries.back();
   m_pitEntries.pop_back();
-  pitEntry->m_nameTreeEntry.reset();
+  pitEntry->m_nameTreeEntry = nullptr;
 }
 
 void
 Entry::setMeasurementsEntry(unique_ptr<measurements::Entry> measurementsEntry)
 {
-  BOOST_ASSERT(measurementsEntry == nullptr || measurementsEntry->m_nameTreeEntry.expired());
+  BOOST_ASSERT(measurementsEntry == nullptr || measurementsEntry->m_nameTreeEntry == nullptr);
 
   if (m_measurementsEntry != nullptr) {
-    m_measurementsEntry->m_nameTreeEntry.reset();
+    m_measurementsEntry->m_nameTreeEntry = nullptr;
   }
   m_measurementsEntry = std::move(measurementsEntry);
 
   if (m_measurementsEntry != nullptr) {
-    m_measurementsEntry->m_nameTreeEntry = this->shared_from_this();
+    m_measurementsEntry->m_nameTreeEntry = this;
   }
 }
 
 void
 Entry::setStrategyChoiceEntry(unique_ptr<strategy_choice::Entry> strategyChoiceEntry)
 {
-  BOOST_ASSERT(strategyChoiceEntry == nullptr || strategyChoiceEntry->m_nameTreeEntry.expired());
+  BOOST_ASSERT(strategyChoiceEntry == nullptr || strategyChoiceEntry->m_nameTreeEntry == nullptr);
 
   if (m_strategyChoiceEntry != nullptr) {
-    m_strategyChoiceEntry->m_nameTreeEntry.reset();
+    m_strategyChoiceEntry->m_nameTreeEntry = nullptr;
   }
   m_strategyChoiceEntry = std::move(strategyChoiceEntry);
 
   if (m_strategyChoiceEntry != nullptr) {
-    m_strategyChoiceEntry->m_nameTreeEntry = this->shared_from_this();
+    m_strategyChoiceEntry->m_nameTreeEntry = this;
   }
 }
 
diff --git a/daemon/table/name-tree-entry.hpp b/daemon/table/name-tree-entry.hpp
index 576139c..d481a5e 100644
--- a/daemon/table/name-tree-entry.hpp
+++ b/daemon/table/name-tree-entry.hpp
@@ -26,7 +26,6 @@
 #ifndef NFD_DAEMON_TABLE_NAME_TREE_ENTRY_HPP
 #define NFD_DAEMON_TABLE_NAME_TREE_ENTRY_HPP
 
-#include "name-tree-hashtable.hpp"
 #include "table/fib-entry.hpp"
 #include "table/pit-entry.hpp"
 #include "table/measurements-entry.hpp"
@@ -35,9 +34,11 @@
 namespace nfd {
 namespace name_tree {
 
+class Node;
+
 /** \brief an entry in the name tree
  */
-class Entry : public enable_shared_from_this<Entry>, noncopyable
+class Entry : noncopyable
 {
 public:
   Entry(const Name& prefix, Node* node);
@@ -151,6 +152,18 @@
   void
   setStrategyChoiceEntry(unique_ptr<strategy_choice::Entry> strategyChoiceEntry);
 
+  /** \return name tree entry on which a table entry is attached,
+   *          or nullptr if the table entry is detached
+   *  \note This function is for NameTree internal use. Other components
+   *        should use NameTree::getEntry(tableEntry) instead.
+   */
+  template<typename ENTRY>
+  static Entry*
+  get(const ENTRY& tableEntry)
+  {
+    return tableEntry.m_nameTreeEntry;
+  }
+
 private:
   Name m_name;
   Node* m_node;
diff --git a/daemon/table/name-tree-hashtable.cpp b/daemon/table/name-tree-hashtable.cpp
index 1267f99..67eafcd 100644
--- a/daemon/table/name-tree-hashtable.cpp
+++ b/daemon/table/name-tree-hashtable.cpp
@@ -24,7 +24,6 @@
  */
 
 #include "name-tree-hashtable.hpp"
-#include "name-tree-entry.hpp"
 #include "core/logger.hpp"
 #include "core/city-hash.hpp"
 
@@ -92,7 +91,7 @@
   : hash(h)
   , prev(nullptr)
   , next(nullptr)
-  , entry(make_shared<Entry>(name, this))
+  , entry(name, this)
 {
 }
 
@@ -182,7 +181,7 @@
   size_t bucket = this->computeBucketIndex(h);
 
   for (const Node* node = m_buckets[bucket]; node != nullptr; node = node->next) {
-    if (node->hash == h && name.compare(0, prefixLen, node->entry->getName()) == 0) {
+    if (node->hash == h && name.compare(0, prefixLen, node->entry.getName()) == 0) {
       NFD_LOG_TRACE("found " << name.getPrefix(prefixLen) << " hash=" << h << " bucket=" << bucket);
       return {node, false};
     }
@@ -195,7 +194,7 @@
 
   Node* node = new Node(h, name.getPrefix(prefixLen));
   this->attach(bucket, node);
-  NFD_LOG_TRACE("insert " << node->entry->getName() << " hash=" << h << " bucket=" << bucket);
+  NFD_LOG_TRACE("insert " << node->entry.getName() << " hash=" << h << " bucket=" << bucket);
   ++m_size;
 
   if (m_size > m_expandThreshold) {
@@ -230,10 +229,10 @@
 Hashtable::erase(Node* node)
 {
   BOOST_ASSERT(node != nullptr);
-  BOOST_ASSERT(node->entry->getParent() == nullptr);
+  BOOST_ASSERT(node->entry.getParent() == nullptr);
 
   size_t bucket = this->computeBucketIndex(node->hash);
-  NFD_LOG_TRACE("erase " << node->entry->getName() << " hash=" << node->hash << " bucket=" << bucket);
+  NFD_LOG_TRACE("erase " << node->entry.getName() << " hash=" << node->hash << " bucket=" << bucket);
 
   this->detach(bucket, node);
   delete node;
diff --git a/daemon/table/name-tree-hashtable.hpp b/daemon/table/name-tree-hashtable.hpp
index a9f0cfa..1ec2d55 100644
--- a/daemon/table/name-tree-hashtable.hpp
+++ b/daemon/table/name-tree-hashtable.hpp
@@ -26,7 +26,7 @@
 #ifndef NFD_DAEMON_TABLE_NAME_TREE_HASHTABLE_HPP
 #define NFD_DAEMON_TABLE_NAME_TREE_HASHTABLE_HPP
 
-#include "core/common.hpp"
+#include "name-tree-entry.hpp"
 
 namespace nfd {
 namespace name_tree {
@@ -61,10 +61,11 @@
  *  Zero or more nodes can be added to a hashtable bucket. They are organized as
  *  a doubly linked list through prev and next pointers.
  */
-class Node
+class Node : noncopyable
 {
 public:
-  /** \post entry != nullptr && entry->getName() == name
+  /** \post entry.getName() == name
+   *  \post getNode(entry) == this
    */
   Node(HashValue h, const Name& name);
 
@@ -74,10 +75,10 @@
   ~Node();
 
 public:
-  HashValue hash;
+  const HashValue hash;
   Node* prev;
   Node* next;
-  shared_ptr<Entry> entry; /// \todo #3687 make Node sole owner of Entry
+  mutable Entry entry;
 };
 
 /** \return node associated with entry
diff --git a/daemon/table/name-tree-iterator.cpp b/daemon/table/name-tree-iterator.cpp
index e62060a..8750867 100644
--- a/daemon/table/name-tree-iterator.cpp
+++ b/daemon/table/name-tree-iterator.cpp
@@ -121,7 +121,7 @@
     for (size_t bucket = 0; bucket < ht.getNBuckets(); ++bucket) {
       const Node* node = ht.getBucket(bucket);
       if (node != nullptr) {
-        i.m_entry = node->entry.get();
+        i.m_entry = &node->entry;
         break;
       }
     }
@@ -136,8 +136,8 @@
 
   // process entries in same bucket
   for (const Node* node = getNode(*i.m_entry)->next; node != nullptr; node = node->next) {
-    if (m_pred(*node->entry)) {
-      i.m_entry = node->entry.get();
+    if (m_pred(node->entry)) {
+      i.m_entry = &node->entry;
       return;
     }
   }
@@ -146,8 +146,8 @@
   size_t currentBucket = ht.computeBucketIndex(getNode(*i.m_entry)->hash);
   for (size_t bucket = currentBucket + 1; bucket < ht.getNBuckets(); ++bucket) {
     for (const Node* node = ht.getBucket(bucket); node != nullptr; node = node->next) {
-      if (m_pred(*node->entry)) {
-        i.m_entry = node->entry.get();
+      if (m_pred(node->entry)) {
+        i.m_entry = &node->entry;
         return;
       }
     }
diff --git a/daemon/table/name-tree-iterator.hpp b/daemon/table/name-tree-iterator.hpp
index f484440..ecde5bd 100644
--- a/daemon/table/name-tree-iterator.hpp
+++ b/daemon/table/name-tree-iterator.hpp
@@ -26,11 +26,13 @@
 #ifndef NFD_DAEMON_TABLE_NAME_TREE_ITERATOR_HPP
 #define NFD_DAEMON_TABLE_NAME_TREE_ITERATOR_HPP
 
-#include "name-tree-entry.hpp"
+#include "name-tree-hashtable.hpp"
 
 namespace nfd {
 namespace name_tree {
 
+class NameTree;
+
 /** \brief a predicate to accept or reject an Entry in find operations
  */
 typedef function<bool(const Entry& entry)> EntrySelector;
diff --git a/daemon/table/name-tree.cpp b/daemon/table/name-tree.cpp
index adff4b3..1550e3d 100644
--- a/daemon/table/name-tree.cpp
+++ b/daemon/table/name-tree.cpp
@@ -54,11 +54,11 @@
     std::tie(node, isNew) = m_ht.insert(name, prefixLen, hashes);
 
     if (isNew && parent != nullptr) {
-      node->entry->setParent(*parent);
+      node->entry.setParent(*parent);
     }
-    parent = node->entry.get();
+    parent = &node->entry;
   }
-  return *node->entry;
+  return node->entry;
 }
 
 Entry&
@@ -148,7 +148,7 @@
 NameTree::findExactMatch(const Name& name) const
 {
   const Node* node = m_ht.find(name, name.size());
-  return node == nullptr ? nullptr : node->entry.get();
+  return node == nullptr ? nullptr : &node->entry;
 }
 
 Entry*
@@ -158,8 +158,8 @@
 
   for (ssize_t prefixLen = name.size(); prefixLen >= 0; --prefixLen) {
     const Node* node = m_ht.find(name, prefixLen, hashes);
-    if (node != nullptr && entrySelector(*node->entry)) {
-      return node->entry.get();
+    if (node != nullptr && entrySelector(node->entry)) {
+      return &node->entry;
     }
   }
 
diff --git a/daemon/table/name-tree.hpp b/daemon/table/name-tree.hpp
index 8542873..0c24654 100644
--- a/daemon/table/name-tree.hpp
+++ b/daemon/table/name-tree.hpp
@@ -65,7 +65,7 @@
   Entry*
   getEntry(const ENTRY& tableEntry) const
   {
-    return tableEntry.m_nameTreeEntry.lock().get();
+    return Entry::get(tableEntry);
   }
 
 public: // mutation
diff --git a/daemon/table/pit-entry.cpp b/daemon/table/pit-entry.cpp
index 395fc90..522f4e2 100644
--- a/daemon/table/pit-entry.cpp
+++ b/daemon/table/pit-entry.cpp
@@ -31,6 +31,7 @@
 
 Entry::Entry(const Interest& interest)
   : m_interest(interest.shared_from_this())
+  , m_nameTreeEntry(nullptr)
 {
 }
 
diff --git a/daemon/table/pit-entry.hpp b/daemon/table/pit-entry.hpp
index 99832ad..d28cb90 100644
--- a/daemon/table/pit-entry.hpp
+++ b/daemon/table/pit-entry.hpp
@@ -33,10 +33,8 @@
 namespace nfd {
 
 namespace name_tree {
-class NameTree;
 class Entry;
 } // namespace name_tree
-using name_tree::NameTree;
 
 namespace pit {
 
@@ -68,18 +66,27 @@
    *  \todo #3162 require Link field to match the representative Interest
    */
   const Interest&
-  getInterest() const;
+  getInterest() const
+  {
+    return *m_interest;
+  }
 
   /** \return Interest Name
    */
   const Name&
-  getName() const;
+  getName() const
+  {
+    return m_interest->getName();
+  }
 
 public: // in-record
   /** \return collection of in-records
    */
   const InRecordCollection&
-  getInRecords() const;
+  getInRecords() const
+  {
+    return m_inRecords;
+  }
 
   /** \retval true There is at least one in-record.
    *               This implies some downstream is waiting for Data or Nack.
@@ -87,19 +94,34 @@
    *                This implies the entry is new or has been satisfied or Nacked.
    */
   bool
-  hasInRecords() const;
+  hasInRecords() const
+  {
+    return !m_inRecords.empty();
+  }
 
   InRecordCollection::iterator
-  in_begin();
+  in_begin()
+  {
+    return m_inRecords.begin();
+  }
 
   InRecordCollection::const_iterator
-  in_begin() const;
+  in_begin() const
+  {
+    return m_inRecords.begin();
+  }
 
   InRecordCollection::iterator
-  in_end();
+  in_end()
+  {
+    return m_inRecords.end();
+  }
 
   InRecordCollection::const_iterator
-  in_end() const;
+  in_end() const
+  {
+    return m_inRecords.end();
+  }
 
   /** \brief get the in-record for \p face
    *  \return an iterator to the in-record, or .in_end() if it does not exist
@@ -127,7 +149,10 @@
   /** \return collection of in-records
    */
   const OutRecordCollection&
-  getOutRecords() const;
+  getOutRecords() const
+  {
+    return m_outRecords;
+  }
 
   /** \retval true There is at least one out-record.
    *               This implies the Interest has been forwarded to some upstream,
@@ -136,19 +161,34 @@
    *                This implies the Interest has not been forwarded.
    */
   bool
-  hasOutRecords() const;
+  hasOutRecords() const
+  {
+    return !m_outRecords.empty();
+  }
 
   OutRecordCollection::iterator
-  out_begin();
+  out_begin()
+  {
+    return m_outRecords.begin();
+  }
 
   OutRecordCollection::const_iterator
-  out_begin() const;
+  out_begin() const
+  {
+    return m_outRecords.begin();
+  }
 
   OutRecordCollection::iterator
-  out_end();
+  out_end()
+  {
+    return m_outRecords.end();
+  }
 
   OutRecordCollection::const_iterator
-  out_end() const;
+  out_end() const
+  {
+    return m_outRecords.end();
+  }
 
   /** \brief get the out-record for \p face
    *  \return an iterator to the out-record, or .out_end() if it does not exist
@@ -194,96 +234,11 @@
   InRecordCollection m_inRecords;
   OutRecordCollection m_outRecords;
 
-  weak_ptr<name_tree::Entry> m_nameTreeEntry;
+  name_tree::Entry* m_nameTreeEntry;
 
-  friend class nfd::NameTree;
-  friend class nfd::name_tree::Entry;
+  friend class name_tree::Entry;
 };
 
-inline const Interest&
-Entry::getInterest() const
-{
-  return *m_interest;
-}
-
-inline const Name&
-Entry::getName() const
-{
-  return m_interest->getName();
-}
-
-inline const InRecordCollection&
-Entry::getInRecords() const
-{
-  return m_inRecords;
-}
-
-inline bool
-Entry::hasInRecords() const
-{
-  return !m_inRecords.empty();
-}
-
-inline InRecordCollection::iterator
-Entry::in_begin()
-{
-  return m_inRecords.begin();
-}
-
-inline InRecordCollection::const_iterator
-Entry::in_begin() const
-{
-  return m_inRecords.begin();
-}
-
-inline InRecordCollection::iterator
-Entry::in_end()
-{
-  return m_inRecords.end();
-}
-
-inline InRecordCollection::const_iterator
-Entry::in_end() const
-{
-  return m_inRecords.end();
-}
-
-inline const OutRecordCollection&
-Entry::getOutRecords() const
-{
-  return m_outRecords;
-}
-
-inline bool
-Entry::hasOutRecords() const
-{
-  return !m_outRecords.empty();
-}
-
-inline OutRecordCollection::iterator
-Entry::out_begin()
-{
-  return m_outRecords.begin();
-}
-
-inline OutRecordCollection::const_iterator
-Entry::out_begin() const
-{
-  return m_outRecords.begin();
-}
-
-inline OutRecordCollection::iterator
-Entry::out_end()
-{
-  return m_outRecords.end();
-}
-
-inline OutRecordCollection::const_iterator
-Entry::out_end() const
-{
-  return m_outRecords.end();
-}
-
 } // namespace pit
 } // namespace nfd
 
diff --git a/daemon/table/strategy-choice-entry.cpp b/daemon/table/strategy-choice-entry.cpp
index 2b7a257..365fd20 100644
--- a/daemon/table/strategy-choice-entry.cpp
+++ b/daemon/table/strategy-choice-entry.cpp
@@ -1,12 +1,12 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014,  Regents of the University of California,
- *                      Arizona Board of Regents,
- *                      Colorado State University,
- *                      University Pierre & Marie Curie, Sorbonne University,
- *                      Washington University in St. Louis,
- *                      Beijing Institute of Technology,
- *                      The University of Memphis
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
  *
  * This file is part of NFD (Named Data Networking Forwarding Daemon).
  * See AUTHORS.md for complete list of NFD authors and contributors.
@@ -21,7 +21,7 @@
  *
  * You should have received a copy of the GNU General Public License along with
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- **/
+ */
 
 #include "strategy-choice-entry.hpp"
 #include "core/logger.hpp"
@@ -33,6 +33,7 @@
 Entry::Entry(const Name& prefix)
   : m_prefix(prefix)
   , m_strategy(nullptr)
+  , m_nameTreeEntry(nullptr)
 {
 }
 
diff --git a/daemon/table/strategy-choice-entry.hpp b/daemon/table/strategy-choice-entry.hpp
index 3a21731..c63676b 100644
--- a/daemon/table/strategy-choice-entry.hpp
+++ b/daemon/table/strategy-choice-entry.hpp
@@ -33,11 +33,10 @@
 namespace fw {
 class Strategy;
 } // namespace fw
+
 namespace name_tree {
-class NameTree;
 class Entry;
 } // namespace name_tree
-using name_tree::NameTree;
 
 namespace strategy_choice {
 
@@ -49,46 +48,36 @@
   Entry(const Name& prefix);
 
   const Name&
-  getPrefix() const;
+  getPrefix() const
+  {
+    return m_prefix;
+  }
 
   const Name&
   getStrategyName() const;
 
   fw::Strategy&
-  getStrategy() const;
+  getStrategy() const
+  {
+    BOOST_ASSERT(m_strategy != nullptr);
+    return *m_strategy;
+  }
 
   void
-  setStrategy(fw::Strategy& strategy);
+  setStrategy(fw::Strategy& strategy)
+  {
+    m_strategy = &strategy;
+  }
 
 private:
   Name m_prefix;
   fw::Strategy* m_strategy;
 
-  weak_ptr<name_tree::Entry> m_nameTreeEntry;
-  friend class nfd::NameTree;
-  friend class nfd::name_tree::Entry;
+  name_tree::Entry* m_nameTreeEntry;
+
+  friend class name_tree::Entry;
 };
 
-
-inline const Name&
-Entry::getPrefix() const
-{
-  return m_prefix;
-}
-
-inline fw::Strategy&
-Entry::getStrategy() const
-{
-  BOOST_ASSERT(m_strategy != nullptr);
-  return *m_strategy;
-}
-
-inline void
-Entry::setStrategy(fw::Strategy& strategy)
-{
-  m_strategy = &strategy;
-}
-
 } // namespace strategy_choice
 } // namespace nfd
 
diff --git a/tests/daemon/table/name-tree.t.cpp b/tests/daemon/table/name-tree.t.cpp
index bf46022..a839152 100644
--- a/tests/daemon/table/name-tree.t.cpp
+++ b/tests/daemon/table/name-tree.t.cpp
@@ -181,62 +181,109 @@
 
 BOOST_AUTO_TEST_SUITE_END() // Hashtable
 
-BOOST_AUTO_TEST_CASE(NameTreeEntry)
+BOOST_AUTO_TEST_SUITE(TestEntry)
+
+BOOST_AUTO_TEST_CASE(TreeRelation)
 {
-  Name prefix("ndn:/named-data/research/abc/def/ghi");
+  Name name("ndn:/named-data/research/abc/def/ghi");
+  auto node = make_unique<Node>(0, name);
+  Entry& npe = node->entry;
+  BOOST_CHECK(npe.getParent() == nullptr);
 
-  auto node = make_unique<Node>(0, prefix);
-  shared_ptr<Entry> npe = node->entry;
-  BOOST_CHECK_EQUAL(npe->getName(), prefix);
-
-  // examine all the get methods
-
-  Entry* parent = npe->getParent();
-  BOOST_CHECK(parent == nullptr);
-
-  const std::vector<Entry*>& children = npe->getChildren();
-  BOOST_CHECK_EQUAL(children.size(), 0);
-
-  fib::Entry* fib = npe->getFibEntry();
-  BOOST_CHECK(fib == nullptr);
-
-  const std::vector<shared_ptr<pit::Entry>>& pitList = npe->getPitEntries();
-  BOOST_CHECK_EQUAL(pitList.size(), 0);
-
-  // examine all the set method
-
-  Name parentName("ndn:/named-data/research/abc/def");
+  Name parentName = name.getPrefix(-1);
   auto parentNode = make_unique<Node>(1, parentName);
-  npe->setParent(*parentNode->entry);
-  BOOST_CHECK_EQUAL(npe->getParent(), parentNode->entry.get());
+  Entry& parent = parentNode->entry;
+  BOOST_CHECK_EQUAL(parent.hasChildren(), false);
+  BOOST_CHECK_EQUAL(parent.isEmpty(), true);
 
-  // Insert FIB
+  npe.setParent(parentNode->entry);
+  BOOST_CHECK_EQUAL(npe.getParent(), &parent);
+  BOOST_CHECK_EQUAL(parent.hasChildren(), true);
+  BOOST_CHECK_EQUAL(parent.isEmpty(), false);
+  BOOST_REQUIRE_EQUAL(parent.getChildren().size(), 1);
+  BOOST_CHECK_EQUAL(parent.getChildren().front(), &npe);
 
-  npe->setFibEntry(make_unique<fib::Entry>(prefix));
-  BOOST_REQUIRE(npe->getFibEntry() != nullptr);
-  BOOST_CHECK_EQUAL(npe->getFibEntry()->getPrefix(), prefix);
-
-  npe->setFibEntry(nullptr);
-  BOOST_CHECK(npe->getFibEntry() == nullptr);
-
-  // Insert a PIT
-
-  auto pitEntry = make_shared<pit::Entry>(*makeInterest(prefix));
-  auto pitEntry2 = make_shared<pit::Entry>(*makeInterest(parentName));
-
-  npe->insertPitEntry(pitEntry);
-  BOOST_CHECK_EQUAL(npe->getPitEntries().size(), 1);
-
-  npe->insertPitEntry(pitEntry2);
-  BOOST_CHECK_EQUAL(npe->getPitEntries().size(), 2);
-
-  npe->erasePitEntry(pitEntry);
-  BOOST_CHECK_EQUAL(npe->getPitEntries().size(), 1);
-
-  npe->erasePitEntry(pitEntry2);
-  BOOST_CHECK_EQUAL(npe->getPitEntries().size(), 0);
+  npe.unsetParent();
+  BOOST_CHECK(npe.getParent() == nullptr);
+  BOOST_CHECK_EQUAL(parent.hasChildren(), false);
+  BOOST_CHECK_EQUAL(parent.isEmpty(), true);
 }
 
+BOOST_AUTO_TEST_CASE(TableEntries)
+{
+  Name name("ndn:/named-data/research/abc/def/ghi");
+  Node node(0, name);
+  Entry& npe = node.entry;
+  BOOST_CHECK_EQUAL(npe.getName(), name);
+
+  BOOST_CHECK_EQUAL(npe.hasTableEntries(), false);
+  BOOST_CHECK_EQUAL(npe.isEmpty(), true);
+  BOOST_CHECK(npe.getFibEntry() == nullptr);
+  BOOST_CHECK_EQUAL(npe.hasPitEntries(), false);
+  BOOST_CHECK_EQUAL(npe.getPitEntries().empty(), true);
+  BOOST_CHECK(npe.getMeasurementsEntry() == nullptr);
+  BOOST_CHECK(npe.getStrategyChoiceEntry() == nullptr);
+
+  npe.setFibEntry(make_unique<fib::Entry>(name));
+  BOOST_REQUIRE(npe.getFibEntry() != nullptr);
+  BOOST_CHECK_EQUAL(npe.getFibEntry()->getPrefix(), name);
+  BOOST_CHECK_EQUAL(npe.hasTableEntries(), true);
+  BOOST_CHECK_EQUAL(npe.isEmpty(), false);
+
+  npe.setFibEntry(nullptr);
+  BOOST_CHECK(npe.getFibEntry() == nullptr);
+  BOOST_CHECK_EQUAL(npe.hasTableEntries(), false);
+  BOOST_CHECK_EQUAL(npe.isEmpty(), true);
+
+  auto pit1 = make_shared<pit::Entry>(*makeInterest(name));
+  shared_ptr<Interest> interest2 = makeInterest(name);
+  interest2->setMinSuffixComponents(2);
+  auto pit2 = make_shared<pit::Entry>(*interest2);
+
+  npe.insertPitEntry(pit1);
+  BOOST_CHECK_EQUAL(npe.hasPitEntries(), true);
+  BOOST_CHECK_EQUAL(npe.getPitEntries().size(), 1);
+  BOOST_CHECK_EQUAL(npe.hasTableEntries(), true);
+  BOOST_CHECK_EQUAL(npe.isEmpty(), false);
+
+  npe.insertPitEntry(pit2);
+  BOOST_CHECK_EQUAL(npe.getPitEntries().size(), 2);
+
+  npe.erasePitEntry(pit1);
+  BOOST_REQUIRE_EQUAL(npe.getPitEntries().size(), 1);
+  BOOST_CHECK_EQUAL(npe.getPitEntries().front()->getInterest(), *interest2);
+
+  npe.erasePitEntry(pit2);
+  BOOST_CHECK_EQUAL(npe.hasPitEntries(), false);
+  BOOST_CHECK_EQUAL(npe.getPitEntries().size(), 0);
+  BOOST_CHECK_EQUAL(npe.hasTableEntries(), false);
+  BOOST_CHECK_EQUAL(npe.isEmpty(), true);
+
+  npe.setMeasurementsEntry(make_unique<measurements::Entry>(name));
+  BOOST_REQUIRE(npe.getMeasurementsEntry() != nullptr);
+  BOOST_CHECK_EQUAL(npe.getMeasurementsEntry()->getName(), name);
+  BOOST_CHECK_EQUAL(npe.hasTableEntries(), true);
+  BOOST_CHECK_EQUAL(npe.isEmpty(), false);
+
+  npe.setMeasurementsEntry(nullptr);
+  BOOST_CHECK(npe.getMeasurementsEntry() == nullptr);
+  BOOST_CHECK_EQUAL(npe.hasTableEntries(), false);
+  BOOST_CHECK_EQUAL(npe.isEmpty(), true);
+
+  npe.setStrategyChoiceEntry(make_unique<strategy_choice::Entry>(name));
+  BOOST_REQUIRE(npe.getStrategyChoiceEntry() != nullptr);
+  BOOST_CHECK_EQUAL(npe.getStrategyChoiceEntry()->getPrefix(), name);
+  BOOST_CHECK_EQUAL(npe.hasTableEntries(), true);
+  BOOST_CHECK_EQUAL(npe.isEmpty(), false);
+
+  npe.setStrategyChoiceEntry(nullptr);
+  BOOST_CHECK(npe.getStrategyChoiceEntry() == nullptr);
+  BOOST_CHECK_EQUAL(npe.hasTableEntries(), false);
+  BOOST_CHECK_EQUAL(npe.isEmpty(), true);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestEntry
+
 BOOST_AUTO_TEST_CASE(Basic)
 {
   size_t nBuckets = 16;