interest: add Interest::modifyForwardingHint

refs #4055

Change-Id: I3e245bcb5091659e0e9d89b18de604e42c906694
diff --git a/src/interest.hpp b/src/interest.hpp
index f772def..a00bbc0 100644
--- a/src/interest.hpp
+++ b/src/interest.hpp
@@ -205,6 +205,25 @@
   Interest&
   setForwardingHint(const DelegationList& value);
 
+  /** @brief modify ForwardingHint in-place
+   *  @tparam Modifier a unary function that accepts DelegationList&
+   *
+   *  This is equivalent to, but more efficient (avoids copying) than:
+   *  @code
+   *  auto fh = interest.getForwardingHint();
+   *  modifier(fh);
+   *  interest.setForwardingHint(fh);
+   *  @endcode
+   */
+  template<typename Modifier>
+  Interest&
+  modifyForwardingHint(const Modifier& modifier)
+  {
+    modifier(m_forwardingHint);
+    m_wire.reset();
+    return *this;
+  }
+
 public: // Selectors
   /**
    * @return true if Interest has any selector present
diff --git a/tests/unit-tests/interest.t.cpp b/tests/unit-tests/interest.t.cpp
index f2a7745..d0345a4 100644
--- a/tests/unit-tests/interest.t.cpp
+++ b/tests/unit-tests/interest.t.cpp
@@ -355,6 +355,18 @@
   BOOST_CHECK_EQUAL(i.getInterestLifetime(), time::milliseconds(1));
 }
 
+BOOST_AUTO_TEST_CASE(ModifyForwardingHint)
+{
+  Interest i;
+  i.setForwardingHint({{1, "/A"}});
+  i.wireEncode();
+  BOOST_CHECK(i.hasWire());
+
+  i.modifyForwardingHint([] (DelegationList& fh) { fh.insert(2, "/B"); });
+  BOOST_CHECK(!i.hasWire());
+  BOOST_CHECK_EQUAL(i.getForwardingHint(), DelegationList({{1, "/A"}, {2, "/B"}}));
+}
+
 // ---- operators ----
 
 BOOST_AUTO_TEST_CASE(Equality)