chunks: move getNextSegmentNo() to PipelineInterests base class

This hides the "excluded segment" logic from subclasses and
reduces code duplication.

Change-Id: I9f7b5b88e6010e4e16a0876e79fc2ecb9ff8dc00
diff --git a/tools/chunks/catchunks/pipeline-interests-aimd.cpp b/tools/chunks/catchunks/pipeline-interests-aimd.cpp
index 2e3da09..3b35001 100644
--- a/tools/chunks/catchunks/pipeline-interests-aimd.cpp
+++ b/tools/chunks/catchunks/pipeline-interests-aimd.cpp
@@ -40,7 +40,6 @@
   , m_rttEstimator(rttEstimator)
   , m_scheduler(m_face.getIoService())
   , m_checkRtoEvent(m_scheduler)
-  , m_nextSegmentNo(0)
   , m_highData(0)
   , m_highInterest(0)
   , m_recPoint(0)
@@ -394,15 +393,6 @@
   afterCwndChange(time::steady_clock::now() - getStartTime(), m_cwnd);
 }
 
-uint64_t
-PipelineInterestsAimd::getNextSegmentNo()
-{
-  // get around the excluded segment
-  if (m_nextSegmentNo == m_excludedSegmentNo)
-    m_nextSegmentNo++;
-  return m_nextSegmentNo++;
-}
-
 void
 PipelineInterestsAimd::cancelInFlightSegmentsGreaterThan(uint64_t segNo)
 {
diff --git a/tools/chunks/catchunks/pipeline-interests-aimd.hpp b/tools/chunks/catchunks/pipeline-interests-aimd.hpp
index 3248100..5aedbfb 100644
--- a/tools/chunks/catchunks/pipeline-interests-aimd.hpp
+++ b/tools/chunks/catchunks/pipeline-interests-aimd.hpp
@@ -122,9 +122,8 @@
   /**
    * @brief fetch all the segments between 0 and lastSegment of the specified prefix
    *
-   * Starts the pipeline with an AIMD algorithm to control the window size. The pipeline will fetch
-   * every segment until the last segment is successfully received or an error occurs.
-   * The segment with segment number equal to m_excludedSegmentNo will not be fetched.
+   * Starts the pipeline with an AIMD algorithm to control the window size. The pipeline will
+   * fetch every segment until the last segment is successfully received or an error occurs.
    */
   void
   doRun() final;
@@ -181,12 +180,6 @@
   void
   decreaseWindow();
 
-  /** \return next segment number to retrieve
-   *  \post m_nextSegmentNo == return-value + 1
-   */
-  uint64_t
-  getNextSegmentNo();
-
   void
   cancelInFlightSegmentsGreaterThan(uint64_t segNo);
 
@@ -199,8 +192,6 @@
   Scheduler m_scheduler;
   scheduler::ScopedEventId m_checkRtoEvent;
 
-  uint64_t m_nextSegmentNo;
-
   uint64_t m_highData; ///< the highest segment number of the Data packet the consumer has received so far
   uint64_t m_highInterest; ///< the highest segment number of the Interests the consumer has sent so far
   uint64_t m_recPoint; ///< the value of m_highInterest when a packet loss event occurred,
diff --git a/tools/chunks/catchunks/pipeline-interests-fixed-window.cpp b/tools/chunks/catchunks/pipeline-interests-fixed-window.cpp
index 04cbf03..b81ec97 100644
--- a/tools/chunks/catchunks/pipeline-interests-fixed-window.cpp
+++ b/tools/chunks/catchunks/pipeline-interests-fixed-window.cpp
@@ -36,7 +36,6 @@
 PipelineInterestsFixedWindow::PipelineInterestsFixedWindow(Face& face, const Options& options)
   : PipelineInterests(face)
   , m_options(options)
-  , m_nextSegmentNo(0)
   , m_hasFailure(false)
 {
   m_segmentFetchers.resize(m_options.maxPipelineSize);
@@ -71,17 +70,15 @@
     return false;
   }
 
-  if (m_nextSegmentNo == m_excludedSegmentNo)
-    m_nextSegmentNo++;
-
-  if (m_hasFinalBlockId && m_nextSegmentNo > m_lastSegmentNo)
-   return false;
+  uint64_t nextSegmentNo = getNextSegmentNo();
+  if (m_hasFinalBlockId && nextSegmentNo > m_lastSegmentNo)
+    return false;
 
   // send interest for next segment
   if (m_options.isVerbose)
-    std::cerr << "Requesting segment #" << m_nextSegmentNo << std::endl;
+    std::cerr << "Requesting segment #" << nextSegmentNo << std::endl;
 
-  Interest interest(Name(m_prefix).appendSegment(m_nextSegmentNo));
+  Interest interest(Name(m_prefix).appendSegment(nextSegmentNo));
   interest.setInterestLifetime(m_options.interestLifetime);
   interest.setMustBeFresh(m_options.mustBeFresh);
   interest.setMaxSuffixComponents(1);
@@ -95,8 +92,7 @@
                                     m_options.isVerbose);
 
   BOOST_ASSERT(!m_segmentFetchers[pipeNo].first || !m_segmentFetchers[pipeNo].first->isRunning());
-  m_segmentFetchers[pipeNo] = make_pair(fetcher, m_nextSegmentNo);
-  m_nextSegmentNo++;
+  m_segmentFetchers[pipeNo] = make_pair(fetcher, nextSegmentNo);
 
   return true;
 }
diff --git a/tools/chunks/catchunks/pipeline-interests-fixed-window.hpp b/tools/chunks/catchunks/pipeline-interests-fixed-window.hpp
index 81b7d72..22f1a4b 100644
--- a/tools/chunks/catchunks/pipeline-interests-fixed-window.hpp
+++ b/tools/chunks/catchunks/pipeline-interests-fixed-window.hpp
@@ -85,7 +85,6 @@
    *
    * Starts a fixed-window pipeline with size equal to m_options.maxPipelineSize. The pipeline
    * will fetch every segment until the last segment is successfully received or an error occurs.
-   * The segment with segment number equal to m_excludedSegmentNo will not be fetched.
    */
   void
   doRun() final;
@@ -110,7 +109,7 @@
 private:
   const Options m_options;
   std::vector<std::pair<shared_ptr<DataFetcher>, uint64_t>> m_segmentFetchers;
-  uint64_t m_nextSegmentNo;
+
   /**
    * true if one or more segment fetchers encountered an error; if m_hasFinalBlockId
    * is false, this is usually not a fatal error for the pipeline
diff --git a/tools/chunks/catchunks/pipeline-interests.cpp b/tools/chunks/catchunks/pipeline-interests.cpp
index 965492f..c0512cc 100644
--- a/tools/chunks/catchunks/pipeline-interests.cpp
+++ b/tools/chunks/catchunks/pipeline-interests.cpp
@@ -36,10 +36,11 @@
 PipelineInterests::PipelineInterests(Face& face)
   : m_face(face)
   , m_lastSegmentNo(0)
-  , m_excludedSegmentNo(0)
-  , m_receivedSize(0)
   , m_nReceived(0)
+  , m_receivedSize(0)
   , m_hasFinalBlockId(false)
+  , m_nextSegmentNo(0)
+  , m_excludedSegmentNo(0)
   , m_isStopping(false)
 {
 }
@@ -78,6 +79,16 @@
   doCancel();
 }
 
+uint64_t
+PipelineInterests::getNextSegmentNo()
+{
+  // skip the excluded segment
+  if (m_nextSegmentNo == m_excludedSegmentNo)
+    m_nextSegmentNo++;
+
+  return m_nextSegmentNo++;
+}
+
 void
 PipelineInterests::onFailure(const std::string& reason)
 {
@@ -116,8 +127,8 @@
 void
 PipelineInterests::printSummary() const
 {
-  typedef time::duration<double, time::milliseconds::period> Milliseconds;
-  Milliseconds timeElapsed = time::steady_clock::now() - getStartTime();
+  using namespace ndn::time;
+  duration<double, milliseconds::period> timeElapsed = steady_clock::now() - getStartTime();
   double throughput = (8 * m_receivedSize * 1000) / timeElapsed.count();
 
   std::cerr << "\nAll segments have been received.\n"
diff --git a/tools/chunks/catchunks/pipeline-interests.hpp b/tools/chunks/catchunks/pipeline-interests.hpp
index d806d1b..c8e14fe 100644
--- a/tools/chunks/catchunks/pipeline-interests.hpp
+++ b/tools/chunks/catchunks/pipeline-interests.hpp
@@ -93,6 +93,13 @@
     return m_isStopping;
   }
 
+  /**
+   * @return next segment number to retrieve
+   * @post m_nextSegmentNo == return-value + 1
+   */
+  uint64_t
+  getNextSegmentNo();
+
   void
   onData(const Interest& interest, const Data& data) const
   {
@@ -106,26 +113,26 @@
   onFailure(const std::string& reason);
 
   /**
+   * @brief print statistics about this fetching session
+   *
+   * Subclasses can override this method to print additional stats or change the summary format
+   */
+  virtual void
+  printSummary() const;
+
+  /**
    * @param throughput The throughput in bits/s
    */
   static std::string
   formatThroughput(double throughput);
 
-  /**
-   * @brief print statistics about quality of packet delivery
-   *
-   * This method should be overriden by each pipeline (e.g. AIMD)
-   */
-  virtual void
-  printSummary() const;
-
 private:
   /**
    * @brief perform subclass-specific operations to fetch all the segments
    *
    * When overriding this function, at a minimum, the subclass should implement the retrieving
-   * of all the segments. Segment m_excludedSegmentNo can be skipped. Subclass must guarantee
-   * that onData is called at least once for every segment that is fetched successfully.
+   * of all the segments. Subclass must guarantee that onData is called at least once for every
+   * segment that is fetched successfully.
    *
    * @note m_lastSegmentNo contains a valid value only if m_hasFinalBlockId is true.
    */
@@ -138,11 +145,9 @@
 protected:
   Face& m_face;
   Name m_prefix;
-  uint64_t m_lastSegmentNo;
-  uint64_t m_excludedSegmentNo;
-
-  size_t m_receivedSize;  ///< size of received data in bytes
+  uint64_t m_lastSegmentNo; ///< valid only if m_hasFinalBlockId == true
   int64_t m_nReceived; ///< number of segments received
+  size_t m_receivedSize; ///< size of received data in bytes
 
 PUBLIC_WITH_TESTS_ELSE_PROTECTED:
   bool m_hasFinalBlockId; ///< true if the last segment number is known
@@ -150,6 +155,8 @@
 private:
   DataCallback m_onData;
   FailureCallback m_onFailure;
+  uint64_t m_nextSegmentNo;
+  uint64_t m_excludedSegmentNo;
   time::steady_clock::TimePoint m_startTime;
   bool m_isStopping;
 };