TaskRunner: Replace use of std::function with std::packaged_task.

The task runner is meant to run a "task" once. Thus, client code should
expect that it can std::bind() with movable types (e.g.,
std::unique_ptr<T>) as arguments. However, the TaskRunner uses
std::function, which only works when all std::bind() arguments are
copyable.

The solution is to replace std::function with std::packaged_task, the
latter of which is purposely designed to be a run-once variant of
std::function; and it also supports move-only types in the bind state.

This change also cleans-up a few other details around the switch:

1. std::packaged_task uses an explicit ctor, whereas std::function
provided an implicit one. Thus, TaskRunner::PostTask() has become a
templated member function, an inline wrapper around calling the
std::packaged_task ctor explicitly.

2. TaskRunnerImpl's use of std::priority_queue for delayed tasks was
replaced with std::multimap, because the API of the former did not
provide non-const access to its elements (which was required for move
operations).

3. Minor tweaks around comments and resource/allocation concerns in
touched code.

Change-Id: I5fe9a2e3a3c2d8d69b564575f81c4a7f4a80b265
Reviewed-on: https://chromium-review.googlesource.com/c/openscreen/+/1646564
Commit-Queue: Yuri Wiitala <miu@chromium.org>
Reviewed-by: Ryan Keane <rwkeane@google.com>
Reviewed-by: Max Yakimakha <yakimakha@chromium.org>
diff --git a/platform/api/task_runner.h b/platform/api/task_runner.h
index 2f05803..611b2b5 100644
--- a/platform/api/task_runner.h
+++ b/platform/api/task_runner.h
@@ -5,7 +5,7 @@
 #ifndef PLATFORM_API_TASK_RUNNER_H_
 #define PLATFORM_API_TASK_RUNNER_H_
 
-#include <functional>
+#include <future>
 
 #include "platform/api/time.h"
 
@@ -23,18 +23,33 @@
 // NOTE: we do not make any assumptions about what thread tasks shall run on.
 class TaskRunner {
  public:
-  using Task = std::function<void()>;
+  using Task = std::packaged_task<void() noexcept>;
 
   virtual ~TaskRunner() = default;
 
-  // Takes a Task that should be run at the first convenient time.
-  virtual void PostTask(Task task) = 0;
+  // Takes any callable target (function, lambda-expression, std::bind result,
+  // etc.) that should be run at the first convenient time.
+  template <typename Functor>
+  inline void PostTask(Functor f) {
+    PostPackagedTask(Task(std::move(f)));
+  }
 
-  // Takes a Task that should be run no sooner than "delay" time from now. Note
-  // that we do not guarantee it will run precisely "delay" later, merely that
-  // it will run no sooner than "delay" time from now.
-  virtual void PostTaskWithDelay(Task task, Clock::duration delay) = 0;
+  // Takes any callable target (function, lambda-expression, std::bind result,
+  // etc.) that should be run no sooner than |delay| time from now. Note that
+  // the Task might run after an additional delay, especially under heavier
+  // system load. There is no deadline concept.
+  template <typename Functor>
+  inline void PostTaskWithDelay(Functor f, Clock::duration delay) {
+    PostPackagedTaskWithDelay(Task(std::move(f)), delay);
+  }
+
+  // Implementations should provide the behavior explained in the comments above
+  // for PostTask[WithDelay](). Client code may also call these directly when
+  // passing an existing Task object.
+  virtual void PostPackagedTask(Task task) = 0;
+  virtual void PostPackagedTaskWithDelay(Task task, Clock::duration delay) = 0;
 };
+
 }  // namespace platform
 }  // namespace openscreen