partial-producer: gather constructor args into Options struct

refs #5069

Change-Id: I9ac66d8c42be4fcfebbd718eeeb50a9009d75c54
diff --git a/PSync/consumer.cpp b/PSync/consumer.cpp
index 82408a9..bc77a05 100644
--- a/PSync/consumer.cpp
+++ b/PSync/consumer.cpp
@@ -53,7 +53,8 @@
                    ndn::time::milliseconds helloInterestLifetime,
                    ndn::time::milliseconds syncInterestLifetime)
   : Consumer(face, syncPrefix,
-             Options{onReceiveHelloData, onUpdate, count, falsePositive, helloInterestLifetime, syncInterestLifetime})
+             Options{onReceiveHelloData, onUpdate, static_cast<uint32_t>(count), falsePositive,
+                     helloInterestLifetime, syncInterestLifetime})
 {
 }
 
diff --git a/PSync/consumer.hpp b/PSync/consumer.hpp
index ed5174b..7d7995d 100644
--- a/PSync/consumer.hpp
+++ b/PSync/consumer.hpp
@@ -65,7 +65,7 @@
     /// Callback to give sync data back to application.
     UpdateCallback onUpdate = [] (const auto&) {};
     /// Number of expected elements (subscriptions) in Bloom filter.
-    unsigned int bfCount = 80;
+    uint32_t bfCount = 80;
     /// Bloom filter false positive probability.
     double bfFalsePositive = 0.001;
     /// Lifetime of hello Interest.
diff --git a/PSync/full-producer.cpp b/PSync/full-producer.cpp
index 4f4c056..fa11120 100644
--- a/PSync/full-producer.cpp
+++ b/PSync/full-producer.cpp
@@ -41,11 +41,13 @@
                            ndn::time::milliseconds syncReplyFreshness,
                            CompressionScheme ibltCompression,
                            CompressionScheme contentCompression)
-  : ProducerBase(face, keyChain, expectedNumEntries, syncPrefix, userPrefix,
+  : ProducerBase(face, keyChain, expectedNumEntries, syncPrefix,
                  syncReplyFreshness, ibltCompression, contentCompression)
   , m_syncInterestLifetime(syncInterestLifetime)
   , m_onUpdate(std::move(onUpdateCb))
 {
+  addUserNode(userPrefix);
+
   m_registeredPrefix = m_face.setInterestFilter(ndn::InterestFilter(m_syncPrefix).allowLoopback(false),
     [this] (auto&&... args) { onSyncInterest(std::forward<decltype(args)>(args)...); },
     [] (auto&&... args) { onRegisterFailed(std::forward<decltype(args)>(args)...); });
diff --git a/PSync/partial-producer.cpp b/PSync/partial-producer.cpp
index 0c27b74..21439db 100644
--- a/PSync/partial-producer.cpp
+++ b/PSync/partial-producer.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  The University of Memphis
+ * Copyright (c) 2014-2023,  The University of Memphis
  *
  * This file is part of PSync.
  * See AUTHORS.md for complete list of PSync authors and contributors.
@@ -33,15 +33,11 @@
 
 PartialProducer::PartialProducer(ndn::Face& face,
                                  ndn::KeyChain& keyChain,
-                                 size_t expectedNumEntries,
                                  const ndn::Name& syncPrefix,
-                                 const ndn::Name& userPrefix,
-                                 ndn::time::milliseconds helloReplyFreshness,
-                                 ndn::time::milliseconds syncReplyFreshness,
-                                 CompressionScheme ibltCompression)
-  : ProducerBase(face, keyChain, expectedNumEntries, syncPrefix, userPrefix,
-                 syncReplyFreshness, ibltCompression, CompressionScheme::NONE)
-  , m_helloReplyFreshness(helloReplyFreshness)
+                                 const Options& opts)
+  : ProducerBase(face, keyChain, opts.ibfCount, syncPrefix, opts.syncDataFreshness,
+                 opts.ibfCompression, CompressionScheme::NONE)
+  , m_helloReplyFreshness(opts.helloDataFreshness)
 {
   m_registeredPrefix = m_face.registerPrefix(m_syncPrefix,
     [this] (const auto&) {
@@ -53,6 +49,21 @@
     [] (auto&&... args) { onRegisterFailed(std::forward<decltype(args)>(args)...); });
 }
 
+PartialProducer::PartialProducer(ndn::Face& face,
+                                 ndn::KeyChain& keyChain,
+                                 size_t expectedNumEntries,
+                                 const ndn::Name& syncPrefix,
+                                 const ndn::Name& userPrefix,
+                                 ndn::time::milliseconds helloReplyFreshness,
+                                 ndn::time::milliseconds syncReplyFreshness,
+                                 CompressionScheme ibltCompression)
+  : PartialProducer(face, keyChain, syncPrefix,
+                    Options{static_cast<uint32_t>(expectedNumEntries), ibltCompression,
+                            helloReplyFreshness, syncReplyFreshness})
+{
+  addUserNode(userPrefix);
+}
+
 void
 PartialProducer::publishName(const ndn::Name& prefix, std::optional<uint64_t> seq)
 {
diff --git a/PSync/partial-producer.hpp b/PSync/partial-producer.hpp
index ffc7de7..78a7818 100644
--- a/PSync/partial-producer.hpp
+++ b/PSync/partial-producer.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  The University of Memphis
+ * Copyright (c) 2014-2023,  The University of Memphis
  *
  * This file is part of PSync.
  * See AUTHORS.md for complete list of PSync authors and contributors.
@@ -37,20 +37,34 @@
 {
 public:
   /**
-   * @brief Constructor
-   *
-   * Registers syncPrefix in NFD and sets internal filters for
-   * "sync" and "hello" under syncPrefix.
-   *
-   * @param face Application's face
-   * @param keyChain KeyChain instance to use for signing
-   * @param expectedNumEntries Expected number of entries in IBF
-   * @param syncPrefix The prefix of the sync group
-   * @param userPrefix The prefix of the first user in the group
-   * @param helloReplyFreshness FreshnessPeriod of hello data
-   * @param syncReplyFreshness FreshnessPeriod of sync data
-   * @param ibltCompression Compression scheme to use for IBF
+   * @brief Constructor options.
    */
+  struct Options
+  {
+    /// Expected number of entries in IBF.
+    uint32_t ibfCount = 40;
+    /// Compression scheme to use for IBF.
+    CompressionScheme ibfCompression = CompressionScheme::NONE;
+    /// FreshnessPeriod of hello data.
+    ndn::time::milliseconds helloDataFreshness = HELLO_REPLY_FRESHNESS;
+    /// FreshnessPeriod of sync data.
+    ndn::time::milliseconds syncDataFreshness = SYNC_REPLY_FRESHNESS;
+  };
+
+  /**
+   * @brief Constructor.
+   *
+   * @param face Application face.
+   * @param keyChain KeyChain instance to use for signing.
+   * @param syncPrefix The prefix of the sync group.
+   * @param opts Options.
+   */
+  PartialProducer(ndn::Face& face,
+                  ndn::KeyChain& keyChain,
+                  const ndn::Name& syncPrefix,
+                  const Options& opts);
+
+  [[deprecated]]
   PartialProducer(ndn::Face& face,
                   ndn::KeyChain& keyChain,
                   size_t expectedNumEntries,
diff --git a/PSync/producer-base.cpp b/PSync/producer-base.cpp
index 74f280d..faa3ea6 100644
--- a/PSync/producer-base.cpp
+++ b/PSync/producer-base.cpp
@@ -31,7 +31,6 @@
                            ndn::KeyChain& keyChain,
                            size_t expectedNumEntries,
                            const ndn::Name& syncPrefix,
-                           const ndn::Name& userPrefix,
                            ndn::time::milliseconds syncReplyFreshness,
                            CompressionScheme ibltCompression,
                            CompressionScheme contentCompression)
@@ -44,12 +43,10 @@
   , m_expectedNumEntries(expectedNumEntries)
   , m_threshold(expectedNumEntries / 2)
   , m_syncPrefix(syncPrefix)
-  , m_userPrefix(userPrefix)
   , m_syncReplyFreshness(syncReplyFreshness)
   , m_ibltCompression(ibltCompression)
   , m_contentCompression(contentCompression)
 {
-  addUserNode(userPrefix);
 }
 
 bool
diff --git a/PSync/producer-base.hpp b/PSync/producer-base.hpp
index adfc8d1..faaa926 100644
--- a/PSync/producer-base.hpp
+++ b/PSync/producer-base.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  The University of Memphis
+ * Copyright (c) 2014-2023,  The University of Memphis
  *
  * This file is part of PSync.
  * See AUTHORS.md for complete list of PSync authors and contributors.
@@ -61,7 +61,6 @@
    * @param keyChain KeyChain instance to use for signing
    * @param expectedNumEntries Expected number of entries in IBF
    * @param syncPrefix The prefix of the sync group
-   * @param userPrefix The prefix of the first user in the group
    * @param syncReplyFreshness FreshnessPeriod of sync data
    * @param ibltCompression Compression scheme to use for IBF
    * @param contentCompression Compression scheme to use for Data content
@@ -70,7 +69,6 @@
                ndn::KeyChain& keyChain,
                size_t expectedNumEntries,
                const ndn::Name& syncPrefix,
-               const ndn::Name& userPrefix,
                ndn::time::milliseconds syncReplyFreshness = SYNC_REPLY_FRESHNESS,
                CompressionScheme ibltCompression = CompressionScheme::NONE,
                CompressionScheme contentCompression = CompressionScheme::NONE);
@@ -175,7 +173,6 @@
   // than it and whether we need to update the other side.
   const size_t m_threshold;
   const ndn::Name m_syncPrefix;
-  const ndn::Name m_userPrefix;
   const ndn::time::milliseconds m_syncReplyFreshness;
   const CompressionScheme m_ibltCompression;
   const CompressionScheme m_contentCompression;
diff --git a/examples/producer.cpp b/examples/producer.cpp
index a19b468..1dc0045 100644
--- a/examples/producer.cpp
+++ b/examples/producer.cpp
@@ -39,7 +39,7 @@
    */
   PSyncPartialProducer(const ndn::Name& syncPrefix, const std::string& userPrefix,
                        int numDataStreams, int maxNumPublish)
-    : m_producer(m_face, m_keyChain, 40, syncPrefix, userPrefix + "-0")
+    : m_producer(m_face, m_keyChain, syncPrefix, {})
     , m_maxNumPublish(maxNumPublish)
   {
     // Add user prefixes and schedule updates for them
@@ -47,7 +47,6 @@
       ndn::Name updateName(userPrefix + "-" + std::to_string(i));
 
       // Add the user prefix to the producer
-      // Note that this does not add the already added userPrefix-0 in the constructor
       m_producer.addUserNode(updateName);
 
       // Each user prefix is updated at a random interval between 0 and 60 seconds
diff --git a/tests/test-partial-producer.cpp b/tests/test-partial-producer.cpp
index 50d7386..5088915 100644
--- a/tests/test-partial-producer.cpp
+++ b/tests/test-partial-producer.cpp
@@ -41,7 +41,8 @@
 BOOST_AUTO_TEST_CASE(RegisterPrefix)
 {
   Name syncPrefix("/psync"), userNode("/testUser");
-  PartialProducer producer(m_face, m_keyChain, 40, syncPrefix, userNode);
+  PartialProducer producer(m_face, m_keyChain, syncPrefix, {});
+  producer.addUserNode(userNode);
 
   m_face.processEvents(-1_ms);
 
@@ -55,7 +56,8 @@
 BOOST_AUTO_TEST_CASE(PublishName)
 {
   Name syncPrefix("/psync"), userNode("/testUser"), nonUser("/testUser2");
-  PartialProducer producer(m_face, m_keyChain, 40, syncPrefix, userNode);
+  PartialProducer producer(m_face, m_keyChain, syncPrefix, {});
+  producer.addUserNode(userNode);
 
   BOOST_CHECK_EQUAL(producer.getSeqNo(userNode).value_or(-1), 0);
   producer.publishName(userNode);
@@ -74,7 +76,8 @@
 BOOST_AUTO_TEST_CASE(SameSyncInterest)
 {
   Name syncPrefix("/psync"), userNode("/testUser");
-  PartialProducer producer(m_face, m_keyChain, 40, syncPrefix, userNode);
+  PartialProducer producer(m_face, m_keyChain, syncPrefix, {});
+  producer.addUserNode(userNode);
 
   Name syncInterestName(syncPrefix);
   syncInterestName.append("sync");
@@ -110,7 +113,8 @@
 BOOST_AUTO_TEST_CASE(OnSyncInterest)
 {
   Name syncPrefix("/psync"), userNode("/testUser");
-  PartialProducer producer(m_face, m_keyChain, 40, syncPrefix, userNode);
+  PartialProducer producer(m_face, m_keyChain, syncPrefix, {});
+  producer.addUserNode(userNode);
 
   // Sync interest with no bloom filter attached
   Name syncInterestName(syncPrefix);
diff --git a/tests/test-partial-sync.cpp b/tests/test-partial-sync.cpp
index 2526d2c..0efe4c8 100644
--- a/tests/test-partial-sync.cpp
+++ b/tests/test-partial-sync.cpp
@@ -37,7 +37,7 @@
 protected:
   PartialSyncFixture()
   {
-    producer = std::make_unique<PartialProducer>(face, m_keyChain, 40, syncPrefix, userPrefix);
+    producer = std::make_unique<PartialProducer>(face, m_keyChain, syncPrefix, PartialProducer::Options{});
     addUserNodes("testUser", 10);
   }
 
@@ -111,8 +111,7 @@
   void
   addUserNodes(const std::string& prefix, int numOfUserNodes)
   {
-    // zeroth is added through constructor
-    for (int i = 1; i < numOfUserNodes; i++) {
+    for (int i = 0; i < numOfUserNodes; i++) {
       producer->addUserNode(prefix + "-" + std::to_string(i));
     }
   }
@@ -291,8 +290,8 @@
   face.unlink();
 
   ndn::DummyClientFace face2(m_io, m_keyChain, {true, true});
-  PartialProducer replicatedProducer(face2, m_keyChain, 40, syncPrefix, userPrefix);
-  for (int i = 1; i < 10; i++) {
+  PartialProducer replicatedProducer(face2, m_keyChain, syncPrefix, {});
+  for (int i = 0; i < 10; i++) {
     replicatedProducer.addUserNode("testUser-" + std::to_string(i));
   }
   advanceClocks(ndn::time::milliseconds(10));
diff --git a/tests/test-producer-base.cpp b/tests/test-producer-base.cpp
index 4886339..468c1d4 100644
--- a/tests/test-producer-base.cpp
+++ b/tests/test-producer-base.cpp
@@ -39,7 +39,8 @@
 BOOST_AUTO_TEST_CASE(Basic)
 {
   Name userNode("/testUser");
-  ProducerBase producerBase(m_face, m_keyChain, 40, Name("/psync"), userNode);
+  ProducerBase producerBase(m_face, m_keyChain, 40, Name("/psync"));
+  producerBase.addUserNode(userNode);
 
   // Hash table size should be 40 + 40/2 = 60 (which is perfectly divisible by N_HASH = 3)
   BOOST_CHECK_EQUAL(producerBase.m_iblt.getHashTable().size(), 60);
@@ -66,7 +67,8 @@
 
 BOOST_AUTO_TEST_CASE(ApplicationNack)
 {
-  ProducerBase producerBase(m_face, m_keyChain, 40, Name("/psync"), Name("/testUser"));
+  ProducerBase producerBase(m_face, m_keyChain, 40, Name("/psync"));
+  producerBase.addUserNode("/testUser");
 
   BOOST_CHECK_EQUAL(m_face.sentData.size(), 0);
   producerBase.sendApplicationNack(Name("test"));