table: FIB enumeration

refs #1315

Change-Id: I535d519836720c40f72904e5520d11026ea30a33
diff --git a/daemon/table/fib.cpp b/daemon/table/fib.cpp
index 940f604..30d20e6 100644
--- a/daemon/table/fib.cpp
+++ b/daemon/table/fib.cpp
@@ -130,4 +130,10 @@
   }
 }
 
+Fib::const_iterator
+Fib::begin() const
+{
+  return const_iterator(m_nameTree.fullEnumerate(&predicate_NameTreeEntry_hasFibEntry));
+}
+
 } // namespace nfd
diff --git a/daemon/table/fib.hpp b/daemon/table/fib.hpp
index e1e5c5a..93741d8 100644
--- a/daemon/table/fib.hpp
+++ b/daemon/table/fib.hpp
@@ -25,6 +25,8 @@
 class Fib : noncopyable
 {
 public:
+  class const_iterator;
+
   explicit
   Fib(NameTree& nameTree);
 
@@ -68,6 +70,42 @@
   size_t
   size() const;
 
+  const_iterator
+  begin() const;
+
+  const_iterator
+  end() const;
+
+  class const_iterator : public std::iterator<std::forward_iterator_tag, fib::Entry>
+  {
+  public:
+    explicit
+    const_iterator(const NameTree::const_iterator& it);
+
+    ~const_iterator();
+
+    const fib::Entry&
+    operator*() const;
+
+    shared_ptr<fib::Entry>
+    operator->() const;
+
+    const_iterator&
+    operator++();
+
+    const_iterator
+    operator++(int);
+
+    bool
+    operator==(const const_iterator& other) const;
+
+    bool
+    operator!=(const const_iterator& other) const;
+
+  private:
+    NameTree::const_iterator m_nameTreeIterator;
+  };
+
 private:
   shared_ptr<fib::Entry>
   findLongestPrefixMatch(shared_ptr<name_tree::Entry> nameTreeEntry) const;
@@ -91,6 +129,63 @@
   return m_nItems;
 }
 
+inline Fib::const_iterator
+Fib::end() const
+{
+  return const_iterator(m_nameTree.end());
+}
+
+inline
+Fib::const_iterator::const_iterator(const NameTree::const_iterator& it)
+  : m_nameTreeIterator(it)
+{
+}
+
+inline
+Fib::const_iterator::~const_iterator()
+{
+}
+
+inline
+Fib::const_iterator
+Fib::const_iterator::operator++(int)
+{
+  Fib::const_iterator temp(*this);
+  ++(*this);
+  return temp;
+}
+
+inline Fib::const_iterator&
+Fib::const_iterator::operator++()
+{
+  ++m_nameTreeIterator;
+  return *this;
+}
+
+inline const fib::Entry&
+Fib::const_iterator::operator*() const
+{
+  return *(m_nameTreeIterator->getFibEntry());
+}
+
+inline shared_ptr<fib::Entry>
+Fib::const_iterator::operator->() const
+{
+  return m_nameTreeIterator->getFibEntry();
+}
+
+inline bool
+Fib::const_iterator::operator==(const Fib::const_iterator& other) const
+{
+  return m_nameTreeIterator == other.m_nameTreeIterator;
+}
+
+inline bool
+Fib::const_iterator::operator!=(const Fib::const_iterator& other) const
+{
+  return m_nameTreeIterator != other.m_nameTreeIterator;
+}
+
 } // namespace nfd
 
 #endif // NFD_TABLE_FIB_HPP
diff --git a/tests/table/fib.cpp b/tests/table/fib.cpp
index cc80bba..a86d5ad 100644
--- a/tests/table/fib.cpp
+++ b/tests/table/fib.cpp
@@ -327,6 +327,36 @@
   validateFindExactMatch(gapFib, "/X/Y/Z");
 }
 
+BOOST_AUTO_TEST_CASE(Iterator)
+{
+  NameTree nameTree(1024);
+  Fib fib(nameTree);
+  Name nameA("/A");
+  Name nameAB("/A/B");
+  Name nameABC("/A/B/C");
+  Name nameRoot("/");
+
+  fib.insert(nameA);
+  fib.insert(nameAB);
+  fib.insert(nameABC);
+  fib.insert(nameRoot);
+
+  std::set<Name> expected;
+  expected.insert(nameA);
+  expected.insert(nameAB);
+  expected.insert(nameABC);
+  expected.insert(nameRoot);
+
+  for (Fib::const_iterator it = fib.begin(); it != fib.end(); it++)
+  {
+    bool isInSet = expected.find(it->getPrefix()) != expected.end();
+    BOOST_CHECK(isInSet);
+    expected.erase(it->getPrefix());
+  }
+
+  BOOST_CHECK_EQUAL(expected.size(), 0);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace tests