table: mock PIT

refs #1128

Change-Id: I8943ad07d93422dc456fd051b2e4c0d5f38bc227
diff --git a/daemon/table/pit-entry.cpp b/daemon/table/pit-entry.cpp
new file mode 100644
index 0000000..e11abef
--- /dev/null
+++ b/daemon/table/pit-entry.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "pit-entry.hpp"
+#include <algorithm>
+
+namespace ndn {
+namespace pit {
+
+Entry::Entry(const Interest& interest)
+  : m_interest(interest)
+{
+}
+
+const Name&
+Entry::getName() const
+{
+  return m_interest.getName();
+}
+
+const InRecordCollection&
+Entry::getInRecords() const
+{
+  return m_inRecords;
+}
+
+const OutRecordCollection&
+Entry::getOutRecords() const
+{
+  return m_outRecords;
+}
+
+bool
+Entry::isNonceSeen(uint32_t nonce) const
+{
+  return m_nonces.count(nonce) > 0;
+}
+
+static inline bool
+predicate_FaceRecord_Face(const FaceRecord& faceRecord, shared_ptr<Face> face)
+{
+  return faceRecord.getFace() == face;
+}
+
+InRecordCollection::iterator
+Entry::insertOrUpdateInRecord(shared_ptr<Face> face, const Interest& interest)
+{
+  InRecordCollection::iterator it = std::find_if(m_inRecords.begin(),
+    m_inRecords.end(), bind(&predicate_FaceRecord_Face, _1, face));
+  if (it == m_inRecords.end()) {
+    m_inRecords.push_front(InRecord(face));
+    it = m_inRecords.begin();
+  }
+  
+  it->update(interest);
+  m_nonces.insert(interest.getNonce());
+  return it;
+}
+
+void
+Entry::deleteInRecords()
+{
+  m_inRecords.clear();
+}
+
+OutRecordCollection::iterator
+Entry::insertOrUpdateOutRecord(shared_ptr<Face> face, const Interest& interest)
+{
+  OutRecordCollection::iterator it = std::find_if(m_outRecords.begin(),
+    m_outRecords.end(), bind(&predicate_FaceRecord_Face, _1, face));
+  if (it == m_outRecords.end()) {
+    m_outRecords.push_front(OutRecord(face));
+    it = m_outRecords.begin();
+  }
+  
+  it->update(interest);
+  m_nonces.insert(interest.getNonce());
+  return it;
+}
+
+void
+Entry::deleteOutRecord(shared_ptr<Face> face)
+{
+  OutRecordCollection::iterator it = std::find_if(m_outRecords.begin(),
+    m_outRecords.end(), bind(&predicate_FaceRecord_Face, _1, face));
+  if (it != m_outRecords.end()) {
+    m_outRecords.erase(it);
+  }
+}
+
+
+} // namespace pit
+} // namespace ndn
diff --git a/daemon/table/pit-entry.hpp b/daemon/table/pit-entry.hpp
new file mode 100644
index 0000000..97de5e2
--- /dev/null
+++ b/daemon/table/pit-entry.hpp
@@ -0,0 +1,93 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TABLE_PIT_ENTRY_HPP
+#define NFD_TABLE_PIT_ENTRY_HPP
+
+#include "pit-in-record.hpp"
+#include "pit-out-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+/** \class InRecordCollection
+ *  \brief represents an unordered collection of InRecords
+ */
+typedef std::list< InRecord>  InRecordCollection;
+
+/** \class OutRecordCollection
+ *  \brief represents an unordered collection of OutRecords
+ */
+typedef std::list<OutRecord> OutRecordCollection;
+
+/** \class Entry
+ *  \brief represents a PIT entry
+ */
+class Entry : noncopyable
+{
+public:
+  explicit
+  Entry(const Interest& interest);
+  
+  const Interest&
+  getInterest() const;
+  
+  /** \return{ Interest Name }
+   */
+  const Name&
+  getName() const;
+  
+  const InRecordCollection&
+  getInRecords() const;
+  
+  const OutRecordCollection&
+  getOutRecords() const;
+  
+  /** \brief determines whether nonce is seen before
+   *         in an incoming or outgoing Interest
+   */
+  bool
+  isNonceSeen(uint32_t nonce) const;
+  
+  /** \brief inserts a InRecord for face, and updates it with interest
+   *  If InRecord for face exists, the existing one is updated.
+   *  \return{ an iterator to the InRecord }
+   */
+  InRecordCollection::iterator
+  insertOrUpdateInRecord(shared_ptr<Face> face, const Interest& interest);
+  
+  /// deletes all InRecords
+  void
+  deleteInRecords();
+  
+  /** \brief inserts a OutRecord for face, and updates it with interest
+   *  If OutRecord for face exists, the existing one is updated.
+   *  \return{ an iterator to the OutRecord }
+   */
+  OutRecordCollection::iterator
+  insertOrUpdateOutRecord(shared_ptr<Face> face, const Interest& interest);
+  
+  /// deletes one OutRecord for face if exists
+  void
+  deleteOutRecord(shared_ptr<Face> face);
+
+private:
+  std::set<uint32_t> m_nonces;
+  const Interest m_interest;
+  InRecordCollection m_inRecords;
+  OutRecordCollection m_outRecords;
+};
+
+inline const Interest&
+Entry::getInterest() const
+{
+  return m_interest;
+}
+
+} // namespace pit
+} // namespace ndn
+
+#endif // NFD_TABLE_PIT_ENTRY_HPP
diff --git a/daemon/table/pit-face-record.cpp b/daemon/table/pit-face-record.cpp
new file mode 100644
index 0000000..89aef1e
--- /dev/null
+++ b/daemon/table/pit-face-record.cpp
@@ -0,0 +1,38 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "pit-face-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+FaceRecord::FaceRecord(shared_ptr<Face> face)
+  : m_face(face)
+  , m_lastNonce(0)
+  , m_lastRenewed(0)
+  , m_expiry(0)
+{
+}
+
+FaceRecord::FaceRecord(const FaceRecord& other)
+  : m_face(other.m_face)
+  , m_lastNonce(other.m_lastNonce)
+  , m_lastRenewed(other.m_lastRenewed)
+  , m_expiry(other.m_expiry)
+{
+}
+
+void
+FaceRecord::update(const Interest& interest)
+{
+  m_lastNonce = interest.getNonce();
+  m_lastRenewed = time::now();
+  m_expiry = m_lastRenewed + time::milliseconds(interest.getInterestLifetime());
+}
+
+
+} // namespace pit
+} // namespace ndn
diff --git a/daemon/table/pit-face-record.hpp b/daemon/table/pit-face-record.hpp
new file mode 100644
index 0000000..d2dfe2c
--- /dev/null
+++ b/daemon/table/pit-face-record.hpp
@@ -0,0 +1,83 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TABLE_PIT_FACE_RECORD_HPP
+#define NFD_TABLE_PIT_FACE_RECORD_HPP
+
+#include "face/face.hpp"
+#include "core/time.hpp"
+
+namespace ndn {
+namespace pit {
+
+/** \class FaceRecord
+ *  \brief contains information about an Interest
+ *         on an incoming or outgoing face
+ *  \note This is an implementation detail to extract common functionality
+ *        of InRecord and OutRecord
+ */
+class FaceRecord
+{
+public:
+  explicit
+  FaceRecord(shared_ptr<Face> face);
+  
+  FaceRecord(const FaceRecord& other);
+  
+  shared_ptr<Face>
+  getFace() const;
+  
+  uint32_t
+  getLastNonce() const;
+  
+  time::Point
+  getLastRenewed() const;
+  
+  /** \brief gives the time point this record expires
+   *  \return{ getLastRenewed() + InterestLifetime }
+   */
+  time::Point
+  getExpiry() const;
+
+  /// updates lastNonce, lastRenewed, expiry fields
+  void
+  update(const Interest& interest);
+
+private:
+  shared_ptr<Face> m_face;
+  uint32_t m_lastNonce;
+  time::Point m_lastRenewed;
+  time::Point m_expiry;
+};
+
+inline shared_ptr<Face>
+FaceRecord::getFace() const
+{
+  return m_face;
+}
+
+inline uint32_t
+FaceRecord::getLastNonce() const
+{
+  return m_lastNonce;
+}
+
+inline time::Point
+FaceRecord::getLastRenewed() const
+{
+  return m_lastRenewed;
+}
+
+inline time::Point
+FaceRecord::getExpiry() const
+{
+  return m_expiry;
+}
+
+} // namespace pit
+} // namespace ndn
+
+#endif // NFD_TABLE_PIT_FACE_RECORD_HPP
diff --git a/daemon/table/pit-in-record.cpp b/daemon/table/pit-in-record.cpp
new file mode 100644
index 0000000..662f074
--- /dev/null
+++ b/daemon/table/pit-in-record.cpp
@@ -0,0 +1,24 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "pit-in-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+InRecord::InRecord(shared_ptr<Face> face)
+  : FaceRecord(face)
+{
+}
+
+InRecord::InRecord(const InRecord& other)
+  : FaceRecord(other)
+{
+}
+
+
+} // namespace pit
+} // namespace ndn
diff --git a/daemon/table/pit-in-record.hpp b/daemon/table/pit-in-record.hpp
new file mode 100644
index 0000000..9539ce3
--- /dev/null
+++ b/daemon/table/pit-in-record.hpp
@@ -0,0 +1,30 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TABLE_PIT_IN_RECORD_HPP
+#define NFD_TABLE_PIT_IN_RECORD_HPP
+
+#include "pit-face-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+/** \class InRecord
+ *  \brief contains information about an Interest from an incoming face
+ */
+class InRecord : public FaceRecord
+{
+public:
+  explicit
+  InRecord(shared_ptr<Face> face);
+  
+  InRecord(const InRecord& other);
+};
+
+} // namespace pit
+} // namespace ndn
+
+#endif // NFD_TABLE_PIT_IN_RECORD_HPP
diff --git a/daemon/table/pit-out-record.cpp b/daemon/table/pit-out-record.cpp
new file mode 100644
index 0000000..ce4db8c
--- /dev/null
+++ b/daemon/table/pit-out-record.cpp
@@ -0,0 +1,23 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "pit-out-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+OutRecord::OutRecord(shared_ptr<Face> face)
+  : FaceRecord(face)
+{
+}
+
+OutRecord::OutRecord(const OutRecord& other)
+  : FaceRecord(other)
+{
+}
+
+} // namespace pit
+} // namespace ndn
diff --git a/daemon/table/pit-out-record.hpp b/daemon/table/pit-out-record.hpp
new file mode 100644
index 0000000..83ff3e1
--- /dev/null
+++ b/daemon/table/pit-out-record.hpp
@@ -0,0 +1,30 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TABLE_PIT_OUT_RECORD_HPP
+#define NFD_TABLE_PIT_OUT_RECORD_HPP
+
+#include "pit-face-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+/** \class OutRecord
+ *  \brief contains information about an Interest toward an outgoing face
+ */
+class OutRecord : public FaceRecord
+{
+public:
+  explicit
+  OutRecord(shared_ptr<Face> face);
+  
+  OutRecord(const OutRecord& other);
+};
+
+} // namespace pit
+} // namespace ndn
+
+#endif // NFD_TABLE_PIT_IN_RECORD_HPP
diff --git a/daemon/table/pit.cpp b/daemon/table/pit.cpp
new file mode 100644
index 0000000..7742266
--- /dev/null
+++ b/daemon/table/pit.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "pit.hpp"
+#include <algorithm>
+
+namespace ndn {
+
+Pit::Pit()
+{
+}
+
+Pit::~Pit()
+{
+}
+
+static inline bool
+operator==(const Exclude& a, const Exclude& b)
+{
+  const Block& aBlock = a.wireEncode();
+  const Block& bBlock = b.wireEncode();
+  return aBlock.size() == bBlock.size() &&
+         0 == memcmp(aBlock.wire(), bBlock.wire(), aBlock.size());
+}
+
+static inline bool
+predicate_PitEntry_similar_Interest(shared_ptr<pit::Entry> entry,
+                                    const Interest& interest)
+{
+  const Interest& pi = entry->getInterest();
+  return pi.getName().equals(interest.getName()) &&
+         pi.getMinSuffixComponents() == interest.getMinSuffixComponents() &&
+         pi.getMaxSuffixComponents() == interest.getMaxSuffixComponents() &&
+         // TODO PublisherPublicKeyLocator (ndn-cpp-dev #1157)
+         pi.getExclude() == interest.getExclude() &&
+         pi.getChildSelector() == interest.getChildSelector() &&
+         pi.getMustBeFresh() == interest.getMustBeFresh();
+}
+
+std::pair<shared_ptr<pit::Entry>, bool>
+Pit::insert(const Interest& interest)
+{
+  std::list<shared_ptr<pit::Entry> >::iterator it = std::find_if(
+    m_table.begin(), m_table.end(),
+    bind(&predicate_PitEntry_similar_Interest, _1, interest));
+  if (it != m_table.end()) return std::make_pair(*it, false);
+  
+  shared_ptr<pit::Entry> entry = make_shared<pit::Entry>(interest);
+  m_table.push_back(entry);
+  return std::make_pair(entry, true);
+}
+
+shared_ptr<pit::DataMatchResult>
+Pit::findAllDataMatches(const Data& data) const
+{
+  shared_ptr<pit::DataMatchResult> result = make_shared<pit::DataMatchResult>();
+  for (std::list<shared_ptr<pit::Entry> >::const_iterator it = m_table.begin();
+       it != m_table.end(); ++it) {
+    shared_ptr<pit::Entry> entry = *it;
+    if (entry->getInterest().matchesName(data.getName())) {
+      result->push_back(entry);
+    }
+  }
+  return result;
+}
+
+void
+Pit::remove(shared_ptr<pit::Entry> pitEntry)
+{
+  m_table.remove(pitEntry);
+}
+
+} // namespace ndn
diff --git a/daemon/table/pit.hpp b/daemon/table/pit.hpp
new file mode 100644
index 0000000..44dc252
--- /dev/null
+++ b/daemon/table/pit.hpp
@@ -0,0 +1,57 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TABLE_PIT_HPP
+#define NFD_TABLE_PIT_HPP
+
+#include "pit-entry.hpp"
+namespace ndn {
+namespace pit {
+
+/** \class DataMatchResult
+ *  \brief an unordered iterable of all PIT entries matching Data
+ *  This type shall support:
+ *    iterator<shared_ptr<pit::Entry>> begin()
+ *    iterator<shared_ptr<pit::Entry>> end()
+ */
+typedef std::vector<shared_ptr<pit::Entry> > DataMatchResult;
+
+} // namespace pit
+
+/** \class Pit
+ *  \brief represents the PIT
+ */
+class Pit : noncopyable
+{
+public:
+  Pit();
+  
+  ~Pit();
+  
+  /** \brief inserts a FIB entry for prefix
+   *  If an entry for exact same prefix exists, that entry is returned.
+   *  \return{ the entry, and true for new entry, false for existing entry }
+   */
+  std::pair<shared_ptr<pit::Entry>, bool>
+  insert(const Interest& interest);
+  
+  /** \brief performs a Data match
+   *  \return{ an iterable of all PIT entries matching data }
+   */
+  shared_ptr<pit::DataMatchResult>
+  findAllDataMatches(const Data& data) const;
+  
+  /// removes a PIT entry
+  void
+  remove(shared_ptr<pit::Entry> pitEntry);
+
+private:
+  std::list<shared_ptr<pit::Entry> > m_table;
+};
+
+} // namespace ndn
+
+#endif // NFD_TABLE_PIT_HPP