Resolve the circular dependency between folly/futures/detail/Core.h and Future.h...
[folly.git] / folly / futures / helpers.h
index 26187b8fa0662316bf66ca97471edb7c3364c854..e99a171814215b96a1ba4f611949b45909b61d20 100644 (file)
  */
 #pragma once
 
-#include <folly/futures/Future.h>
+#include <atomic>
+#include <tuple>
+#include <utility>
+
 #include <folly/Portability.h>
+#include <folly/Try.h>
+#include <folly/futures/Future.h>
+#include <folly/futures/Promise.h>
 
 namespace folly {
 
+namespace detail {
+template <typename... Ts>
+struct CollectAllVariadicContext {
+  CollectAllVariadicContext() {}
+  template <typename T, size_t I>
+  inline void setPartialResult(Try<T>& t) {
+    std::get<I>(results) = std::move(t);
+  }
+  ~CollectAllVariadicContext() {
+    p.setValue(std::move(results));
+  }
+  Promise<std::tuple<Try<Ts>...>> p;
+  std::tuple<Try<Ts>...> results;
+  typedef Future<std::tuple<Try<Ts>...>> type;
+};
+
+template <typename... Ts>
+struct CollectVariadicContext {
+  CollectVariadicContext() {}
+  template <typename T, size_t I>
+  inline void setPartialResult(Try<T>& t) {
+    if (t.hasException()) {
+      if (!threw.exchange(true)) {
+        p.setException(std::move(t.exception()));
+      }
+    } else if (!threw) {
+      std::get<I>(results) = std::move(t);
+    }
+  }
+  ~CollectVariadicContext() noexcept {
+    if (!threw.exchange(true)) {
+      p.setValue(unwrapTryTuple(std::move(results)));
+    }
+  }
+  Promise<std::tuple<Ts...>> p;
+  std::tuple<folly::Try<Ts>...> results;
+  std::atomic<bool> threw{false};
+  typedef Future<std::tuple<Ts...>> type;
+};
+}
+
 /// This namespace is for utility functions that would usually be static
 /// members of Future, except they don't make sense there because they don't
 /// depend on the template type (rather, on the type of their arguments in