From 226fe9d8f7538e4f5b505732d9ee1a1a89dbb576 Mon Sep 17 00:00:00 2001
From: Danilo Piparo <danilo.piparo@cern.ch>
Date: Fri, 25 Aug 2017 14:43:07 +0200
Subject: [PATCH] Adopt naming conventions of std::future

---
 core/imt/CMakeLists.txt      |   2 +-
 core/imt/inc/ROOT/Future.hxx | 161 +++++++++++++++++++++++++++++++++++
 core/imt/src/Future.cxx      |  28 ++++++
 3 files changed, 190 insertions(+), 1 deletion(-)
 create mode 100644 core/imt/inc/ROOT/Future.hxx
 create mode 100644 core/imt/src/Future.cxx

diff --git a/core/imt/CMakeLists.txt b/core/imt/CMakeLists.txt
index 6c1b12ff6e7..9c735982b5e 100644
--- a/core/imt/CMakeLists.txt
+++ b/core/imt/CMakeLists.txt
@@ -5,7 +5,7 @@
 set(sources base.cxx)
 
 if (imt)
-  set(headers ROOT/TPoolManager.hxx ROOT/TThreadExecutor.hxx ROOT/TTaskGroup.hxx)
+  set(headers ROOT/TPoolManager.hxx ROOT/TThreadExecutor.hxx ROOT/TTaskGroup.hxx ROOT/Future.hxx)
   ROOT_GENERATE_DICTIONARY(G__Imt ${headers} STAGE1 MODULE Imt LINKDEF LinkDef.h  DEPENDENCIES Core Thread BUILTINS TBB) # For auto{loading,parsing}
   set(sources ${sources} TImplicitMT.cxx TThreadExecutor.cxx TPoolManager.cxx TTaskGroup.cxx G__Imt.cxx)
 endif()
diff --git a/core/imt/inc/ROOT/Future.hxx b/core/imt/inc/ROOT/Future.hxx
new file mode 100644
index 00000000000..80d5826e1c4
--- /dev/null
+++ b/core/imt/inc/ROOT/Future.hxx
@@ -0,0 +1,161 @@
+// @(#)root/thread:$Id$
+// Author: Danilo Piparo August 2017
+
+/*************************************************************************
+ * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers.               *
+ * All rights reserved.                                                  *
+ *                                                                       *
+ * For the licensing terms see $ROOTSYS/LICENSE.                         *
+ * For the list of contributors see $ROOTSYS/README/CREDITS.             *
+ *************************************************************************/
+
+#ifndef ROOT_Async
+#define ROOT_Async
+
+#include "RConfigure.h"
+
+#include "ROOT/TTaskGroup.hxx"
+
+#include <type_traits>
+#include <future>
+
+// exclude in case ROOT does not have IMT support
+#ifndef R__USE_IMT
+// No need to error out for dictionaries.
+#if !defined(__ROOTCLING__) && !defined(G__DICTIONARY)
+#error "Cannot use ROOT::Experimental::Async without defining R__USE_IMT."
+#endif
+#else
+
+namespace ROOT {
+
+// fwd declaration
+namespace Experimental {
+template <typename T>
+class Future;
+}
+
+namespace Detail {
+template <typename T>
+class FutureImpl {
+   template<typename V> friend class Future;
+protected:
+   using TTaskGroup = Experimental::TTaskGroup;
+   std::future<T> fStdFut;
+   std::unique_ptr<TTaskGroup> fTg {nullptr};
+
+   FutureImpl(std::future<T> &&fut, std::unique_ptr<TTaskGroup> &&tg) : fStdFut(std::move(fut)) {
+      fTg = std::move(tg);
+   };
+   FutureImpl(){};
+
+   FutureImpl(std::future<T> &&fut) : fStdFut(std::move(fut)) {}
+
+   FutureImpl(FutureImpl<T> &&other) { *this = std::move(other); }
+
+   FutureImpl(const FutureImpl<T> &other) = delete;
+
+public:
+
+   FutureImpl<T> &operator=(FutureImpl<T> &&other)
+   {
+      fStdFut = std::move(other.fStdFut);
+      fTg = std::move(other.fTg);
+      return *this;
+   }
+
+   FutureImpl<T> &operator=(FutureImpl<T> &other) = delete;
+
+   void wait() { fTg->Wait(); }
+
+   bool valid() const { return fStdFut.valid(); };
+};
+}
+
+namespace Experimental {
+
+////////////////////////////////////////////////////////////////////////////////
+/// A future class. It can wrap an std::future.
+template <typename T>
+class Future final : public Detail::FutureImpl<T> {
+template <class Function, class... Args>
+   friend Future<typename std::result_of<typename std::decay<Function>::type(typename std::decay<Args>::type...)>::type> Async(Function &&f, Args &&... args);
+private:
+   Future(std::future<T> &&fut, std::unique_ptr<TTaskGroup> &&tg)
+      : Detail::FutureImpl<T>(std::forward<std::future<T>>(fut), std::move(tg)){};
+public:
+   Future(std::future<T> &&fut) : Detail::FutureImpl<T>(std::forward<std::future<T>>(fut)) {};
+
+   Future(Future<T>&& other): Detail::FutureImpl<T>(std::forward<Future<T>>(other)) {}
+
+   T get()
+   {
+      this->wait();
+      return this->fStdFut.get();
+   }
+};
+/// \cond
+// Two specialisations, for void and T& as for std::future
+template <>
+class Future<void> final : public Detail::FutureImpl<void> {
+template <class Function, class... Args>
+   friend Future<typename std::result_of<typename std::decay<Function>::type(typename std::decay<Args>::type...)>::type> Async(Function &&f, Args &&... args);
+private:
+   Future(std::future<void> &&fut, std::unique_ptr<TTaskGroup> &&tg)
+      : Detail::FutureImpl<void>(std::forward<std::future<void>>(fut), std::move(tg)){};
+public:
+   Future(std::future<void> &&fut) : Detail::FutureImpl<void>(std::forward<std::future<void>>(fut)) {};
+
+   Future(Future<void> &&other) : Detail::FutureImpl<void>(std::forward<Future<void>>(other)) {}
+
+   void get()
+   {
+      this->wait();
+      fStdFut.get();
+   }
+};
+
+template <typename T>
+class Future<T &> final : public Detail::FutureImpl<T &> {
+template <class Function, class... Args>
+   friend Future<typename std::result_of<typename std::decay<Function>::type(typename std::decay<Args>::type...)>::type> Async(Function &&f, Args &&... args);
+private:
+   Future(std::future<T &> &&fut, std::unique_ptr<TTaskGroup> &&tg)
+      : Detail::FutureImpl<T &>(std::forward<std::future<T &>>(fut), std::move(tg)){};
+public:
+   Future(std::future<T&> &&fut) : Detail::FutureImpl<T>(std::forward<std::future<T&>>(fut)) {};
+
+   Future(Future<T&> &&other) : Detail::FutureImpl<T&>(std::forward<Future<T&>>(other)) {}
+
+   T &get()
+   {
+      this->wait();
+      return this->fStdFut.get();
+   }
+};
+/// \endcond
+
+////////////////////////////////////////////////////////////////////////////////
+/// Runs a function asynchronously potentially in a new thread and returns a
+/// ROOT Future that will hold the result.
+template <class Function, class... Args>
+Future<typename std::result_of<typename std::decay<Function>::type(typename std::decay<Args>::type...)>::type>
+Async(Function &&f, Args &&... args)
+{
+   // The return type according to the standard implementation of std::future
+   // the long type is due to the fact that we want to be c++11 compatible.
+   // A more elegant version would be:
+   // std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
+   using Ret_t = typename std::result_of<typename std::decay<Function>::type(typename std::decay<Args>::type...)>::type;
+
+   auto thisPt = std::make_shared<std::packaged_task<Ret_t()>>(std::bind(f, args...));
+   std::unique_ptr<ROOT::Experimental::TTaskGroup> tg(new ROOT::Experimental::TTaskGroup());
+   tg->Run([thisPt]() { (*thisPt)(); });
+
+   return ROOT::Experimental::Future<Ret_t>(thisPt->get_future(), std::move(tg));
+}
+}
+}
+
+#endif
+#endif
diff --git a/core/imt/src/Future.cxx b/core/imt/src/Future.cxx
new file mode 100644
index 00000000000..bd21115ec71
--- /dev/null
+++ b/core/imt/src/Future.cxx
@@ -0,0 +1,28 @@
+// @(#)root/thread:$Id$
+// Author: Danilo Piparo August 2017
+
+/*************************************************************************
+ * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers.               *
+ * All rights reserved.                                                  *
+ *                                                                       *
+ * For the licensing terms see $ROOTSYS/LICENSE.                         *
+ * For the list of contributors see $ROOTSYS/README/CREDITS.             *
+ *************************************************************************/
+
+// #include "ROOT/TTaskGroup.hxx"
+//
+// #include <memory>
+//
+// namespace ROOT {
+//
+// namespace Internal {
+// namespace AsyncUtils{
+//
+// std::shared_ptr<Experimental::TTaskGroup> GetAsyncTaskGroup() {
+//    static auto gAsyncTaskGroup = std::make_shared<Experimental::TTaskGroup>();
+//    return gAsyncTaskGroup;
+// }
+//
+// }
+// }
+// }
-- 
GitLab