move wangle/futures to futures
authorJames Sedgwick <jsedgwick@fb.com>
Fri, 9 Jan 2015 16:27:02 +0000 (08:27 -0800)
committerViswanath Sivakumar <viswanath@fb.com>
Tue, 13 Jan 2015 19:01:05 +0000 (11:01 -0800)
Summary:
First step of moving futures out of wangle into folly

Namespace change will be another diff

This was just a straight codemod of "wangle/futures" to "futures"

Test Plan: wait for contbuild

Reviewed By: davejwatson@fb.com

Subscribers: trunkagent, fbcode-common-diffs@, chaoyc, search-fbcode-diffs@, lars, ruibalp, hero-diffs@, zeus-diffs@, vikas, mcduff, hitesh, cold-storage-diffs@, unicorn-diffs@, ldbrandy, targeting-diff-backend@, netego-diffs@, fugalh, adamsyta, atlas2-eng@, alandau, apollo-diffs@, bmatheny, adityab, everstore-dev@, zhuohuang, sweeney, mwa, jgehring, prometheus-diffs@, smarlow, akr, bnitka, jcoens, zhguo, jying, darshan, apodsiadlo, alikhtarov, fuegen, dzhulgakov, alihussains, jeremyfein, mshneer, folly-diffs@, wch, lins, tingy, maxwellsayles, hannesr

FB internal diff: D1772041

Tasks: 5960242

Signature: t1:1772041:1420739169:36126b1264c5d1747d241921d02b13e306c73fe1

79 files changed:
folly/Makefile.am
folly/futures/Deprecated.h [new file with mode: 0644]
folly/futures/Future-inl.h [new file with mode: 0644]
folly/futures/Future.cpp [new file with mode: 0644]
folly/futures/Future.h [new file with mode: 0644]
folly/futures/InlineExecutor.cpp [new file with mode: 0644]
folly/futures/InlineExecutor.h [new file with mode: 0644]
folly/futures/ManualExecutor.cpp [new file with mode: 0644]
folly/futures/ManualExecutor.h [new file with mode: 0644]
folly/futures/OpaqueCallbackShunt.h [new file with mode: 0644]
folly/futures/Promise-inl.h [new file with mode: 0644]
folly/futures/Promise.h [new file with mode: 0644]
folly/futures/QueuedImmediateExecutor.cpp [new file with mode: 0644]
folly/futures/QueuedImmediateExecutor.h [new file with mode: 0644]
folly/futures/README.md [new file with mode: 0644]
folly/futures/ScheduledExecutor.h [new file with mode: 0644]
folly/futures/Timekeeper.h [new file with mode: 0644]
folly/futures/Try-inl.h [new file with mode: 0644]
folly/futures/Try.h [new file with mode: 0644]
folly/futures/WangleException.h [new file with mode: 0644]
folly/futures/detail/Core.h [new file with mode: 0644]
folly/futures/detail/FSM.h [new file with mode: 0644]
folly/futures/detail/ThreadWheelTimekeeper.cpp [new file with mode: 0644]
folly/futures/detail/ThreadWheelTimekeeper.h [new file with mode: 0644]
folly/futures/detail/Types.h [new file with mode: 0644]
folly/futures/test/Benchmark.cpp [new file with mode: 0644]
folly/futures/test/ClientCompile.cpp [new file with mode: 0644]
folly/futures/test/ExecutorTest.cpp [new file with mode: 0644]
folly/futures/test/FSM.cpp [new file with mode: 0644]
folly/futures/test/FutureTest.cpp [new file with mode: 0644]
folly/futures/test/Interrupts.cpp [new file with mode: 0644]
folly/futures/test/Thens.cpp [new file with mode: 0644]
folly/futures/test/Thens.h [new file with mode: 0644]
folly/futures/test/TimekeeperTest.cpp [new file with mode: 0644]
folly/futures/test/Try.cpp [new file with mode: 0644]
folly/futures/test/ViaTest.cpp [new file with mode: 0644]
folly/futures/test/main.cpp [new file with mode: 0644]
folly/futures/test/thens.rb [new file with mode: 0755]
folly/wangle/channel/ChannelHandler.h
folly/wangle/channel/ChannelHandlerContext.h
folly/wangle/channel/ChannelPipeline.h
folly/wangle/concurrent/FutureExecutor.h
folly/wangle/futures/Deprecated.h [deleted file]
folly/wangle/futures/Future-inl.h [deleted file]
folly/wangle/futures/Future.cpp [deleted file]
folly/wangle/futures/Future.h [deleted file]
folly/wangle/futures/InlineExecutor.cpp [deleted file]
folly/wangle/futures/InlineExecutor.h [deleted file]
folly/wangle/futures/ManualExecutor.cpp [deleted file]
folly/wangle/futures/ManualExecutor.h [deleted file]
folly/wangle/futures/OpaqueCallbackShunt.h [deleted file]
folly/wangle/futures/Promise-inl.h [deleted file]
folly/wangle/futures/Promise.h [deleted file]
folly/wangle/futures/QueuedImmediateExecutor.cpp [deleted file]
folly/wangle/futures/QueuedImmediateExecutor.h [deleted file]
folly/wangle/futures/README.md [deleted file]
folly/wangle/futures/ScheduledExecutor.h [deleted file]
folly/wangle/futures/Timekeeper.h [deleted file]
folly/wangle/futures/Try-inl.h [deleted file]
folly/wangle/futures/Try.h [deleted file]
folly/wangle/futures/WangleException.h [deleted file]
folly/wangle/futures/detail/Core.h [deleted file]
folly/wangle/futures/detail/FSM.h [deleted file]
folly/wangle/futures/detail/ThreadWheelTimekeeper.cpp [deleted file]
folly/wangle/futures/detail/ThreadWheelTimekeeper.h [deleted file]
folly/wangle/futures/detail/Types.h [deleted file]
folly/wangle/futures/test/Benchmark.cpp [deleted file]
folly/wangle/futures/test/ClientCompile.cpp [deleted file]
folly/wangle/futures/test/ExecutorTest.cpp [deleted file]
folly/wangle/futures/test/FSM.cpp [deleted file]
folly/wangle/futures/test/FutureTest.cpp [deleted file]
folly/wangle/futures/test/Interrupts.cpp [deleted file]
folly/wangle/futures/test/Thens.cpp [deleted file]
folly/wangle/futures/test/Thens.h [deleted file]
folly/wangle/futures/test/TimekeeperTest.cpp [deleted file]
folly/wangle/futures/test/Try.cpp [deleted file]
folly/wangle/futures/test/ViaTest.cpp [deleted file]
folly/wangle/futures/test/main.cpp [deleted file]
folly/wangle/futures/test/thens.rb [deleted file]

index 50ec57d2f9218e8ce925deff27e9a829c83b33e7..d717d5fd8d311db1059e789df69abdc66f5f8b97 100644 (file)
@@ -84,6 +84,24 @@ nobase_follyinclude_HEADERS = \
        FormatArg.h \
        Format.h \
        Format-inl.h \
+       futures/Deprecated.h \
+       futures/Future-inl.h \
+       futures/Future.h \
+       futures/InlineExecutor.h \
+       futures/ManualExecutor.h \
+       futures/OpaqueCallbackShunt.h \
+       futures/Promise-inl.h \
+       futures/Promise.h \
+       futures/QueuedImmediateExecutor.h \
+       futures/ScheduledExecutor.h \
+       futures/Timekeeper.h \
+       futures/Try-inl.h \
+       futures/Try.h \
+       futures/WangleException.h \
+       futures/detail/Core.h \
+       futures/detail/FSM.h \
+       futures/detail/ThreadWheelTimekeeper.h \
+       futures/detail/Types.h \
        gen/Base.h \
        gen/Base-inl.h \
        gen/Combine.h \
@@ -221,24 +239,6 @@ nobase_follyinclude_HEADERS = \
        wangle/concurrent/NamedThreadFactory.h \
        wangle/concurrent/ThreadFactory.h \
        wangle/concurrent/ThreadPoolExecutor.h \
-       wangle/futures/Deprecated.h \
-       wangle/futures/Future-inl.h \
-       wangle/futures/Future.h \
-       wangle/futures/InlineExecutor.h \
-       wangle/futures/ManualExecutor.h \
-       wangle/futures/OpaqueCallbackShunt.h \
-       wangle/futures/Promise-inl.h \
-       wangle/futures/Promise.h \
-       wangle/futures/QueuedImmediateExecutor.h \
-       wangle/futures/ScheduledExecutor.h \
-       wangle/futures/Timekeeper.h \
-       wangle/futures/Try-inl.h \
-       wangle/futures/Try.h \
-       wangle/futures/WangleException.h \
-       wangle/futures/detail/Core.h \
-       wangle/futures/detail/FSM.h \
-       wangle/futures/detail/ThreadWheelTimekeeper.h \
-       wangle/futures/detail/Types.h \
        wangle/rx/Observable.h \
        wangle/rx/Observer.h \
        wangle/rx/Subject.h \
@@ -287,6 +287,11 @@ libfolly_la_SOURCES = \
        File.cpp \
        FileUtil.cpp \
        FingerprintTables.cpp \
+       futures/detail/ThreadWheelTimekeeper.cpp \
+       futures/Future.cpp \
+       futures/InlineExecutor.cpp \
+       futures/ManualExecutor.cpp \
+       futures/QueuedImmediateExecutor.cpp \
        detail/Futex.cpp \
        GroupVarint.cpp \
        GroupVarintTables.cpp \
@@ -342,11 +347,6 @@ libfolly_la_SOURCES = \
        wangle/concurrent/IOThreadPoolExecutor.cpp \
        wangle/concurrent/GlobalExecutor.cpp \
        wangle/concurrent/ThreadPoolExecutor.cpp \
-       wangle/futures/detail/ThreadWheelTimekeeper.cpp \
-       wangle/futures/Future.cpp \
-       wangle/futures/InlineExecutor.cpp \
-       wangle/futures/ManualExecutor.cpp \
-       wangle/futures/QueuedImmediateExecutor.cpp \
        wangle/ssl/PasswordInFile.cpp \
        wangle/ssl/SSLContextManager.cpp \
        wangle/ssl/SSLSessionCacheManager.cpp \
diff --git a/folly/futures/Deprecated.h b/folly/futures/Deprecated.h
new file mode 100644 (file)
index 0000000..75937b1
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#define DEPRECATED __attribute__((__deprecated__))
diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h
new file mode 100644 (file)
index 0000000..c19f08a
--- /dev/null
@@ -0,0 +1,842 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <thread>
+
+#include <folly/Baton.h>
+#include <folly/futures/detail/Core.h>
+#include <folly/futures/Timekeeper.h>
+
+namespace folly { namespace wangle {
+
+class Timekeeper;
+
+namespace detail {
+  Timekeeper* getTimekeeperSingleton();
+}
+
+template <typename T>
+struct isFuture {
+  static const bool value = false;
+};
+
+template <typename T>
+struct isFuture<Future<T> > {
+  static const bool value = true;
+};
+
+template <class T>
+Future<T>::Future(Future<T>&& other) noexcept : core_(nullptr) {
+  *this = std::move(other);
+}
+
+template <class T>
+Future<T>& Future<T>::operator=(Future<T>&& other) {
+  std::swap(core_, other.core_);
+  return *this;
+}
+
+template <class T>
+Future<T>::~Future() {
+  detach();
+}
+
+template <class T>
+void Future<T>::detach() {
+  if (core_) {
+    core_->detachFuture();
+    core_ = nullptr;
+  }
+}
+
+template <class T>
+void Future<T>::throwIfInvalid() const {
+  if (!core_)
+    throw NoState();
+}
+
+template <class T>
+template <class F>
+void Future<T>::setCallback_(F&& func) {
+  throwIfInvalid();
+  core_->setCallback(std::move(func));
+}
+
+// Variant: f.then([](Try<T>&& t){ return t.value(); });
+template <class T>
+template <class F>
+typename std::enable_if<
+  !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
+  Future<typename std::result_of<F(Try<T>&&)>::type> >::type
+Future<T>::then(F&& func) {
+  typedef typename std::result_of<F(Try<T>&&)>::type B;
+
+  throwIfInvalid();
+
+  // wrap these so we can move them into the lambda
+  folly::MoveWrapper<Promise<B>> p;
+  folly::MoveWrapper<F> funcm(std::forward<F>(func));
+
+  // grab the Future now before we lose our handle on the Promise
+  auto f = p->getFuture();
+
+  /* This is a bit tricky.
+
+     We can't just close over *this in case this Future gets moved. So we
+     make a new dummy Future. We could figure out something more
+     sophisticated that avoids making a new Future object when it can, as an
+     optimization. But this is correct.
+
+     core_ can't be moved, it is explicitly disallowed (as is copying). But
+     if there's ever a reason to allow it, this is one place that makes that
+     assumption and would need to be fixed. We use a standard shared pointer
+     for core_ (by copying it in), which means in essence obj holds a shared
+     pointer to itself.  But this shouldn't leak because Promise will not
+     outlive the continuation, because Promise will setException() with a
+     broken Promise if it is destructed before completed. We could use a
+     weak pointer but it would have to be converted to a shared pointer when
+     func is executed (because the Future returned by func may possibly
+     persist beyond the callback, if it gets moved), and so it is an
+     optimization to just make it shared from the get-go.
+
+     We have to move in the Promise and func using the MoveWrapper
+     hack. (func could be copied but it's a big drag on perf).
+
+     Two subtle but important points about this design. detail::Core has no
+     back pointers to Future or Promise, so if Future or Promise get moved
+     (and they will be moved in performant code) we don't have to do
+     anything fancy. And because we store the continuation in the
+     detail::Core, not in the Future, we can execute the continuation even
+     after the Future has gone out of scope. This is an intentional design
+     decision. It is likely we will want to be able to cancel a continuation
+     in some circumstances, but I think it should be explicit not implicit
+     in the destruction of the Future used to create it.
+     */
+  setCallback_(
+    [p, funcm](Try<T>&& t) mutable {
+      p->fulfil([&]() {
+        return (*funcm)(std::move(t));
+      });
+    });
+
+  return f;
+}
+
+// Variant: f.then([](T&& t){ return t; });
+template <class T>
+template <class F>
+typename std::enable_if<
+  !std::is_same<T, void>::value &&
+  !isFuture<typename std::result_of<
+    F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
+  Future<typename std::result_of<
+    F(typename detail::AliasIfVoid<T>::type&&)>::type> >::type
+Future<T>::then(F&& func) {
+  typedef typename std::result_of<F(T&&)>::type B;
+
+  throwIfInvalid();
+
+  folly::MoveWrapper<Promise<B>> p;
+  folly::MoveWrapper<F> funcm(std::forward<F>(func));
+  auto f = p->getFuture();
+
+  setCallback_(
+    [p, funcm](Try<T>&& t) mutable {
+      if (t.hasException()) {
+        p->setException(std::move(t.exception()));
+      } else {
+        p->fulfil([&]() {
+          return (*funcm)(std::move(t.value()));
+        });
+      }
+    });
+
+  return f;
+}
+
+// Variant: f.then([](){ return; });
+template <class T>
+template <class F>
+typename std::enable_if<
+  std::is_same<T, void>::value &&
+  !isFuture<typename std::result_of<F()>::type>::value,
+  Future<typename std::result_of<F()>::type> >::type
+Future<T>::then(F&& func) {
+  typedef typename std::result_of<F()>::type B;
+
+  throwIfInvalid();
+
+  folly::MoveWrapper<Promise<B>> p;
+  folly::MoveWrapper<F> funcm(std::forward<F>(func));
+  auto f = p->getFuture();
+
+  setCallback_(
+    [p, funcm](Try<T>&& t) mutable {
+      if (t.hasException()) {
+        p->setException(std::move(t.exception()));
+      } else {
+        p->fulfil([&]() {
+          return (*funcm)();
+        });
+      }
+    });
+
+  return f;
+}
+
+// Variant: f.then([](Try<T>&& t){ return makeFuture<T>(t.value()); });
+template <class T>
+template <class F>
+typename std::enable_if<
+  isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
+  Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
+Future<T>::then(F&& func) {
+  typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
+
+  throwIfInvalid();
+
+  // wrap these so we can move them into the lambda
+  folly::MoveWrapper<Promise<B>> p;
+  folly::MoveWrapper<F> funcm(std::forward<F>(func));
+
+  // grab the Future now before we lose our handle on the Promise
+  auto f = p->getFuture();
+
+  setCallback_(
+    [p, funcm](Try<T>&& t) mutable {
+      try {
+        auto f2 = (*funcm)(std::move(t));
+        // that didn't throw, now we can steal p
+        f2.setCallback_([p](Try<B>&& b) mutable {
+          p->fulfilTry(std::move(b));
+        });
+      } catch (const std::exception& e) {
+        p->setException(exception_wrapper(std::current_exception(), e));
+      } catch (...) {
+        p->setException(exception_wrapper(std::current_exception()));
+      }
+    });
+
+  return f;
+}
+
+// Variant: f.then([](T&& t){ return makeFuture<T>(t); });
+template <class T>
+template <class F>
+typename std::enable_if<
+  !std::is_same<T, void>::value &&
+  isFuture<typename std::result_of<
+    F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
+  Future<typename std::result_of<
+    F(typename detail::AliasIfVoid<T>::type&&)>::type::value_type> >::type
+Future<T>::then(F&& func) {
+  typedef typename std::result_of<F(T&&)>::type::value_type B;
+
+  throwIfInvalid();
+
+  folly::MoveWrapper<Promise<B>> p;
+  folly::MoveWrapper<F> funcm(std::forward<F>(func));
+  auto f = p->getFuture();
+
+  setCallback_(
+    [p, funcm](Try<T>&& t) mutable {
+      if (t.hasException()) {
+        p->setException(std::move(t.exception()));
+      } else {
+        try {
+          auto f2 = (*funcm)(std::move(t.value()));
+          f2.setCallback_([p](Try<B>&& b) mutable {
+            p->fulfilTry(std::move(b));
+          });
+        } catch (const std::exception& e) {
+          p->setException(exception_wrapper(std::current_exception(), e));
+        } catch (...) {
+          p->setException(exception_wrapper(std::current_exception()));
+        }
+      }
+    });
+
+  return f;
+}
+
+// Variant: f.then([](){ return makeFuture(); });
+template <class T>
+template <class F>
+typename std::enable_if<
+  std::is_same<T, void>::value &&
+  isFuture<typename std::result_of<F()>::type>::value,
+  Future<typename std::result_of<F()>::type::value_type> >::type
+Future<T>::then(F&& func) {
+  typedef typename std::result_of<F()>::type::value_type B;
+
+  throwIfInvalid();
+
+  folly::MoveWrapper<Promise<B>> p;
+  folly::MoveWrapper<F> funcm(std::forward<F>(func));
+
+  auto f = p->getFuture();
+
+  setCallback_(
+    [p, funcm](Try<T>&& t) mutable {
+      if (t.hasException()) {
+        p->setException(t.exception());
+      } else {
+        try {
+          auto f2 = (*funcm)();
+          f2.setCallback_([p](Try<B>&& b) mutable {
+            p->fulfilTry(std::move(b));
+          });
+        } catch (const std::exception& e) {
+          p->setException(exception_wrapper(std::current_exception(), e));
+        } catch (...) {
+          p->setException(exception_wrapper(std::current_exception()));
+        }
+      }
+    });
+
+  return f;
+}
+
+template <class T>
+Future<void> Future<T>::then() {
+  return then([] (Try<T>&& t) {});
+}
+
+// onError where the callback returns T
+template <class T>
+template <class F>
+typename std::enable_if<
+  !detail::Extract<F>::ReturnsFuture::value,
+  Future<T>>::type
+Future<T>::onError(F&& func) {
+  typedef typename detail::Extract<F>::FirstArg Exn;
+  static_assert(
+      std::is_same<typename detail::Extract<F>::RawReturn, T>::value,
+      "Return type of onError callback must be T or Future<T>");
+
+  Promise<T> p;
+  auto f = p.getFuture();
+  auto pm = folly::makeMoveWrapper(std::move(p));
+  auto funcm = folly::makeMoveWrapper(std::move(func));
+  setCallback_([pm, funcm](Try<T>&& t) mutable {
+    if (!t.template withException<Exn>([&] (Exn& e) {
+          pm->fulfil([&]{
+            return (*funcm)(e);
+          });
+        })) {
+      pm->fulfilTry(std::move(t));
+    }
+  });
+
+  return f;
+}
+
+// onError where the callback returns Future<T>
+template <class T>
+template <class F>
+typename std::enable_if<
+  detail::Extract<F>::ReturnsFuture::value,
+  Future<T>>::type
+Future<T>::onError(F&& func) {
+  static_assert(
+      std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
+      "Return type of onError callback must be T or Future<T>");
+  typedef typename detail::Extract<F>::FirstArg Exn;
+
+  Promise<T> p;
+  auto f = p.getFuture();
+  auto pm = folly::makeMoveWrapper(std::move(p));
+  auto funcm = folly::makeMoveWrapper(std::move(func));
+  setCallback_([pm, funcm](Try<T>&& t) mutable {
+    if (!t.template withException<Exn>([&] (Exn& e) {
+          try {
+            auto f2 = (*funcm)(e);
+            f2.setCallback_([pm](Try<T>&& t2) mutable {
+              pm->fulfilTry(std::move(t2));
+            });
+          } catch (const std::exception& e2) {
+            pm->setException(exception_wrapper(std::current_exception(), e2));
+          } catch (...) {
+            pm->setException(exception_wrapper(std::current_exception()));
+          }
+        })) {
+      pm->fulfilTry(std::move(t));
+    }
+  });
+
+  return f;
+}
+
+template <class T>
+typename std::add_lvalue_reference<T>::type Future<T>::value() {
+  throwIfInvalid();
+
+  return core_->getTry().value();
+}
+
+template <class T>
+typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
+  throwIfInvalid();
+
+  return core_->getTry().value();
+}
+
+template <class T>
+Try<T>& Future<T>::getTry() {
+  throwIfInvalid();
+
+  return core_->getTry();
+}
+
+template <class T>
+template <typename Executor>
+inline Future<T> Future<T>::via(Executor* executor) && {
+  throwIfInvalid();
+
+  this->deactivate();
+  core_->setExecutor(executor);
+
+  return std::move(*this);
+}
+
+template <class T>
+template <typename Executor>
+inline Future<T> Future<T>::via(Executor* executor) & {
+  throwIfInvalid();
+
+  MoveWrapper<Promise<T>> p;
+  auto f = p->getFuture();
+  then([p](Try<T>&& t) mutable { p->fulfilTry(std::move(t)); });
+  return std::move(f).via(executor);
+}
+
+template <class T>
+bool Future<T>::isReady() const {
+  throwIfInvalid();
+  return core_->ready();
+}
+
+template <class T>
+void Future<T>::raise(exception_wrapper exception) {
+  core_->raise(std::move(exception));
+}
+
+// makeFuture
+
+template <class T>
+Future<typename std::decay<T>::type> makeFuture(T&& t) {
+  Promise<typename std::decay<T>::type> p;
+  p.setValue(std::forward<T>(t));
+  return p.getFuture();
+}
+
+inline // for multiple translation units
+Future<void> makeFuture() {
+  Promise<void> p;
+  p.setValue();
+  return p.getFuture();
+}
+
+template <class F>
+auto makeFutureTry(
+    F&& func,
+    typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
+    -> Future<decltype(func())> {
+  Promise<decltype(func())> p;
+  p.fulfil(
+    [&func]() {
+      return (func)();
+    });
+  return p.getFuture();
+}
+
+template <class F>
+auto makeFutureTry(F const& func) -> Future<decltype(func())> {
+  F copy = func;
+  return makeFutureTry(std::move(copy));
+}
+
+template <class T>
+Future<T> makeFuture(std::exception_ptr const& e) {
+  Promise<T> p;
+  p.setException(e);
+  return p.getFuture();
+}
+
+template <class T>
+Future<T> makeFuture(exception_wrapper ew) {
+  Promise<T> p;
+  p.setException(std::move(ew));
+  return p.getFuture();
+}
+
+template <class T, class E>
+typename std::enable_if<std::is_base_of<std::exception, E>::value,
+                        Future<T>>::type
+makeFuture(E const& e) {
+  Promise<T> p;
+  p.setException(make_exception_wrapper<E>(e));
+  return p.getFuture();
+}
+
+template <class T>
+Future<T> makeFuture(Try<T>&& t) {
+  if (t.hasException()) {
+    return makeFuture<T>(std::move(t.exception()));
+  } else {
+    return makeFuture<T>(std::move(t.value()));
+  }
+}
+
+template <>
+inline Future<void> makeFuture(Try<void>&& t) {
+  if (t.hasException()) {
+    return makeFuture<void>(std::move(t.exception()));
+  } else {
+    return makeFuture();
+  }
+}
+
+// via
+template <typename Executor>
+Future<void> via(Executor* executor) {
+  return makeFuture().via(executor);
+}
+
+// when (variadic)
+
+template <typename... Fs>
+typename detail::VariadicContext<
+  typename std::decay<Fs>::type::value_type...>::type
+whenAll(Fs&&... fs)
+{
+  auto ctx =
+    new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
+  ctx->total = sizeof...(fs);
+  auto f_saved = ctx->p.getFuture();
+  detail::whenAllVariadicHelper(ctx,
+    std::forward<typename std::decay<Fs>::type>(fs)...);
+  return f_saved;
+}
+
+// when (iterator)
+
+template <class InputIterator>
+Future<
+  std::vector<
+  Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
+whenAll(InputIterator first, InputIterator last)
+{
+  typedef
+    typename std::iterator_traits<InputIterator>::value_type::value_type T;
+
+  if (first >= last) {
+    return makeFuture(std::vector<Try<T>>());
+  }
+  size_t n = std::distance(first, last);
+
+  auto ctx = new detail::WhenAllContext<T>();
+
+  ctx->results.resize(n);
+
+  auto f_saved = ctx->p.getFuture();
+
+  for (size_t i = 0; first != last; ++first, ++i) {
+     assert(i < n);
+     auto& f = *first;
+     f.setCallback_([ctx, i, n](Try<T>&& t) {
+         ctx->results[i] = std::move(t);
+         if (++ctx->count == n) {
+           ctx->p.setValue(std::move(ctx->results));
+           delete ctx;
+         }
+       });
+  }
+
+  return f_saved;
+}
+
+template <class InputIterator>
+Future<
+  std::pair<size_t,
+            Try<
+              typename
+              std::iterator_traits<InputIterator>::value_type::value_type> > >
+whenAny(InputIterator first, InputIterator last) {
+  typedef
+    typename std::iterator_traits<InputIterator>::value_type::value_type T;
+
+  auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
+  auto f_saved = ctx->p.getFuture();
+
+  for (size_t i = 0; first != last; first++, i++) {
+    auto& f = *first;
+    f.setCallback_([i, ctx](Try<T>&& t) {
+      if (!ctx->done.exchange(true)) {
+        ctx->p.setValue(std::make_pair(i, std::move(t)));
+      }
+      ctx->decref();
+    });
+  }
+
+  return f_saved;
+}
+
+template <class InputIterator>
+Future<std::vector<std::pair<size_t, Try<typename
+  std::iterator_traits<InputIterator>::value_type::value_type>>>>
+whenN(InputIterator first, InputIterator last, size_t n) {
+  typedef typename
+    std::iterator_traits<InputIterator>::value_type::value_type T;
+  typedef std::vector<std::pair<size_t, Try<T>>> V;
+
+  struct ctx_t {
+    V v;
+    size_t completed;
+    Promise<V> p;
+  };
+  auto ctx = std::make_shared<ctx_t>();
+  ctx->completed = 0;
+
+  // for each completed Future, increase count and add to vector, until we
+  // have n completed futures at which point we fulfil our Promise with the
+  // vector
+  auto it = first;
+  size_t i = 0;
+  while (it != last) {
+    it->then([ctx, n, i](Try<T>&& t) {
+      auto& v = ctx->v;
+      auto c = ++ctx->completed;
+      if (c <= n) {
+        assert(ctx->v.size() < n);
+        v.push_back(std::make_pair(i, std::move(t)));
+        if (c == n) {
+          ctx->p.fulfilTry(Try<V>(std::move(v)));
+        }
+      }
+    });
+
+    it++;
+    i++;
+  }
+
+  if (i < n) {
+    ctx->p.setException(std::runtime_error("Not enough futures"));
+  }
+
+  return ctx->p.getFuture();
+}
+
+template <typename T>
+Future<T>
+waitWithSemaphore(Future<T>&& f) {
+  Baton<> baton;
+  auto done = f.then([&](Try<T> &&t) {
+    baton.post();
+    return std::move(t.value());
+  });
+  baton.wait();
+  while (!done.isReady()) {
+    // There's a race here between the return here and the actual finishing of
+    // the future. f is completed, but the setup may not have finished on done
+    // after the baton has posted.
+    std::this_thread::yield();
+  }
+  return done;
+}
+
+template<>
+inline Future<void> waitWithSemaphore<void>(Future<void>&& f) {
+  Baton<> baton;
+  auto done = f.then([&](Try<void> &&t) {
+    baton.post();
+    t.value();
+  });
+  baton.wait();
+  while (!done.isReady()) {
+    // There's a race here between the return here and the actual finishing of
+    // the future. f is completed, but the setup may not have finished on done
+    // after the baton has posted.
+    std::this_thread::yield();
+  }
+  return done;
+}
+
+template <typename T, class Dur>
+Future<T>
+waitWithSemaphore(Future<T>&& f, Dur timeout) {
+  auto baton = std::make_shared<Baton<>>();
+  auto done = f.then([baton](Try<T> &&t) {
+    baton->post();
+    return std::move(t.value());
+  });
+  baton->timed_wait(std::chrono::system_clock::now() + timeout);
+  return done;
+}
+
+template <class Dur>
+Future<void>
+waitWithSemaphore(Future<void>&& f, Dur timeout) {
+  auto baton = std::make_shared<Baton<>>();
+  auto done = f.then([baton](Try<void> &&t) {
+    baton->post();
+    t.value();
+  });
+  baton->timed_wait(std::chrono::system_clock::now() + timeout);
+  return done;
+}
+
+namespace {
+  template <class T>
+  void getWaitHelper(Future<T>* f) {
+    // If we already have a value do the cheap thing
+    if (f->isReady()) {
+      return;
+    }
+
+    folly::Baton<> baton;
+    f->then([&](Try<T> const&) {
+      baton.post();
+    });
+    baton.wait();
+  }
+
+  template <class T>
+  Future<T> getWaitTimeoutHelper(Future<T>* f, Duration dur) {
+    // TODO make and use variadic whenAny #5877971
+    Promise<T> p;
+    auto token = std::make_shared<std::atomic<bool>>();
+    folly::Baton<> baton;
+
+    folly::wangle::detail::getTimekeeperSingleton()->after(dur)
+      .then([&,token](Try<void> const& t) {
+        if (token->exchange(true) == false) {
+          try {
+            t.value();
+            p.setException(TimedOut());
+          } catch (std::exception const& e) {
+            p.setException(exception_wrapper(std::current_exception(), e));
+          } catch (...) {
+            p.setException(exception_wrapper(std::current_exception()));
+          }
+          baton.post();
+        }
+      });
+
+    f->then([&, token](Try<T>&& t) {
+      if (token->exchange(true) == false) {
+        p.fulfilTry(std::move(t));
+        baton.post();
+      }
+    });
+
+    baton.wait();
+    return p.getFuture();
+  }
+}
+
+template <class T>
+T Future<T>::get() {
+  getWaitHelper(this);
+
+  // Big assumption here: the then() call above, since it doesn't move out
+  // the value, leaves us with a value to return here. This would be a big
+  // no-no in user code, but I'm invoking internal developer privilege. This
+  // is slightly more efficient (save a move()) especially if there's an
+  // exception (save a throw).
+  return std::move(value());
+}
+
+template <>
+inline void Future<void>::get() {
+  getWaitHelper(this);
+  value();
+}
+
+template <class T>
+T Future<T>::get(Duration dur) {
+  return std::move(getWaitTimeoutHelper(this, dur).value());
+}
+
+template <>
+inline void Future<void>::get(Duration dur) {
+  getWaitTimeoutHelper(this, dur).value();
+}
+
+template <class T>
+Future<T> Future<T>::within(Duration dur, Timekeeper* tk) {
+  return within(dur, TimedOut(), tk);
+}
+
+template <class T>
+template <class E>
+Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
+
+  struct Context {
+    Context(E ex) : exception(std::move(ex)), promise(), token(false) {}
+    E exception;
+    Promise<T> promise;
+    std::atomic<bool> token;
+  };
+  auto ctx = std::make_shared<Context>(std::move(e));
+
+  if (!tk) {
+    tk = folly::wangle::detail::getTimekeeperSingleton();
+  }
+
+  tk->after(dur)
+    .then([ctx](Try<void> const& t) {
+      if (ctx->token.exchange(true) == false) {
+        try {
+          t.throwIfFailed();
+          ctx->promise.setException(std::move(ctx->exception));
+        } catch (std::exception const& e2) {
+          ctx->promise.setException(
+              exception_wrapper(std::current_exception(), e2));
+        } catch (...) {
+          ctx->promise.setException(
+              exception_wrapper(std::current_exception()));
+        }
+      }
+    });
+
+  this->then([ctx](Try<T>&& t) {
+    if (ctx->token.exchange(true) == false) {
+      ctx->promise.fulfilTry(std::move(t));
+    }
+  });
+
+  return ctx->promise.getFuture();
+}
+
+template <class T>
+Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) {
+  return whenAll(*this, futures::sleep(dur, tk))
+    .then([](Try<std::tuple<Try<T>, Try<void>>>&& tup) {
+      Try<T>& t = std::get<0>(tup.value());
+      return makeFuture<T>(std::move(t));
+    });
+}
+
+}}
+
+// I haven't included a Future<T&> specialization because I don't forsee us
+// using it, however it is not difficult to add when needed. Refer to
+// Future<void> for guidance. std::future and boost::future code would also be
+// instructive.
diff --git a/folly/futures/Future.cpp b/folly/futures/Future.cpp
new file mode 100644 (file)
index 0000000..fc7ff9b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <folly/futures/Future.h>
+#include <folly/futures/detail/ThreadWheelTimekeeper.h>
+#include <folly/Likely.h>
+
+namespace folly { namespace wangle { namespace futures {
+
+Future<void> sleep(Duration dur, Timekeeper* tk) {
+  if (LIKELY(!tk)) {
+    tk = detail::getTimekeeperSingleton();
+  }
+  return tk->after(dur);
+}
+
+}}}
diff --git a/folly/futures/Future.h b/folly/futures/Future.h
new file mode 100644 (file)
index 0000000..e61c530
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <exception>
+#include <functional>
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+#include <folly/MoveWrapper.h>
+#include <folly/futures/Deprecated.h>
+#include <folly/futures/Promise.h>
+#include <folly/futures/Try.h>
+#include <folly/futures/WangleException.h>
+#include <folly/futures/detail/Types.h>
+
+namespace folly { namespace wangle {
+
+template <class> struct Promise;
+
+namespace detail {
+
+template <class> struct Core;
+template <class...> struct VariadicContext;
+
+template <class T>
+struct AliasIfVoid {
+  typedef typename std::conditional<
+    std::is_same<T, void>::value,
+    int,
+    T>::type type;
+};
+
+
+template <typename T>
+struct IsFuture : std::integral_constant<bool, false> {
+    typedef T Inner;
+};
+
+template <template <typename T> class Future, typename T>
+struct IsFuture<Future<T>> : std::integral_constant<bool, true> {
+    typedef T Inner;
+};
+
+template <typename...>
+struct ArgType;
+
+template <typename Arg, typename... Args>
+struct ArgType<Arg, Args...> {
+  typedef Arg FirstArg;
+};
+
+template <>
+struct ArgType<> {
+  typedef void FirstArg;
+};
+
+template <typename L>
+struct Extract : Extract<decltype(&L::operator())> { };
+
+template <typename Class, typename R, typename... Args>
+struct Extract<R(Class::*)(Args...) const> {
+  typedef IsFuture<R> ReturnsFuture;
+  typedef Future<typename ReturnsFuture::Inner> Return;
+  typedef typename ReturnsFuture::Inner RawReturn;
+  typedef typename ArgType<Args...>::FirstArg FirstArg;
+};
+
+template <typename Class, typename R, typename... Args>
+struct Extract<R(Class::*)(Args...)> {
+  typedef IsFuture<R> ReturnsFuture;
+  typedef Future<typename ReturnsFuture::Inner> Return;
+  typedef typename ReturnsFuture::Inner RawReturn;
+  typedef typename ArgType<Args...>::FirstArg FirstArg;
+};
+
+
+} // detail
+
+struct Timekeeper;
+
+template <typename T> struct isFuture;
+
+/// 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
+/// some cases). This is the least-bad naming scheme we could think of. Some
+/// of the functions herein have really-likely-to-collide names, like "map"
+/// and "sleep".
+namespace futures {
+  /// Returns a Future that will complete after the specified duration. The
+  /// Duration typedef of a `std::chrono` duration type indicates the
+  /// resolution you can expect to be meaningful (milliseconds at the time of
+  /// writing). Normally you wouldn't need to specify a Timekeeper, we will
+  /// use the global wangle timekeeper (we run a thread whose job it is to
+  /// keep time for wangle timeouts) but we provide the option for power
+  /// users.
+  ///
+  /// The Timekeeper thread will be lazily created the first time it is
+  /// needed. If your program never uses any timeouts or other time-based
+  /// Futures you will pay no Timekeeper thread overhead.
+  Future<void> sleep(Duration, Timekeeper* = nullptr);
+}
+
+template <class T>
+class Future {
+ public:
+  typedef T value_type;
+
+  // not copyable
+  Future(Future const&) = delete;
+  Future& operator=(Future const&) = delete;
+
+  // movable
+  Future(Future&&) noexcept;
+  Future& operator=(Future&&);
+
+  ~Future();
+
+  /** Return the reference to result. Should not be called if !isReady().
+    Will rethrow the exception if an exception has been
+    captured.
+
+    This function is not thread safe - the returned Future can only
+    be executed from the thread that the executor runs it in.
+    See below for a thread safe version
+    */
+  typename std::add_lvalue_reference<T>::type
+  value();
+  typename std::add_lvalue_reference<const T>::type
+  value() const;
+
+  /// Returns an inactive Future which will call back on the other side of
+  /// executor (when it is activated).
+  ///
+  /// NB remember that Futures activate when they destruct. This is good,
+  /// it means that this will work:
+  ///
+  ///   f.via(e).then(a).then(b);
+  ///
+  /// a and b will execute in the same context (the far side of e), because
+  /// the Future (temporary variable) created by via(e) does not call back
+  /// until it destructs, which is after then(a) and then(b) have been wired
+  /// up.
+  ///
+  /// But this is still racy:
+  ///
+  ///   f = f.via(e).then(a);
+  ///   f.then(b);
+  // The ref-qualifier allows for `this` to be moved out so we
+  // don't get access-after-free situations in chaining.
+  // https://akrzemi1.wordpress.com/2014/06/02/ref-qualifiers/
+  template <typename Executor>
+  Future<T> via(Executor* executor) &&;
+
+  /// This variant creates a new future, where the ref-qualifier && version
+  /// moves `this` out. This one is less efficient but avoids confusing users
+  /// when "return f.via(x);" fails.
+  template <typename Executor>
+  Future<T> via(Executor* executor) &;
+
+  /** True when the result (or exception) is ready. */
+  bool isReady() const;
+
+  /** A reference to the Try of the value */
+  Try<T>& getTry();
+
+  /// Block until the future is fulfilled. Returns the value (moved out), or
+  /// throws the exception. The future must not already have a callback.
+  T get();
+
+  /// Block until the future is fulfilled, or until timed out. Returns the
+  /// value (moved out), or throws the exception (which might be a TimedOut
+  /// exception).
+  T get(Duration dur);
+
+  /** When this Future has completed, execute func which is a function that
+    takes a Try<T>&&. A Future for the return type of func is
+    returned. e.g.
+
+    Future<string> f2 = f1.then([](Try<T>&&) { return string("foo"); });
+
+    The Future given to the functor is ready, and the functor may call
+    value(), which may rethrow if this has captured an exception. If func
+    throws, the exception will be captured in the Future that is returned.
+    */
+  /* TODO n3428 and other async frameworks have something like then(scheduler,
+     Future), we might want to support a similar API which could be
+     implemented a little more efficiently than
+     f.via(executor).then(callback) */
+  template <class F>
+  typename std::enable_if<
+    !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
+    Future<typename std::result_of<F(Try<T>&&)>::type> >::type
+  then(F&& func);
+
+  /// Variant where func takes a T directly, bypassing a try. Any exceptions
+  /// will be implicitly passed on to the resultant Future.
+  ///
+  ///   Future<int> f = makeFuture<int>(42).then([](int i) { return i+1; });
+  template <class F>
+  typename std::enable_if<
+    !std::is_same<T, void>::value &&
+    !isFuture<typename std::result_of<
+      F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
+    Future<typename std::result_of<
+      F(typename detail::AliasIfVoid<T>::type&&)>::type> >::type
+  then(F&& func);
+
+  /// Like the above variant, but for void futures. That is, func takes no
+  /// argument.
+  ///
+  ///   Future<int> f = makeFuture().then([] { return 42; });
+  template <class F>
+  typename std::enable_if<
+    std::is_same<T, void>::value &&
+    !isFuture<typename std::result_of<F()>::type>::value,
+    Future<typename std::result_of<F()>::type> >::type
+  then(F&& func);
+
+  /// Variant where func returns a Future<T> instead of a T. e.g.
+  ///
+  ///   Future<string> f2 = f1.then(
+  ///     [](Try<T>&&) { return makeFuture<string>("foo"); });
+  template <class F>
+  typename std::enable_if<
+    isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
+    Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
+  then(F&& func);
+
+  /// Variant where func returns a Future<T2> and takes a T directly, bypassing
+  /// a Try. Any exceptions will be implicitly passed on to the resultant
+  /// Future. For example,
+  ///
+  ///   Future<int> f = makeFuture<int>(42).then(
+  ///     [](int i) { return makeFuture<int>(i+1); });
+  template <class F>
+  typename std::enable_if<
+    !std::is_same<T, void>::value &&
+    isFuture<typename std::result_of<
+      F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
+    Future<typename std::result_of<
+      F(typename detail::AliasIfVoid<T>::type&&)>::type::value_type> >::type
+  then(F&& func);
+
+  /// Like the above variant, but for void futures. That is, func takes no
+  /// argument and returns a future.
+  ///
+  ///   Future<int> f = makeFuture().then(
+  ///     [] { return makeFuture<int>(42); });
+  template <class F>
+  typename std::enable_if<
+    std::is_same<T, void>::value &&
+    isFuture<typename std::result_of<F()>::type>::value,
+    Future<typename std::result_of<F()>::type::value_type> >::type
+  then(F&& func);
+
+  /// Variant where func is an ordinary function (static method, method)
+  ///
+  ///   R doWork(Try<T>&&);
+  ///
+  ///   Future<R> f2 = f1.then(doWork);
+  ///
+  /// or
+  ///
+  ///   struct Worker {
+  ///     static R doWork(Try<T>&&); }
+  ///
+  ///   Future<R> f2 = f1.then(&Worker::doWork);
+  template <class = T, class R = std::nullptr_t>
+  typename std::enable_if<!isFuture<R>::value, Future<R>>::type
+  inline then(R(*func)(Try<T>&&)) {
+    return then([func](Try<T>&& t) {
+      return (*func)(std::move(t));
+    });
+  }
+
+  /// Variant where func returns a Future<R> instead of a R. e.g.
+  ///
+  ///   struct Worker {
+  ///     Future<R> doWork(Try<T>&&); }
+  ///
+  ///   Future<R> f2 = f1.then(&Worker::doWork);
+  template <class = T, class R = std::nullptr_t>
+  typename std::enable_if<isFuture<R>::value, R>::type
+  inline then(R(*func)(Try<T>&&)) {
+    return then([func](Try<T>&& t) {
+      return (*func)(std::move(t));
+    });
+  }
+
+  /// Variant where func is an member function
+  ///
+  ///   struct Worker {
+  ///     R doWork(Try<T>&&); }
+  ///
+  ///   Worker *w;
+  ///   Future<R> f2 = f1.then(w, &Worker::doWork);
+  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
+  typename std::enable_if<!isFuture<R>::value, Future<R>>::type
+  inline then(Caller *instance, R(Caller::*func)(Try<T>&&)) {
+    return then([instance, func](Try<T>&& t) {
+      return (instance->*func)(std::move(t));
+    });
+  }
+
+  // Same as above, but func takes void instead of Try<void>&&
+  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
+  typename std::enable_if<
+      std::is_same<T, void>::value && !isFuture<R>::value, Future<R>>::type
+  inline then(Caller *instance, R(Caller::*func)()) {
+    return then([instance, func]() {
+      return (instance->*func)();
+    });
+  }
+
+  // Same as above, but func takes T&& instead of Try<T>&&
+  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
+  typename std::enable_if<
+      !std::is_same<T, void>::value && !isFuture<R>::value, Future<R>>::type
+  inline then(
+      Caller *instance,
+      R(Caller::*func)(typename detail::AliasIfVoid<T>::type&&)) {
+    return then([instance, func](T&& t) {
+      return (instance->*func)(std::move(t));
+    });
+  }
+
+  /// Variant where func returns a Future<R> instead of a R. e.g.
+  ///
+  ///   struct Worker {
+  ///     Future<R> doWork(Try<T>&&); }
+  ///
+  ///   Worker *w;
+  ///   Future<R> f2 = f1.then(w, &Worker::doWork);
+  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
+  typename std::enable_if<isFuture<R>::value, R>::type
+  inline then(Caller *instance, R(Caller::*func)(Try<T>&&)) {
+    return then([instance, func](Try<T>&& t) {
+      return (instance->*func)(std::move(t));
+    });
+  }
+
+  // Same as above, but func takes void instead of Try<void>&&
+  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
+  typename std::enable_if<
+      std::is_same<T, void>::value && isFuture<R>::value, R>::type
+  inline then(Caller *instance, R(Caller::*func)()) {
+    return then([instance, func]() {
+      return (instance->*func)();
+    });
+  }
+
+  // Same as above, but func takes T&& instead of Try<T>&&
+  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
+  typename std::enable_if<
+      !std::is_same<T, void>::value && isFuture<R>::value, R>::type
+  inline then(
+      Caller *instance,
+      R(Caller::*func)(typename detail::AliasIfVoid<T>::type&&)) {
+    return then([instance, func](T&& t) {
+      return (instance->*func)(std::move(t));
+    });
+  }
+
+  /// Convenience method for ignoring the value and creating a Future<void>.
+  /// Exceptions still propagate.
+  Future<void> then();
+
+  /// Set an error callback for this Future. The callback should take a single
+  /// argument of the type that you want to catch, and should return a value of
+  /// the same type as this Future, or a Future of that type (see overload
+  /// below). For instance,
+  ///
+  /// makeFuture()
+  ///   .then([] {
+  ///     throw std::runtime_error("oh no!");
+  ///     return 42;
+  ///   })
+  ///   .onError([] (std::runtime_error& e) {
+  ///     LOG(INFO) << "std::runtime_error: " << e.what();
+  ///     return -1; // or makeFuture<int>(-1)
+  ///   });
+  template <class F>
+  typename std::enable_if<
+    !detail::Extract<F>::ReturnsFuture::value,
+    Future<T>>::type
+  onError(F&& func);
+
+  /// Overload of onError where the error callback returns a Future<T>
+  template <class F>
+  typename std::enable_if<
+    detail::Extract<F>::ReturnsFuture::value,
+    Future<T>>::type
+  onError(F&& func);
+
+  /// This is not the method you're looking for.
+  ///
+  /// This needs to be public because it's used by make* and when*, and it's
+  /// not worth listing all those and their fancy template signatures as
+  /// friends. But it's not for public consumption.
+  template <class F>
+  void setCallback_(F&& func);
+
+  /// A Future's callback is executed when all three of these conditions have
+  /// become true: it has a value (set by the Promise), it has a callback (set
+  /// by then), and it is active (active by default).
+  ///
+  /// Inactive Futures will activate upon destruction.
+  Future<T>& activate() & {
+    core_->activate();
+    return *this;
+  }
+  Future<T>& deactivate() & {
+    core_->deactivate();
+    return *this;
+  }
+  Future<T> activate() && {
+    core_->activate();
+    return std::move(*this);
+  }
+  Future<T> deactivate() && {
+    core_->deactivate();
+    return std::move(*this);
+  }
+
+  bool isActive() {
+    return core_->isActive();
+  }
+
+  template <class E>
+  void raise(E&& exception) {
+    raise(make_exception_wrapper<typename std::remove_reference<E>::type>(
+        std::move(exception)));
+  }
+
+  /// Raise an interrupt. If the promise holder has an interrupt
+  /// handler it will be called and potentially stop asynchronous work from
+  /// being done. This is advisory only - a promise holder may not set an
+  /// interrupt handler, or may do anything including ignore. But, if you know
+  /// your future supports this the most likely result is stopping or
+  /// preventing the asynchronous operation (if in time), and the promise
+  /// holder setting an exception on the future. (That may happen
+  /// asynchronously, of course.)
+  void raise(exception_wrapper interrupt);
+
+  void cancel() {
+    raise(FutureCancellation());
+  }
+
+  /// Throw TimedOut if this Future does not complete within the given
+  /// duration from now. The optional Timeekeeper is as with futures::sleep().
+  Future<T> within(Duration, Timekeeper* = nullptr);
+
+  /// Throw the given exception if this Future does not complete within the
+  /// given duration from now. The optional Timeekeeper is as with
+  /// futures::sleep().
+  template <class E>
+  Future<T> within(Duration, E exception, Timekeeper* = nullptr);
+
+  /// Delay the completion of this Future for at least this duration from
+  /// now. The optional Timekeeper is as with futures::sleep().
+  Future<T> delayed(Duration, Timekeeper* = nullptr);
+
+ private:
+  typedef detail::Core<T>* corePtr;
+
+  // shared core state object
+  corePtr core_;
+
+  explicit
+  Future(corePtr obj) : core_(obj) {}
+
+  void detach();
+
+  void throwIfInvalid() const;
+
+  friend class Promise<T>;
+};
+
+/**
+  Make a completed Future by moving in a value. e.g.
+
+    string foo = "foo";
+    auto f = makeFuture(std::move(foo));
+
+  or
+
+    auto f = makeFuture<string>("foo");
+*/
+template <class T>
+Future<typename std::decay<T>::type> makeFuture(T&& t);
+
+/** Make a completed void Future. */
+Future<void> makeFuture();
+
+/** Make a completed Future by executing a function. If the function throws
+  we capture the exception, otherwise we capture the result. */
+template <class F>
+auto makeFutureTry(
+  F&& func,
+  typename std::enable_if<
+    !std::is_reference<F>::value, bool>::type sdf = false)
+  -> Future<decltype(func())>;
+
+template <class F>
+auto makeFutureTry(
+  F const& func)
+  -> Future<decltype(func())>;
+
+/// Make a failed Future from an exception_ptr.
+/// Because the Future's type cannot be inferred you have to specify it, e.g.
+///
+///   auto f = makeFuture<string>(std::current_exception());
+template <class T>
+Future<T> makeFuture(std::exception_ptr const& e) DEPRECATED;
+
+/// Make a failed Future from an exception_wrapper.
+template <class T>
+Future<T> makeFuture(exception_wrapper ew);
+
+/** Make a Future from an exception type E that can be passed to
+  std::make_exception_ptr(). */
+template <class T, class E>
+typename std::enable_if<std::is_base_of<std::exception, E>::value,
+                        Future<T>>::type
+makeFuture(E const& e);
+
+/** Make a Future out of a Try */
+template <class T>
+Future<T> makeFuture(Try<T>&& t);
+
+/*
+ * Return a new Future that will call back on the given Executor.
+ * This is just syntactic sugar for makeFuture().via(executor)
+ *
+ * @param executor the Executor to call back on
+ *
+ * @returns a void Future that will call back on the given executor
+ */
+template <typename Executor>
+Future<void> via(Executor* executor);
+
+/** When all the input Futures complete, the returned Future will complete.
+  Errors do not cause early termination; this Future will always succeed
+  after all its Futures have finished (whether successfully or with an
+  error).
+
+  The Futures are moved in, so your copies are invalid. If you need to
+  chain further from these Futures, use the variant with an output iterator.
+
+  XXX is this still true?
+  This function is thread-safe for Futures running on different threads.
+
+  The return type for Future<T> input is a Future<std::vector<Try<T>>>
+  */
+template <class InputIterator>
+Future<std::vector<Try<
+  typename std::iterator_traits<InputIterator>::value_type::value_type>>>
+whenAll(InputIterator first, InputIterator last);
+
+/// This version takes a varying number of Futures instead of an iterator.
+/// The return type for (Future<T1>, Future<T2>, ...) input
+/// is a Future<std::tuple<Try<T1>, Try<T2>, ...>>.
+/// The Futures are moved in, so your copies are invalid.
+template <typename... Fs>
+typename detail::VariadicContext<
+  typename std::decay<Fs>::type::value_type...>::type
+whenAll(Fs&&... fs);
+
+/** The result is a pair of the index of the first Future to complete and
+  the Try. If multiple Futures complete at the same time (or are already
+  complete when passed in), the "winner" is chosen non-deterministically.
+
+  This function is thread-safe for Futures running on different threads.
+  */
+template <class InputIterator>
+Future<std::pair<
+  size_t,
+  Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
+whenAny(InputIterator first, InputIterator last);
+
+/** when n Futures have completed, the Future completes with a vector of
+  the index and Try of those n Futures (the indices refer to the original
+  order, but the result vector will be in an arbitrary order)
+
+  Not thread safe.
+  */
+template <class InputIterator>
+Future<std::vector<std::pair<
+  size_t,
+  Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>>
+whenN(InputIterator first, InputIterator last, size_t n);
+
+/** Wait for the given future to complete on a semaphore. Returns a completed
+ * future containing the result.
+ *
+ * NB if the promise for the future would be fulfilled in the same thread that
+ * you call this, it will deadlock.
+ */
+template <class T>
+Future<T> waitWithSemaphore(Future<T>&& f);
+
+/** Wait for up to `timeout` for the given future to complete. Returns a future
+ * which may or may not be completed depending whether the given future
+ * completed in time
+ *
+ * Note: each call to this starts a (short-lived) thread and allocates memory.
+ */
+template <typename T, class Dur>
+Future<T> waitWithSemaphore(Future<T>&& f, Dur timeout);
+
+}} // folly::wangle
+
+#include <folly/futures/Future-inl.h>
diff --git a/folly/futures/InlineExecutor.cpp b/folly/futures/InlineExecutor.cpp
new file mode 100644 (file)
index 0000000..1ef2f06
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
diff --git a/folly/futures/InlineExecutor.h b/folly/futures/InlineExecutor.h
new file mode 100644 (file)
index 0000000..e692408
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <folly/Executor.h>
+
+namespace folly { namespace wangle {
+
+  /// When work is "queued", execute it immediately inline.
+  /// Usually when you think you want this, you actually want a
+  /// QueuedImmediateExecutor.
+  class InlineExecutor : public Executor {
+   public:
+    void add(Func f) override {
+      f();
+    }
+  };
+
+}}
diff --git a/folly/futures/ManualExecutor.cpp b/folly/futures/ManualExecutor.cpp
new file mode 100644 (file)
index 0000000..e75ae72
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/futures/ManualExecutor.h>
+
+#include <string.h>
+#include <string>
+#include <tuple>
+
+#include <stdexcept>
+
+namespace folly { namespace wangle {
+
+ManualExecutor::ManualExecutor() {
+  if (sem_init(&sem_, 0, 0) == -1) {
+    throw std::runtime_error(std::string("sem_init: ") + strerror(errno));
+  }
+}
+
+void ManualExecutor::add(Func callback) {
+  std::lock_guard<std::mutex> lock(lock_);
+  funcs_.push(std::move(callback));
+  sem_post(&sem_);
+}
+
+size_t ManualExecutor::run() {
+  size_t count;
+  size_t n;
+  Func func;
+
+  {
+    std::lock_guard<std::mutex> lock(lock_);
+
+    while (!scheduledFuncs_.empty()) {
+      auto& sf = scheduledFuncs_.top();
+      if (sf.time > now_)
+        break;
+      funcs_.push(sf.func);
+      scheduledFuncs_.pop();
+    }
+
+    n = funcs_.size();
+  }
+
+  for (count = 0; count < n; count++) {
+    {
+      std::lock_guard<std::mutex> lock(lock_);
+      if (funcs_.empty()) {
+        break;
+      }
+
+      // Balance the semaphore so it doesn't grow without bound
+      // if nobody is calling wait().
+      // This may fail (with EAGAIN), that's fine.
+      sem_trywait(&sem_);
+
+      func = std::move(funcs_.front());
+      funcs_.pop();
+    }
+    func();
+  }
+
+  return count;
+}
+
+void ManualExecutor::wait() {
+  while (true) {
+    {
+      std::lock_guard<std::mutex> lock(lock_);
+      if (!funcs_.empty())
+        break;
+    }
+
+    auto ret = sem_wait(&sem_);
+    if (ret == 0) {
+      break;
+    }
+    if (errno != EINVAL) {
+      throw std::runtime_error(std::string("sem_wait: ") + strerror(errno));
+    }
+  }
+}
+
+void ManualExecutor::advanceTo(TimePoint const& t) {
+  if (t > now_) {
+    now_ = t;
+  }
+  run();
+}
+
+}} // namespace
diff --git a/folly/futures/ManualExecutor.h b/folly/futures/ManualExecutor.h
new file mode 100644 (file)
index 0000000..b17a0bd
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <folly/futures/ScheduledExecutor.h>
+#include <semaphore.h>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <cstdio>
+
+namespace folly { namespace wangle {
+  /// A ManualExecutor only does work when you turn the crank, by calling
+  /// run() or indirectly with makeProgress() or waitFor().
+  ///
+  /// The clock for a manual executor starts at 0 and advances only when you
+  /// ask it to. i.e. time is also under manual control.
+  ///
+  /// NB No attempt has been made to make anything other than add and schedule
+  /// threadsafe.
+  class ManualExecutor : public ScheduledExecutor {
+   public:
+    ManualExecutor();
+
+    void add(Func) override;
+
+    /// Do work. Returns the number of functions that were executed (maybe 0).
+    /// Non-blocking, in the sense that we don't wait for work (we can't
+    /// control whether one of the functions blocks).
+    /// This is stable, it will not chase an ever-increasing tail of work.
+    /// This also means, there may be more work available to perform at the
+    /// moment that this returns.
+    size_t run();
+
+    /// Wait for work to do.
+    void wait();
+
+    /// Wait for work to do, and do it.
+    void makeProgress() {
+      wait();
+      run();
+    }
+
+    /// makeProgress until this Future is ready.
+    template <class F> void waitFor(F const& f) {
+      // TODO(5427828)
+#if 0
+      while (!f.isReady())
+        makeProgress();
+#else
+      while (!f.isReady()) {
+        run();
+      }
+#endif
+
+    }
+
+    virtual void scheduleAt(Func&& f, TimePoint const& t) override {
+      std::lock_guard<std::mutex> lock(lock_);
+      scheduledFuncs_.emplace(t, std::move(f));
+      sem_post(&sem_);
+    }
+
+    /// Advance the clock. The clock never advances on its own.
+    /// Advancing the clock causes some work to be done, if work is available
+    /// to do (perhaps newly available because of the advanced clock).
+    /// If dur is <= 0 this is a noop.
+    void advance(Duration const& dur) {
+      advanceTo(now_ + dur);
+    }
+
+    /// Advance the clock to this absolute time. If t is <= now(),
+    /// this is a noop.
+    void advanceTo(TimePoint const& t);
+
+    TimePoint now() override { return now_; }
+
+   private:
+    std::mutex lock_;
+    std::queue<Func> funcs_;
+    sem_t sem_;
+
+    // helper class to enable ordering of scheduled events in the priority
+    // queue
+    struct ScheduledFunc {
+      TimePoint time;
+      size_t ordinal;
+      Func func;
+
+      ScheduledFunc(TimePoint const& t, Func&& f)
+        : time(t), func(std::move(f))
+      {
+        static size_t seq = 0;
+        ordinal = seq++;
+      }
+
+      bool operator<(ScheduledFunc const& b) const {
+        if (time == b.time)
+          return ordinal < b.ordinal;
+        return time < b.time;
+      }
+    };
+    std::priority_queue<ScheduledFunc> scheduledFuncs_;
+    TimePoint now_ = now_.min();
+  };
+
+}}
diff --git a/folly/futures/OpaqueCallbackShunt.h b/folly/futures/OpaqueCallbackShunt.h
new file mode 100644 (file)
index 0000000..7977fb0
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <folly/futures/Promise.h>
+
+namespace folly { namespace wangle {
+
+/// These classes help you wrap an existing C style callback function
+/// into a Future.
+///
+///   void legacy_send_async(..., void (*cb)(void*), void*);
+///
+///   Future<T> wrappedSendAsync(T&& obj) {
+///     auto handle = new OpaqueCallbackShunt<T>(obj);
+///     auto future = handle->promise_.getFuture();
+///     legacy_send_async(..., OpaqueCallbackShunt<T>::callback, handle)
+///     return future;
+///   }
+///
+/// If the legacy function doesn't conform to void (*cb)(void*), use a lambda:
+///
+///   auto cb = [](t1*, t2*, void* arg) {
+///     OpaqueCallbackShunt<T>::callback(arg);
+///   };
+///   legacy_send_async(..., cb, handle);
+
+template <typename T>
+class OpaqueCallbackShunt {
+public:
+  explicit OpaqueCallbackShunt(T&& obj)
+    : obj_(std::move(obj)) { }
+  static void callback(void* arg) {
+    std::unique_ptr<OpaqueCallbackShunt<T>> handle(
+      static_cast<OpaqueCallbackShunt<T>*>(arg));
+    handle->promise_.setValue(std::move(handle->obj_));
+  }
+  folly::wangle::Promise<T> promise_;
+private:
+  T obj_;
+};
+
+}} // folly::wangle
diff --git a/folly/futures/Promise-inl.h b/folly/futures/Promise-inl.h
new file mode 100644 (file)
index 0000000..75b260c
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <thread>
+
+#include <folly/futures/WangleException.h>
+#include <folly/futures/detail/Core.h>
+
+namespace folly { namespace wangle {
+
+template <class T>
+Promise<T>::Promise() : retrieved_(false), core_(new detail::Core<T>())
+{}
+
+template <class T>
+Promise<T>::Promise(Promise<T>&& other) : core_(nullptr) {
+  *this = std::move(other);
+}
+
+template <class T>
+Promise<T>& Promise<T>::operator=(Promise<T>&& other) {
+  std::swap(core_, other.core_);
+  std::swap(retrieved_, other.retrieved_);
+  return *this;
+}
+
+template <class T>
+void Promise<T>::throwIfFulfilled() {
+  if (!core_)
+    throw NoState();
+  if (core_->ready())
+    throw PromiseAlreadySatisfied();
+}
+
+template <class T>
+void Promise<T>::throwIfRetrieved() {
+  if (retrieved_)
+    throw FutureAlreadyRetrieved();
+}
+
+template <class T>
+Promise<T>::~Promise() {
+  detach();
+}
+
+template <class T>
+void Promise<T>::detach() {
+  if (core_) {
+    if (!retrieved_)
+      core_->detachFuture();
+    core_->detachPromise();
+    core_ = nullptr;
+  }
+}
+
+template <class T>
+Future<T> Promise<T>::getFuture() {
+  throwIfRetrieved();
+  retrieved_ = true;
+  return Future<T>(core_);
+}
+
+template <class T>
+template <class E>
+typename std::enable_if<std::is_base_of<std::exception, E>::value>::type
+Promise<T>::setException(E const& e) {
+  setException(make_exception_wrapper<E>(e));
+}
+
+template <class T>
+void Promise<T>::setException(std::exception_ptr const& ep) {
+  try {
+    std::rethrow_exception(ep);
+  } catch (const std::exception& e) {
+    setException(exception_wrapper(std::current_exception(), e));
+  } catch (...) {
+    setException(exception_wrapper(std::current_exception()));
+  }
+}
+
+template <class T>
+void Promise<T>::setException(exception_wrapper ew) {
+  throwIfFulfilled();
+  core_->setResult(Try<T>(std::move(ew)));
+}
+
+template <class T>
+void Promise<T>::setInterruptHandler(
+  std::function<void(exception_wrapper const&)> fn) {
+  core_->setInterruptHandler(std::move(fn));
+}
+
+template <class T>
+void Promise<T>::fulfilTry(Try<T>&& t) {
+  throwIfFulfilled();
+  core_->setResult(std::move(t));
+}
+
+template <class T>
+template <class M>
+void Promise<T>::setValue(M&& v) {
+  static_assert(!std::is_same<T, void>::value,
+                "Use setValue() instead");
+
+  fulfilTry(Try<T>(std::forward<M>(v)));
+}
+
+template <class T>
+void Promise<T>::setValue() {
+  static_assert(std::is_same<T, void>::value,
+                "Use setValue(value) instead");
+
+  fulfilTry(Try<void>());
+}
+
+template <class T>
+template <class F>
+void Promise<T>::fulfil(F&& func) {
+  throwIfFulfilled();
+  fulfilTry(makeTryFunction(std::forward<F>(func)));
+}
+
+}}
diff --git a/folly/futures/Promise.h b/folly/futures/Promise.h
new file mode 100644 (file)
index 0000000..58b7323
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <folly/futures/Deprecated.h>
+#include <folly/futures/Try.h>
+#include <functional>
+
+namespace folly { namespace wangle {
+
+// forward declaration
+template <class T> class Future;
+
+template <class T>
+class Promise {
+public:
+  Promise();
+  ~Promise();
+
+  // not copyable
+  Promise(Promise const&) = delete;
+  Promise& operator=(Promise const&) = delete;
+
+  // movable
+  Promise(Promise<T>&&);
+  Promise& operator=(Promise<T>&&);
+
+  /** Return a Future tied to the shared core state. This can be called only
+    once, thereafter Future already retrieved exception will be raised. */
+  Future<T> getFuture();
+
+  /** Fulfil the Promise with an exception_wrapper */
+  void setException(exception_wrapper ew);
+
+  /** Fulfil the Promise with an exception_ptr, e.g.
+    try {
+      ...
+    } catch (...) {
+      p.setException(std::current_exception());
+    }
+    */
+  void setException(std::exception_ptr const&) DEPRECATED;
+
+  /** Fulfil the Promise with an exception type E, which can be passed to
+    std::make_exception_ptr(). Useful for originating exceptions. If you
+    caught an exception the exception_wrapper form is more appropriate.
+    */
+  template <class E>
+  typename std::enable_if<std::is_base_of<std::exception, E>::value>::type
+  setException(E const&);
+
+  /// Set an interrupt handler to handle interrupts. See the documentation for
+  /// Future::raise(). Your handler can do whatever it wants, but if you
+  /// bother to set one then you probably will want to fulfil the promise with
+  /// an exception (or special value) indicating how the interrupt was
+  /// handled.
+  void setInterruptHandler(std::function<void(exception_wrapper const&)>);
+
+  /** Fulfil this Promise (only for Promise<void>) */
+  void setValue();
+
+  /** Set the value (use perfect forwarding for both move and copy) */
+  template <class M>
+  void setValue(M&& value);
+
+  void fulfilTry(Try<T>&& t);
+
+  /** Fulfil this Promise with the result of a function that takes no
+    arguments and returns something implicitly convertible to T.
+    Captures exceptions. e.g.
+
+    p.fulfil([] { do something that may throw; return a T; });
+  */
+  template <class F>
+  void fulfil(F&& func);
+
+private:
+  typedef typename Future<T>::corePtr corePtr;
+
+  // Whether the Future has been retrieved (a one-time operation).
+  bool retrieved_;
+
+  // shared core state object
+  corePtr core_;
+
+  void throwIfFulfilled();
+  void throwIfRetrieved();
+  void detach();
+};
+
+}}
+
+#include <folly/futures/Future.h>
+#include <folly/futures/Promise-inl.h>
diff --git a/folly/futures/QueuedImmediateExecutor.cpp b/folly/futures/QueuedImmediateExecutor.cpp
new file mode 100644 (file)
index 0000000..c972287
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/futures/QueuedImmediateExecutor.h>
+#include <folly/ThreadLocal.h>
+#include <queue>
+
+namespace folly { namespace wangle {
+
+void QueuedImmediateExecutor::add(Func callback) {
+  thread_local std::queue<Func> q;
+
+  if (q.empty()) {
+    q.push(std::move(callback));
+    while (!q.empty()) {
+      q.front()();
+      q.pop();
+    }
+  } else {
+    q.push(callback);
+  }
+}
+
+}} // namespace
diff --git a/folly/futures/QueuedImmediateExecutor.h b/folly/futures/QueuedImmediateExecutor.h
new file mode 100644 (file)
index 0000000..a82c32d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <folly/Executor.h>
+
+namespace folly { namespace wangle {
+
+/**
+ * Runs inline like InlineExecutor, but with a queue so that any tasks added
+ * to this executor by one of its own callbacks will be queued instead of
+ * executed inline (nested). This is usually better behavior than Inline.
+ */
+class QueuedImmediateExecutor : public Executor {
+ public:
+  void add(Func) override;
+};
+
+}} // namespace
diff --git a/folly/futures/README.md b/folly/futures/README.md
new file mode 100644 (file)
index 0000000..cec17f5
--- /dev/null
@@ -0,0 +1,278 @@
+# Wangle
+Wangle is a framework for expressing asynchronous code in C++ using the Future pattern.
+
+**wan•gle** |ˈwaNGgÉ™l| informal  
+*verb*  
+Obtain (something that is desired) by persuading others to comply or by manipulating events.
+
+*noun*  
+A framework for expressing asynchronous control flow in C++, that is composable and easily translated to/from synchronous code.
+
+*synonyms*  
+[Finagle](http://twitter.github.io/finagle/)
+
+Wangle is a futures-based async framework inspired by [Twitter's Finagle](http://twitter.github.io/finagle/) (which is in scala), and (loosely) building upon the existing (but anemic) Futures code found in the C++11 standard ([`std::future`](http://en.cppreference.com/w/cpp/thread/future)) and [`boost::future`](http://www.boost.org/doc/libs/1_53_0/boost/thread/future.hpp) (especially >= 1.53.0). Although inspired by the std::future interface, it is not syntactically drop-in compatible because some ideas didn't translate well enough and we decided to break from the API. But semantically, it should be straightforward to translate from existing std::future code to Wangle.
+
+The primary semantic differences are that Wangle Futures and Promises are not threadsafe; and as does `boost::future`, Wangle supports continuing callbacks (`then()`) and there are helper methods `whenAll()` and `whenAny()` which are important compositional building blocks.
+
+## Brief Synopsis
+
+```C++
+#include <folly/futures/Future.h>
+using namespace folly::wangle;
+using namespace std;
+
+void foo(int x) {
+  // do something with x
+  cout << "foo(" << x << ")" << endl;
+}
+
+// ...
+
+  cout << "making Promise" << endl;
+  Promise<int> p;
+  Future<int> f = p.getFuture();
+  f.then(
+    [](Try<int>&& t) {
+      foo(t.value());
+    });
+  cout << "Future chain made" << endl;
+
+// ... now perhaps in another event callback
+
+  cout << "fulfilling Promise" << endl;
+  p.setValue(42);
+  cout << "Promise fulfilled" << endl;
+```
+
+This would print:
+  
+```
+making Promise
+Future chain made
+fulfilling Promise
+foo(42)
+Promise fulfilled
+```
+
+## User Guide
+
+Let's begin with an example. Consider a simplified Memcache client class with this interface:
+
+```C++
+class MemcacheClient {
+ public:
+  struct GetReply {
+    enum class Result {
+      FOUND,
+      NOT_FOUND,
+      SERVER_ERROR,
+    };
+
+    Result result;
+    // The value when result is FOUND,
+    // The error message when result is SERVER_ERROR or CLIENT_ERROR
+    // undefined otherwise
+    std::string value;
+  };
+
+  GetReply get(std::string key);
+};
+```
+
+This API is synchronous, i.e. when you call `get()` you have to wait for the result. This is very simple, but unfortunately it is also very easy to write very slow code using synchronous APIs.
+
+Now, consider this traditional asynchronous signature for `get()`:
+
+```C++
+int get(std::string key, std::function<void(GetReply)> callback);
+```
+
+When you call `get()`, your asynchronous operation begins and when it finishes your callback will be called with the result. (Unless something goes drastically wrong and you get an error code from `get()`.) Very performant code can be written with an API like this, but for nontrivial applications the code descends into a special kind of spaghetti code affectionately referred to as "callback hell".
+
+The Future-based API looks like this:
+
+```C++
+Future<GetReply> get(std::string key);
+```
+
+A `Future<GetReply>` is a placeholder for the `GetReply` that we will eventually get. A Future usually starts life out "unfulfilled", or incomplete, i.e.:
+
+```C++
+fut.isReady() == false
+fut.value()  // will throw an exception because the Future is not ready
+```
+
+At some point in the future, the Future will have been fulfilled, and we can access its value.
+
+```C++
+fut.isReady() == true
+GetReply& reply = fut.value();
+```
+
+Futures support exceptions. If something exceptional happened, your Future may represent an exception instead of a value. In that case:
+
+```C++
+fut.isReady() == true
+fut.value() // will rethrow the exception
+```
+
+Just what is exceptional depends on the API. In our example we have chosen not to raise exceptions for `SERVER_ERROR`, but represent this explicitly in the `GetReply` object. On the other hand, an astute Memcache veteran would notice that we left `CLIENT_ERROR` out of `GetReply::Result`, and perhaps a `CLIENT_ERROR` would have been raised as an exception, because `CLIENT_ERROR` means there's a bug in the library and this would be truly exceptional. These decisions are judgement calls by the API designer. The important thing is that exceptional conditions (including and especially spurious exceptions that nobody expects) get captured and can be handled higher up the "stack".
+
+So far we have described a way to initiate an asynchronous operation via an API that returns a Future, and then sometime later after it is fulfilled, we get its value. This is slightly more useful than a synchronous API, but it's not yet ideal. There are two more very important pieces to the puzzle.
+
+First, we can aggregate Futures, to define a new Future that completes after some or all of the aggregated Futures complete.  Consider two examples: fetching a batch of requests and waiting for all of them, and fetching a group of requests and waiting for only one of them.
+
+```C++
+vector<Future<GetReply>> futs;
+for (auto& key : keys) {
+  futs.push_back(mc.get(key));
+}
+auto all = whenAll(futs.begin(), futs.end());
+
+vector<Future<GetReply>> futs;
+for (auto& key : keys) {
+  futs.push_back(mc.get(key));
+}
+auto any = whenAny(futs.begin(), futs.end());
+```
+
+`all` and `any` are Futures (for the exact type and usage see the header files).  They will be complete when all/one of `futs` are complete, respectively. (There is also `whenN()` for when you need *some*.)
+
+Second, we can attach callbacks to a Future, and chain them together monadically. An example will clarify:
+
+```C++
+Future<GetReply> fut1 = mc.get("foo");
+
+Future<string> fut2 = fut1.then(
+  [](Try<GetReply>&& t) {
+    if (t.value().result == MemcacheClient::GetReply::Result::FOUND)
+      return t.value().value;
+    throw SomeException("No value");
+  });
+
+Future<void> fut3 = fut2.then(
+  [](Try<string>&& t) {
+    try {
+      cout << t.value() << endl;
+    } catch (std::exception const& e) {
+      cerr << e.what() << endl;
+    }
+  });
+```
+
+That example is a little contrived but the idea is that you can transform a result from one type to another, potentially in a chain, and unhandled errors propagate. Of course, the intermediate variables are optional. `Try<T>` is the object wrapper that supports both value and exception.
+
+Using `then` to add callbacks is idiomatic. It brings all the code into one place, which avoids callback hell.
+
+Up to this point we have skirted around the matter of waiting for Futures. You may never need to wait for a Future, because your code is event-driven and all follow-up action happens in a then-block. But if want to have a batch workflow, where you initiate a batch of asynchronous operations and then wait for them all to finish at a synchronization point, then you will want to wait for a Future.
+
+Other future frameworks like Finagle and std::future/boost::future, give you the ability to wait directly on a Future, by calling `fut.wait()` (naturally enough). Wangle has diverged from this pattern because we don't want to be in the business of dictating how your thread waits. We may work out something that we feel is sufficiently general, in the meantime adapt this spin loop to however your thread should wait:
+
+  while (!f.isReady()) {}
+
+(Hint: you might want to use an event loop or a semaphore or something. You probably don't want to just spin like this.)
+
+Wangle is partially threadsafe. A Promise or Future can migrate between threads as long as there's a full memory barrier of some sort. `Future::then` and `Promise::setValue` (and all variants that boil down to those two calls) can be called from different threads. BUT, be warned that you might be surprised about which thread your callback executes on. Let's consider an example.
+
+```C++
+// Thread A
+Promise<void> p;
+auto f = p.getFuture();
+
+// Thread B
+f.then(x).then(y).then(z);
+
+// Thread A
+p.setValue();
+```
+
+This is legal and technically threadsafe. However, it is important to realize that you do not know in which thread `x`, `y`, and/or `z` will execute. Maybe they will execute in Thread A when `p.setValue()` is called. Or, maybe they will execute in Thread B when `f.then` is called. Or, maybe `x` will execute in Thread B, but `y` and/or `z` will execute in Thread A. There's a race between `setValue` and `then`—whichever runs last will execute the callback. The only guarantee is that one of them will run the callback.
+
+Naturally, you will want some control over which thread executes callbacks. We have a few mechanisms to help.
+
+The first and most useful is `via`, which passes execution through an `Executor`, which usually has the effect of running the callback in a new thread.
+```C++
+aFuture
+  .then(x)
+  .via(e1).then(y1).then(y2)
+  .via(e2).then(z);
+```
+`x` will execute in the current thread. `y1` and `y2` will execute in the thread on the other side of `e1`, and `z` will execute in the thread on the other side of `e2`. `y1` and `y2` will execute on the same thread, whichever thread that is. If `e1` and `e2` execute in different threads than the current thread, then the final callback does not happen in the current thread. If you want to get back to the current thread, you need to get there via an executor.
+
+This works because `via` returns a deactivated ("cold") Future, which blocks the propagation of callbacks until it is activated. Activation happens either explicitly (`activate`) or implicitly when the Future returned by `via` is destructed. In this example, there is no ambiguity about in which context any of the callbacks happen (including `y2`), because propagation is blocked at the `via` callsites until after everything is wired up (temporaries are destructed after the calls to `then` have completed).
+
+You can still have a race after `via` if you break it into multiple statements, e.g. in this counterexample:
+```C++
+f = f.via(e1).then(y1).then(y2); // nothing racy here
+f2.then(y3); // racy
+```
+
+## You make me Promises, Promises
+
+If you are wrapping an asynchronous operation, or providing an asynchronous API to users, then you will want to make Promises. Every Future has a corresponding Promise (except Futures that spring into existence already completed, with `makeFuture()`). Promises are simple, you make one, you extract the Future, and you fulfil it with a value or an exception. Example:
+
+```C++
+Promise<int> p;
+Future<int> f = p.getFuture();
+
+f.isReady() == false
+
+p.setValue(42);
+
+f.isReady() == true
+f.value() == 42
+```
+
+and an exception example:
+
+```C++
+Promise<int> p;
+Future<int> f = p.getFuture();
+
+f.isReady() == false
+
+p.setException(std::runtime_error("Fail"));
+
+f.isReady() == true
+f.value() // throws the exception
+```
+
+It's good practice to use fulfil which takes a function and automatically captures exceptions, e.g.
+
+```C++
+Promise<int> p;
+p.fulfil([]{
+  try {
+    // do stuff that may throw
+    return 42;
+  } catch (MySpecialException const& e) {
+    // handle it
+    return 7;
+  }
+  // Any exceptions that we didn't catch, will be caught for us
+});
+```
+
+## FAQ
+
+### Why not use std::future?
+No callback support.
+See also http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf
+
+### Why not use boost::future?
+- 1.53 is brand new, and not in fbcode
+- It's still a bit buggy/bleeding-edge
+- They haven't fleshed out the threading model very well yet, e.g. every single `then` currently spawns a new thread unless you explicitly ask it to work on this thread only, and there is no support for executors yet.
+
+### Why use heap-allocated shared state? Why is Promise not a subclass of Future?
+C++. It boils down to wanting to return a Future by value for performance (move semantics and compiler optimizations), and programmer sanity, and needing a reference to the shared state by both the user (which holds the Future) and the asynchronous operation (which holds the Promise), and allowing either to go out of scope.
+
+### What about proper continuations? Futures suck.
+People mean two things here, they either mean using continuations (as in CSP) or they mean using generators which require continuations. It's important to know those are two distinct questions, but in our context the answer is the same because continuations are a prerequisite for generators.
+
+C++ doesn't directly support continuations very well. But there are some ways to do them in C/C++ that rely on some rather low-level facilities like `setjmp` and `longjmp` (among others). So yes, they are possible (cf. [Mordor](https://github.com/ccutrer/mordor)).
+
+The tradeoff is memory. Each continuation has a stack, and that stack is usually fixed-size and has to be big enough to support whatever ordinary computation you might want to do on it. So each living continuation requires a relatively large amount of memory. If you know the number of continuations will be small, this might be a good fit. In particular, it might be faster and the code might read cleaner.
+
+Wangle takes the middle road between callback hell and continuations, one which has been trodden and proved useful in other languages. It doesn't claim to be the best model for all situations. Use your tools wisely.
diff --git a/folly/futures/ScheduledExecutor.h b/folly/futures/ScheduledExecutor.h
new file mode 100644 (file)
index 0000000..94850c2
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <folly/Executor.h>
+#include <chrono>
+#include <memory>
+#include <stdexcept>
+
+namespace folly { namespace wangle {
+  // An executor that supports timed scheduling. Like RxScheduler.
+  class ScheduledExecutor : public Executor {
+   public:
+     // Reality is that better than millisecond resolution is very hard to
+     // achieve. However, we reserve the right to be incredible.
+     typedef std::chrono::microseconds Duration;
+     typedef std::chrono::steady_clock::time_point TimePoint;
+
+     virtual ~ScheduledExecutor() = default;
+
+     virtual void add(Func) override = 0;
+
+     /// Alias for add() (for Rx consistency)
+     void schedule(Func&& a) { add(std::move(a)); }
+
+     /// Schedule a Func to be executed after dur time has elapsed
+     /// Expect millisecond resolution at best.
+     void schedule(Func&& a, Duration const& dur) {
+       scheduleAt(std::move(a), now() + dur);
+     }
+
+     /// Schedule a Func to be executed at time t, or as soon afterward as
+     /// possible. Expect millisecond resolution at best. Must be threadsafe.
+     virtual void scheduleAt(Func&& a, TimePoint const& t) {
+       throw std::logic_error("unimplemented");
+     }
+
+     /// Get this executor's notion of time. Must be threadsafe.
+     virtual TimePoint now() {
+       return std::chrono::steady_clock::now();
+     }
+  };
+}}
diff --git a/folly/futures/Timekeeper.h b/folly/futures/Timekeeper.h
new file mode 100644 (file)
index 0000000..7bbdddc
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <folly/futures/detail/Types.h>
+
+namespace folly { namespace wangle {
+
+template <class> struct Future;
+
+/// A Timekeeper handles the details of keeping time and fulfilling delay
+/// promises. The returned Future<void> will either complete after the
+/// elapsed time, or in the event of some kind of exceptional error may hold
+/// an exception. These Futures respond to cancellation. If you use a lot of
+/// Delays and many of them ultimately are unneeded (as would be the case for
+/// Delays that are used to trigger timeouts of async operations), then you
+/// can and should cancel them to reclaim resources.
+///
+/// Users will typically get one of these via Future::sleep(Duration) or
+/// use them implicitly behind the scenes by passing a timeout to some Future
+/// operation.
+///
+/// Although we don't formally alias Delay = Future<void>,
+/// that's an appropriate term for it. People will probably also call these
+/// Timeouts, and that's ok I guess, but that term is so overloaded I thought
+/// it made sense to introduce a cleaner term.
+///
+/// Remember that Duration is a std::chrono duration (millisecond resolution
+/// at the time of writing).
+class Timekeeper {
+ public:
+  virtual ~Timekeeper() = default;
+
+  /// Returns a future that will complete after the given duration with the
+  /// elapsed time. Exceptional errors can happen but they must be
+  /// exceptional. Use the steady (monotonic) clock.
+  ///
+  /// You may cancel this Future to reclaim resources.
+  ///
+  /// This future probably completes on the timer thread. You should almost
+  /// certainly follow it with a via() call or the accuracy of other timers
+  /// will suffer.
+  virtual Future<void> after(Duration) = 0;
+
+  /// Returns a future that will complete at the requested time.
+  ///
+  /// You may cancel this Future to reclaim resources.
+  ///
+  /// NB This is sugar for `after(when - now)`, so while you are welcome to
+  /// use a std::chrono::system_clock::time_point it will not track changes to
+  /// the system clock but rather execute that many milliseconds in the future
+  /// according to the steady clock.
+  template <class Clock>
+  Future<void> at(std::chrono::time_point<Clock> when);
+};
+
+}}
+
+// now get those definitions
+#include <folly/futures/Future.h>
+
+// finally we can use Future
+namespace folly { namespace wangle {
+
+  template <class Clock>
+  Future<void> Timekeeper::at(std::chrono::time_point<Clock> when) {
+    auto now = Clock::now();
+
+    if (when <= now) {
+      return makeFuture();
+    }
+
+    return after(when - now);
+  }
+
+}}
diff --git a/folly/futures/Try-inl.h b/folly/futures/Try-inl.h
new file mode 100644 (file)
index 0000000..0aded74
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdexcept>
+
+#include <folly/futures/WangleException.h>
+
+namespace folly { namespace wangle {
+
+template <class T>
+Try<T>::Try(Try<T>&& t) : contains_(t.contains_) {
+  if (contains_ == Contains::VALUE) {
+    new (&value_)T(std::move(t.value_));
+  } else if (contains_ == Contains::EXCEPTION) {
+    new (&e_)std::unique_ptr<exception_wrapper>(std::move(t.e_));
+  }
+}
+
+template <class T>
+Try<T>& Try<T>::operator=(Try<T>&& t) {
+  this->~Try();
+  contains_ = t.contains_;
+  if (contains_ == Contains::VALUE) {
+    new (&value_)T(std::move(t.value_));
+  } else if (contains_ == Contains::EXCEPTION) {
+    new (&e_)std::unique_ptr<exception_wrapper>(std::move(t.e_));
+  }
+  return *this;
+}
+
+template <class T>
+Try<T>::~Try() {
+  if (contains_ == Contains::VALUE) {
+    value_.~T();
+  } else if (contains_ == Contains::EXCEPTION) {
+    e_.~unique_ptr<exception_wrapper>();
+  }
+}
+
+template <class T>
+T& Try<T>::value() {
+  throwIfFailed();
+  return value_;
+}
+
+template <class T>
+const T& Try<T>::value() const {
+  throwIfFailed();
+  return value_;
+}
+
+template <class T>
+void Try<T>::throwIfFailed() const {
+  if (contains_ != Contains::VALUE) {
+    if (contains_ == Contains::EXCEPTION) {
+      e_->throwException();
+    } else {
+      throw UsingUninitializedTry();
+    }
+  }
+}
+
+void Try<void>::throwIfFailed() const {
+  if (!hasValue_) {
+    e_->throwException();
+  }
+}
+
+template <typename T>
+inline T moveFromTry(wangle::Try<T>&& t) {
+  return std::move(t.value());
+}
+
+inline void moveFromTry(wangle::Try<void>&& t) {
+  return t.value();
+}
+
+template <typename F>
+typename std::enable_if<
+  !std::is_same<typename std::result_of<F()>::type, void>::value,
+  Try<typename std::result_of<F()>::type>>::type
+makeTryFunction(F&& f) {
+  typedef typename std::result_of<F()>::type ResultType;
+  try {
+    return Try<ResultType>(f());
+  } catch (std::exception& e) {
+    return Try<ResultType>(exception_wrapper(std::current_exception(), e));
+  } catch (...) {
+    return Try<ResultType>(exception_wrapper(std::current_exception()));
+  }
+}
+
+template <typename F>
+typename std::enable_if<
+  std::is_same<typename std::result_of<F()>::type, void>::value,
+  Try<void>>::type
+makeTryFunction(F&& f) {
+  try {
+    f();
+    return Try<void>();
+  } catch (std::exception& e) {
+    return Try<void>(exception_wrapper(std::current_exception(), e));
+  } catch (...) {
+    return Try<void>(exception_wrapper(std::current_exception()));
+  }
+}
+
+}}
diff --git a/folly/futures/Try.h b/folly/futures/Try.h
new file mode 100644 (file)
index 0000000..e98682d
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <type_traits>
+#include <exception>
+#include <algorithm>
+#include <folly/ExceptionWrapper.h>
+#include <folly/Likely.h>
+#include <folly/Memory.h>
+#include <folly/futures/Deprecated.h>
+#include <folly/futures/WangleException.h>
+
+namespace folly { namespace wangle {
+
+/*
+ * Try<T> is a wrapper that contains either an instance of T, an exception, or
+ * nothing. Its primary use case is as a representation of a Promise or Future's
+ * result and so it provides a number of methods that are useful in that
+ * context. Exceptions are stored as exception_wrappers so that the user can
+ * minimize rethrows if so desired.
+ *
+ * There is a specialization, Try<void>, which represents either success
+ * or an exception.
+ */
+template <class T>
+class Try {
+  static_assert(!std::is_reference<T>::value,
+                "Try may not be used with reference types");
+
+  enum class Contains {
+    VALUE,
+    EXCEPTION,
+    NOTHING,
+  };
+
+ public:
+  /*
+   * The value type for the Try
+   */
+  typedef T element_type;
+
+  /*
+   * Construct an empty Try
+   */
+  Try() : contains_(Contains::NOTHING) {}
+
+  /*
+   * Construct a Try with a value by copy
+   *
+   * @param v The value to copy in
+   */
+  explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
+
+  /*
+   * Construct a Try with a value by move
+   *
+   * @param v The value to move in
+   */
+  explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
+
+  /*
+   * Construct a Try with an exception_wrapper
+   *
+   * @param e The exception_wrapper
+   */
+  explicit Try(exception_wrapper e)
+    : contains_(Contains::EXCEPTION),
+      e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
+
+  /*
+   * DEPRECATED
+   * Construct a Try with an exception_pointer
+   *
+   * @param ep The exception_pointer. Will be rethrown.
+   */
+  explicit Try(std::exception_ptr ep) DEPRECATED
+    : contains_(Contains::EXCEPTION) {
+    try {
+      std::rethrow_exception(ep);
+    } catch (const std::exception& e) {
+      e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
+    } catch (...) {
+      e_ = folly::make_unique<exception_wrapper>(std::current_exception());
+    }
+  }
+
+  // Move constructor
+  Try(Try<T>&& t);
+  // Move assigner
+  Try& operator=(Try<T>&& t);
+
+  // Non-copyable
+  Try(const Try<T>& t) = delete;
+  // Non-copyable
+  Try& operator=(const Try<T>& t) = delete;
+
+  ~Try();
+
+  /*
+   * Get a mutable reference to the contained value. If the Try contains an
+   * exception it will be rethrown.
+   *
+   * @returns mutable reference to the contained value
+   */
+  T& value();
+  /*
+   * Get a const reference to the contained value. If the Try contains an
+   * exception it will be rethrown.
+   *
+   * @returns const reference to the contained value
+   */
+  const T& value() const;
+
+  /*
+   * If the Try contains an exception, rethrow it. Otherwise do nothing.
+   */
+  void throwIfFailed() const;
+
+  /*
+   * Const dereference operator. If the Try contains an exception it will be
+   * rethrown.
+   *
+   * @returns const reference to the contained value
+   */
+  const T& operator*() const { return value(); }
+  /*
+   * Dereference operator. If the Try contains an exception it will be rethrown.
+   *
+   * @returns mutable reference to the contained value
+   */
+  T& operator*() { return value(); }
+
+  /*
+   * Const arrow operator. If the Try contains an exception it will be
+   * rethrown.
+   *
+   * @returns const reference to the contained value
+   */
+  const T* operator->() const { return &value(); }
+  /*
+   * Arrow operator. If the Try contains an exception it will be rethrown.
+   *
+   * @returns mutable reference to the contained value
+   */
+  T* operator->() { return &value(); }
+
+  /*
+   * @returns True if the Try contains a value, false otherwise
+   */
+  bool hasValue() const { return contains_ == Contains::VALUE; }
+  /*
+   * @returns True if the Try contains an exception, false otherwise
+   */
+  bool hasException() const { return contains_ == Contains::EXCEPTION; }
+
+  /*
+   * @returns True if the Try contains an exception of type Ex, false otherwise
+   */
+  template <class Ex>
+  bool hasException() const {
+    return hasException() && e_->is_compatible_with<Ex>();
+  }
+
+  exception_wrapper& exception() {
+    if (UNLIKELY(!hasException())) {
+      throw WangleException("exception(): Try does not contain an exception");
+    }
+    return *e_;
+  }
+
+  /*
+   * If the Try contains an exception and it is of type Ex, execute func(Ex)
+   *
+   * @param func a function that takes a single parameter of type const Ex&
+   *
+   * @returns True if the Try held an Ex and func was executed, false otherwise
+   */
+  template <class Ex, class F>
+  bool withException(F func) const {
+    if (!hasException()) {
+      return false;
+    }
+    return e_->with_exception<Ex>(std::move(func));
+  }
+
+ private:
+  Contains contains_;
+  union {
+    T value_;
+    std::unique_ptr<exception_wrapper> e_;
+  };
+};
+
+/*
+ * Specialization of Try for void value type. Encapsulates either success or an
+ * exception.
+ */
+template <>
+class Try<void> {
+ public:
+  // Construct a Try holding a successful and void result
+  Try() : hasValue_(true) {}
+
+  /*
+   * Construct a Try with an exception_wrapper
+   *
+   * @param e The exception_wrapper
+   */
+  explicit Try(exception_wrapper e)
+    : hasValue_(false),
+      e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
+
+  /*
+   * DEPRECATED
+   * Construct a Try with an exception_pointer
+   *
+   * @param ep The exception_pointer. Will be rethrown.
+   */
+  explicit Try(std::exception_ptr ep) DEPRECATED : hasValue_(false) {
+    try {
+      std::rethrow_exception(ep);
+    } catch (const std::exception& e) {
+      e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
+    } catch (...) {
+      e_ = folly::make_unique<exception_wrapper>(std::current_exception());
+    }
+  }
+
+  // Copy assigner
+  Try& operator=(const Try<void>& t) {
+    hasValue_ = t.hasValue_;
+    if (t.e_) {
+      e_ = folly::make_unique<exception_wrapper>(*t.e_);
+    }
+    return *this;
+  }
+  // Copy constructor
+  Try(const Try<void>& t) {
+    *this = t;
+  }
+
+  // If the Try contains an exception, throws it
+  void value() const { throwIfFailed(); }
+  // Dereference operator. If the Try contains an exception, throws it
+  void operator*() const { return value(); }
+
+  // If the Try contains an exception, throws it
+  inline void throwIfFailed() const;
+
+  // @returns False if the Try contains an exception, true otherwise
+  bool hasValue() const { return hasValue_; }
+  // @returns True if the Try contains an exception, false otherwise
+  bool hasException() const { return !hasValue_; }
+
+  // @returns True if the Try contains an exception of type Ex, false otherwise
+  template <class Ex>
+  bool hasException() const {
+    return hasException() && e_->is_compatible_with<Ex>();
+  }
+
+  /*
+   * @throws WangleException if the Try doesn't contain an exception
+   *
+   * @returns mutable reference to the exception contained by this Try
+   */
+  exception_wrapper& exception() {
+    if (UNLIKELY(!hasException())) {
+      throw WangleException("exception(): Try does not contain an exception");
+    }
+    return *e_;
+  }
+
+  /*
+   * If the Try contains an exception and it is of type Ex, execute func(Ex)
+   *
+   * @param func a function that takes a single parameter of type const Ex&
+   *
+   * @returns True if the Try held an Ex and func was executed, false otherwise
+   */
+  template <class Ex, class F>
+  bool withException(F func) const {
+    if (!hasException()) {
+      return false;
+    }
+    return e_->with_exception<Ex>(std::move(func));
+  }
+
+ private:
+  bool hasValue_;
+  std::unique_ptr<exception_wrapper> e_{nullptr};
+};
+
+/*
+ * Extracts value from try and returns it. Throws if try contained an exception.
+ *
+ * @param t Try to extract value from
+ *
+ * @returns value contained in t
+ */
+template <typename T>
+T moveFromTry(wangle::Try<T>&& t);
+
+/*
+ * Throws if try contained an exception.
+ *
+ * @param t Try to move from
+ */
+void moveFromTry(wangle::Try<void>&& t);
+
+/*
+ * @param f a function to execute and capture the result of (value or exception)
+ *
+ * @returns Try holding the result of f
+ */
+template <typename F>
+typename std::enable_if<
+  !std::is_same<typename std::result_of<F()>::type, void>::value,
+  Try<typename std::result_of<F()>::type>>::type
+makeTryFunction(F&& f);
+
+/*
+ * Specialization of makeTryFunction for void
+ *
+ * @param f a function to execute and capture the result of
+ *
+ * @returns Try<void> holding the result of f
+ */
+template <typename F>
+typename std::enable_if<
+  std::is_same<typename std::result_of<F()>::type, void>::value,
+  Try<void>>::type
+makeTryFunction(F&& f);
+
+
+}}
+
+#include <folly/futures/Try-inl.h>
diff --git a/folly/futures/WangleException.h b/folly/futures/WangleException.h
new file mode 100644 (file)
index 0000000..0d97130
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <exception>
+#include <string>
+
+namespace folly { namespace wangle {
+
+class WangleException : public std::exception {
+
+public:
+
+  explicit WangleException(std::string message_arg)
+    : message(message_arg) {}
+
+  ~WangleException() throw(){}
+
+  virtual const char *what() const throw() {
+    return message.c_str();
+  }
+
+  bool operator==(const WangleException &other) const{
+    return other.message == this->message;
+  }
+
+  bool operator!=(const WangleException &other) const{
+    return !(*this == other);
+  }
+
+  protected:
+    std::string message;
+};
+
+class BrokenPromise : public WangleException {
+  public:
+    explicit BrokenPromise() :
+      WangleException("Broken promise") { }
+};
+
+class NoState : public WangleException {
+  public:
+    explicit NoState() : WangleException("No state") { }
+};
+
+class PromiseAlreadySatisfied : public WangleException {
+  public:
+    explicit PromiseAlreadySatisfied() :
+      WangleException("Promise already satisfied") { }
+};
+
+class FutureNotReady : public WangleException {
+  public:
+    explicit FutureNotReady() :
+      WangleException("Future not ready") { }
+};
+
+class FutureAlreadyRetrieved : public WangleException {
+  public:
+    explicit FutureAlreadyRetrieved () :
+      WangleException("Future already retrieved") { }
+};
+
+class UsingUninitializedTry : public WangleException {
+  public:
+    explicit UsingUninitializedTry() :
+      WangleException("Using unitialized try") { }
+};
+
+class FutureCancellation : public WangleException {
+ public:
+  FutureCancellation() : WangleException("Future was cancelled") {}
+};
+
+class TimedOut : public WangleException {
+ public:
+  TimedOut() : WangleException("Timed out") {}
+};
+
+}}
diff --git a/folly/futures/detail/Core.h b/folly/futures/detail/Core.h
new file mode 100644 (file)
index 0000000..1eb7062
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <mutex>
+#include <stdexcept>
+#include <vector>
+
+#include <folly/Optional.h>
+#include <folly/SmallLocks.h>
+
+#include <folly/futures/Try.h>
+#include <folly/futures/Promise.h>
+#include <folly/futures/Future.h>
+#include <folly/Executor.h>
+#include <folly/futures/detail/FSM.h>
+
+#include <folly/io/async/Request.h>
+
+namespace folly { namespace wangle { namespace detail {
+
+// As of GCC 4.8.1, the std::function in libstdc++ optimizes only for pointers
+// to functions, using a helper avoids a call to malloc.
+template<typename T>
+void empty_callback(Try<T>&&) { }
+
+enum class State {
+  Waiting,
+  Interruptible,
+  Interrupted,
+  Done,
+};
+
+/** The shared state object for Future and Promise. */
+template<typename T>
+class Core : protected FSM<State> {
+ public:
+  // This must be heap-constructed. There's probably a way to enforce that in
+  // code but since this is just internal detail code and I don't know how
+  // off-hand, I'm punting.
+  Core() : FSM<State>(State::Waiting) {}
+  ~Core() {
+    assert(calledBack_);
+    assert(detached_ == 2);
+  }
+
+  // not copyable
+  Core(Core const&) = delete;
+  Core& operator=(Core const&) = delete;
+
+  // not movable (see comment in the implementation of Future::then)
+  Core(Core&&) noexcept = delete;
+  Core& operator=(Core&&) = delete;
+
+  Try<T>& getTry() {
+    if (ready()) {
+      return *result_;
+    } else {
+      throw FutureNotReady();
+    }
+  }
+
+  template <typename F>
+  void setCallback(F func) {
+    auto setCallback_ = [&]{
+      if (callback_) {
+        throw std::logic_error("setCallback called twice");
+      }
+
+      context_ = RequestContext::saveContext();
+      callback_ = std::move(func);
+    };
+
+    FSM_START
+      case State::Waiting:
+      case State::Interruptible:
+      case State::Interrupted:
+        FSM_UPDATE(state, setCallback_);
+        break;
+
+      case State::Done:
+        FSM_UPDATE2(State::Done,
+          setCallback_,
+          [&]{ maybeCallback(); });
+        break;
+    FSM_END
+  }
+
+  void setResult(Try<T>&& t) {
+    FSM_START
+      case State::Waiting:
+      case State::Interruptible:
+      case State::Interrupted:
+        FSM_UPDATE2(State::Done,
+          [&]{ result_ = std::move(t); },
+          [&]{ maybeCallback(); });
+        break;
+
+      case State::Done:
+        throw std::logic_error("setResult called twice");
+    FSM_END
+  }
+
+  bool ready() const {
+    return getState() == State::Done;
+  }
+
+  // Called by a destructing Future
+  void detachFuture() {
+    if (!callback_) {
+      setCallback(empty_callback<T>);
+    }
+    activate();
+    detachOne();
+  }
+
+  // Called by a destructing Promise
+  void detachPromise() {
+    if (!ready()) {
+      setResult(Try<T>(exception_wrapper(BrokenPromise())));
+    }
+    detachOne();
+  }
+
+  void deactivate() {
+    active_ = false;
+  }
+
+  void activate() {
+    active_ = true;
+    if (ready()) {
+      maybeCallback();
+    }
+  }
+
+  bool isActive() { return active_; }
+
+  void setExecutor(Executor* x) {
+    executor_ = x;
+  }
+
+  void raise(exception_wrapper const& e) {
+    FSM_START
+      case State::Interruptible:
+        FSM_UPDATE2(State::Interrupted,
+          [&]{ interrupt_ = folly::make_unique<exception_wrapper>(e); },
+          [&]{ interruptHandler_(*interrupt_); });
+        break;
+
+      case State::Waiting:
+      case State::Interrupted:
+        FSM_UPDATE(State::Interrupted,
+          [&]{ interrupt_ = folly::make_unique<exception_wrapper>(e); });
+        break;
+
+      case State::Done:
+        FSM_BREAK
+    FSM_END
+  }
+
+  void setInterruptHandler(std::function<void(exception_wrapper const&)> fn) {
+    FSM_START
+      case State::Waiting:
+      case State::Interruptible:
+        FSM_UPDATE(State::Interruptible,
+          [&]{ interruptHandler_ = std::move(fn); });
+        break;
+
+      case State::Interrupted:
+        fn(*interrupt_);
+        FSM_BREAK
+
+      case State::Done:
+        FSM_BREAK
+    FSM_END
+  }
+
+ private:
+  void maybeCallback() {
+    assert(ready());
+    if (isActive() && callback_) {
+      if (!calledBack_.exchange(true)) {
+        // TODO(5306911) we should probably try/catch
+        Executor* x = executor_;
+
+        RequestContext::setContext(context_);
+        if (x) {
+          MoveWrapper<std::function<void(Try<T>&&)>> cb(std::move(callback_));
+          MoveWrapper<folly::Optional<Try<T>>> val(std::move(result_));
+          x->add([cb, val]() mutable { (*cb)(std::move(**val)); });
+        } else {
+          callback_(std::move(*result_));
+        }
+      }
+    }
+  }
+
+  void detachOne() {
+    auto d = ++detached_;
+    assert(d >= 1);
+    assert(d <= 2);
+    if (d == 2) {
+      // we should have already executed the callback with the value
+      assert(calledBack_);
+      delete this;
+    }
+  }
+
+  folly::Optional<Try<T>> result_;
+  std::function<void(Try<T>&&)> callback_;
+  std::shared_ptr<RequestContext> context_{nullptr};
+  std::atomic<bool> calledBack_ {false};
+  std::atomic<unsigned char> detached_ {0};
+  std::atomic<bool> active_ {true};
+  std::atomic<Executor*> executor_ {nullptr};
+  std::unique_ptr<exception_wrapper> interrupt_;
+  std::function<void(exception_wrapper const&)> interruptHandler_;
+};
+
+template <typename... Ts>
+struct VariadicContext {
+  VariadicContext() : total(0), count(0) {}
+  Promise<std::tuple<Try<Ts>... > > p;
+  std::tuple<Try<Ts>... > results;
+  size_t total;
+  std::atomic<size_t> count;
+  typedef Future<std::tuple<Try<Ts>...>> type;
+};
+
+template <typename... Ts, typename THead, typename... Fs>
+typename std::enable_if<sizeof...(Fs) == 0, void>::type
+whenAllVariadicHelper(VariadicContext<Ts...> *ctx, THead&& head, Fs&&... tail) {
+  head.setCallback_([ctx](Try<typename THead::value_type>&& t) {
+    std::get<sizeof...(Ts) - sizeof...(Fs) - 1>(ctx->results) = std::move(t);
+    if (++ctx->count == ctx->total) {
+      ctx->p.setValue(std::move(ctx->results));
+      delete ctx;
+    }
+  });
+}
+
+template <typename... Ts, typename THead, typename... Fs>
+typename std::enable_if<sizeof...(Fs) != 0, void>::type
+whenAllVariadicHelper(VariadicContext<Ts...> *ctx, THead&& head, Fs&&... tail) {
+  head.setCallback_([ctx](Try<typename THead::value_type>&& t) {
+    std::get<sizeof...(Ts) - sizeof...(Fs) - 1>(ctx->results) = std::move(t);
+    if (++ctx->count == ctx->total) {
+      ctx->p.setValue(std::move(ctx->results));
+      delete ctx;
+    }
+  });
+  // template tail-recursion
+  whenAllVariadicHelper(ctx, std::forward<Fs>(tail)...);
+}
+
+template <typename T>
+struct WhenAllContext {
+  WhenAllContext() : count(0) {}
+  Promise<std::vector<Try<T> > > p;
+  std::vector<Try<T> > results;
+  std::atomic<size_t> count;
+};
+
+template <typename T>
+struct WhenAnyContext {
+  explicit WhenAnyContext(size_t n) : done(false), ref_count(n) {};
+  Promise<std::pair<size_t, Try<T>>> p;
+  std::atomic<bool> done;
+  std::atomic<size_t> ref_count;
+  void decref() {
+    if (--ref_count == 0) {
+      delete this;
+    }
+  }
+};
+
+}}} // namespace
diff --git a/folly/futures/detail/FSM.h b/folly/futures/detail/FSM.h
new file mode 100644 (file)
index 0000000..be4eb8a
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <mutex>
+#include <folly/SmallLocks.h>
+
+namespace folly { namespace wangle { namespace detail {
+
+/// Finite State Machine helper base class.
+/// Inherit from this.
+/// For best results, use an "enum class" for Enum.
+template <class Enum>
+class FSM {
+private:
+  // I am not templatizing this because folly::MicroSpinLock needs to be
+  // zero-initialized (or call init) which isn't generic enough for something
+  // that behaves like std::mutex. :(
+  using Mutex = folly::MicroSpinLock;
+  Mutex mutex_ {0};
+
+  // This might not be necessary for all Enum types, e.g. anything
+  // that is atomically updated in practice on this CPU and there's no risk
+  // of returning a bogus state because of tearing.
+  // An optimization would be to use a static conditional on the Enum type.
+  std::atomic<Enum> state_;
+
+public:
+  explicit FSM(Enum startState) : state_(startState) {}
+
+  Enum getState() const {
+    return state_.load(std::memory_order_relaxed);
+  }
+
+  /// Atomically do a state transition with accompanying action.
+  /// The action will see the old state.
+  /// @returns true on success, false and action unexecuted otherwise
+  template <class F>
+  bool updateState(Enum A, Enum B, F const& action) {
+    std::lock_guard<Mutex> lock(mutex_);
+    if (state_ != A) return false;
+    action();
+    state_ = B;
+    return true;
+  }
+
+  /// Atomically do a state transition with accompanying action. Then do the
+  /// unprotected action without holding the lock. If the atomic transition
+  /// fails, returns false and neither action was executed.
+  ///
+  /// This facilitates code like this:
+  ///   bool done = false;
+  ///   while (!done) {
+  ///     switch (getState()) {
+  ///     case State::Foo:
+  ///       done = updateState(State::Foo, State::Bar,
+  ///           [&]{ /* do protected stuff */ },
+  ///           [&]{ /* do unprotected stuff */});
+  ///       break;
+  ///
+  /// Which reads nicer than code like this:
+  ///   while (true) {
+  ///     switch (getState()) {
+  ///     case State::Foo:
+  ///       if (!updateState(State::Foo, State::Bar,
+  ///           [&]{ /* do protected stuff */ })) {
+  ///         continue;
+  ///       }
+  ///       /* do unprotected stuff */
+  ///       return; // or otherwise break out of the loop
+  ///
+  /// The protected action will see the old state, and the unprotected action
+  /// will see the new state.
+  template <class F1, class F2>
+  bool updateState(Enum A, Enum B,
+                   F1 const& protectedAction, F2 const& unprotectedAction) {
+    bool result = updateState(A, B, protectedAction);
+    if (result) {
+      unprotectedAction();
+    }
+    return result;
+  }
+};
+
+#define FSM_START \
+  {bool done = false; while (!done) { auto state = getState(); switch (state) {
+
+#define FSM_UPDATE2(b, protectedAction, unprotectedAction) \
+    done = updateState(state, (b), (protectedAction), (unprotectedAction));
+
+#define FSM_UPDATE(b, action) FSM_UPDATE2((b), (action), []{})
+
+#define FSM_CASE(a, b, action) \
+  case (a): \
+    FSM_UPDATE((b), (action)); \
+    break;
+
+#define FSM_CASE2(a, b, protectedAction, unprotectedAction) \
+  case (a): \
+    FSM_UPDATE2((b), (protectedAction), (unprotectedAction)); \
+    break;
+
+#define FSM_BREAK done = true; break;
+#define FSM_END }}}
+
+
+}}}
diff --git a/folly/futures/detail/ThreadWheelTimekeeper.cpp b/folly/futures/detail/ThreadWheelTimekeeper.cpp
new file mode 100644 (file)
index 0000000..d77e68e
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ThreadWheelTimekeeper.h"
+
+#include <folly/experimental/Singleton.h>
+#include <folly/futures/Future.h>
+#include <future>
+
+namespace folly { namespace wangle { namespace detail {
+
+namespace {
+  Singleton<ThreadWheelTimekeeper> timekeeperSingleton_;
+
+  // Our Callback object for HHWheelTimer
+  struct WTCallback : public folly::HHWheelTimer::Callback {
+    // Only allow creation by this factory, to ensure heap allocation.
+    static WTCallback* create() {
+      // optimization opportunity: memory pool
+      return new WTCallback();
+    }
+
+    Future<void> getFuture() {
+      return promise_.getFuture();
+    }
+
+   protected:
+    Promise<void> promise_;
+
+    explicit WTCallback() {
+      promise_.setInterruptHandler(
+        std::bind(&WTCallback::interruptHandler, this));
+    }
+
+    void timeoutExpired() noexcept override {
+      promise_.setValue();
+      delete this;
+    }
+
+    void interruptHandler() {
+      cancelTimeout();
+      delete this;
+    }
+  };
+
+} // namespace
+
+
+ThreadWheelTimekeeper::ThreadWheelTimekeeper() :
+  thread_([this]{ eventBase_.loopForever(); }),
+  wheelTimer_(new HHWheelTimer(&eventBase_, std::chrono::milliseconds(1)))
+{
+  eventBase_.waitUntilRunning();
+  eventBase_.runInEventBaseThread([this]{
+    // 15 characters max
+    eventBase_.setName("FutureTimekeepr");
+  });
+}
+
+ThreadWheelTimekeeper::~ThreadWheelTimekeeper() {
+  eventBase_.runInEventBaseThread([this]{
+    wheelTimer_->cancelAll();
+  });
+  eventBase_.terminateLoopSoon();
+  thread_.join();
+}
+
+Future<void> ThreadWheelTimekeeper::after(Duration dur) {
+  auto cob = WTCallback::create();
+  auto f = cob->getFuture();
+  eventBase_.runInEventBaseThread([=]{
+    wheelTimer_->scheduleTimeout(cob, dur);
+  });
+  return f;
+}
+
+Timekeeper* getTimekeeperSingleton() {
+  return timekeeperSingleton_.get_fast();
+}
+
+}}}
diff --git a/folly/futures/detail/ThreadWheelTimekeeper.h b/folly/futures/detail/ThreadWheelTimekeeper.h
new file mode 100644 (file)
index 0000000..1174dce
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <folly/futures/Future.h>
+#include <folly/futures/Timekeeper.h>
+#include <folly/io/async/EventBase.h>
+#include <folly/io/async/HHWheelTimer.h>
+#include <thread>
+
+namespace folly { namespace wangle { namespace detail {
+
+/// The default Timekeeper implementation which uses a HHWheelTimer on an
+/// EventBase in a dedicated thread. Users needn't deal with this directly, it
+/// is used by default by Future methods that work with timeouts.
+class ThreadWheelTimekeeper : public Timekeeper {
+ public:
+  /// But it doesn't *have* to be a singleton.
+  ThreadWheelTimekeeper();
+  ~ThreadWheelTimekeeper();
+
+  /// Implement the Timekeeper interface
+  /// This future *does* complete on the timer thread. You should almost
+  /// certainly follow it with a via() call or the accuracy of other timers
+  /// will suffer.
+  Future<void> after(Duration) override;
+
+ protected:
+  folly::EventBase eventBase_;
+  std::thread thread_;
+  HHWheelTimer::UniquePtr wheelTimer_;
+};
+
+Timekeeper* getTimekeeperSingleton();
+
+}}}
diff --git a/folly/futures/detail/Types.h b/folly/futures/detail/Types.h
new file mode 100644 (file)
index 0000000..57b93e0
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+
+namespace folly { namespace wangle {
+
+using Duration = std::chrono::milliseconds;
+
+}}
diff --git a/folly/futures/test/Benchmark.cpp b/folly/futures/test/Benchmark.cpp
new file mode 100644 (file)
index 0000000..0f73d3f
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gflags/gflags.h>
+#include <folly/Baton.h>
+#include <folly/Benchmark.h>
+#include <folly/futures/Future.h>
+#include <folly/futures/Promise.h>
+#include <semaphore.h>
+#include <vector>
+
+using namespace folly::wangle;
+using namespace std;
+
+namespace {
+
+template <class T>
+T incr(Try<T>&& t) {
+  return t.value() + 1;
+}
+
+void someThens(size_t n) {
+  auto f = makeFuture<int>(42);
+  for (size_t i = 0; i < n; i++) {
+    f = f.then(incr<int>);
+  }
+}
+
+} // anonymous namespace
+
+BENCHMARK(constantFuture) {
+  makeFuture(42);
+}
+
+// This shouldn't get too far below 100%
+BENCHMARK_RELATIVE(promiseAndFuture) {
+  Promise<int> p;
+  Future<int> f = p.getFuture();
+  p.setValue(42);
+  f.value();
+}
+
+// The higher the better. At the time of writing, it's only about 40% :(
+BENCHMARK_RELATIVE(withThen) {
+  Promise<int> p;
+  Future<int> f = p.getFuture().then(incr<int>);
+  p.setValue(42);
+  f.value();
+}
+
+// thens
+BENCHMARK_DRAW_LINE()
+
+BENCHMARK(oneThen) {
+  someThens(1);
+}
+
+// look for >= 50% relative
+BENCHMARK_RELATIVE(twoThens) {
+  someThens(2);
+}
+
+// look for >= 25% relative
+BENCHMARK_RELATIVE(fourThens) {
+  someThens(4);
+}
+
+// look for >= 1% relative
+BENCHMARK_RELATIVE(hundredThens) {
+  someThens(100);
+}
+
+// Lock contention. Although in practice fulfil()s tend to be temporally
+// separate from then()s, still sometimes they will be concurrent. So the
+// higher this number is, the better.
+BENCHMARK_DRAW_LINE()
+
+BENCHMARK(no_contention) {
+  vector<Promise<int>> promises(10000);
+  vector<Future<int>> futures;
+  std::thread producer, consumer;
+
+  BENCHMARK_SUSPEND {
+    folly::Baton<> b1, b2;
+    for (auto& p : promises)
+      futures.push_back(p.getFuture());
+
+    consumer = std::thread([&]{
+      b1.post();
+      for (auto& f : futures) f.then(incr<int>);
+    });
+    consumer.join();
+
+    producer = std::thread([&]{
+      b2.post();
+      for (auto& p : promises) p.setValue(42);
+    });
+
+    b1.wait();
+    b2.wait();
+  }
+
+  // The only thing we are measuring is how long fulfil + callbacks take
+  producer.join();
+}
+
+BENCHMARK_RELATIVE(contention) {
+  vector<Promise<int>> promises(10000);
+  vector<Future<int>> futures;
+  std::thread producer, consumer;
+  sem_t sem;
+  sem_init(&sem, 0, 0);
+
+  BENCHMARK_SUSPEND {
+    folly::Baton<> b1, b2;
+    for (auto& p : promises)
+      futures.push_back(p.getFuture());
+
+    consumer = std::thread([&]{
+      b1.post();
+      for (auto& f : futures) {
+        sem_wait(&sem);
+        f.then(incr<int>);
+      }
+    });
+
+    producer = std::thread([&]{
+      b2.post();
+      for (auto& p : promises) {
+        sem_post(&sem);
+        p.setValue(42);
+      }
+    });
+
+    b1.wait();
+    b2.wait();
+  }
+
+  // The astute reader will notice that we're not *precisely* comparing apples
+  // to apples here. Well, maybe it's like comparing Granny Smith to
+  // Braeburn or something. In the serial version, we waited for the futures
+  // to be all set up, but here we are probably still doing that work
+  // (although in parallel). But even though there is more work (on the order
+  // of 2x), it is being done by two threads. Hopefully most of the difference
+  // we see is due to lock contention and not false parallelism.
+  //
+  // Be warned that if the box is under heavy load, this will greatly skew
+  // these results (scheduling overhead will begin to dwarf lock contention).
+  // I'm not sure but I'd guess in Windtunnel this will mean large variance,
+  // because I expect they load the boxes as much as they can?
+  consumer.join();
+  producer.join();
+}
+
+BENCHMARK_DRAW_LINE();
+
+// The old way. Throw an exception, and rethrow to access it upstream.
+void throwAndCatchImpl() {
+  makeFuture()
+      .then([](Try<void>&&){ throw std::runtime_error("oh no"); })
+      .then([](Try<void>&& t) {
+        try {
+          t.value();
+        } catch(const std::runtime_error& e) {
+          // ...
+          return;
+        }
+        CHECK(false);
+      });
+}
+
+// Not much better. Throw an exception, and access it via the wrapper upstream.
+// Actually a little worse due to wrapper overhead. then() won't know that the
+// exception is a runtime_error, so will have to store it as an exception_ptr
+// anyways. withException will therefore have to rethrow. Note that if we threw
+// std::exception instead, we would see some wins, as that's the type then()
+// will try to wrap, so no exception_ptrs/rethrows are necessary.
+void throwAndCatchWrappedImpl() {
+  makeFuture()
+      .then([](Try<void>&&){ throw std::runtime_error("oh no"); })
+      .then([](Try<void>&& t) {
+        auto caught = t.withException<std::runtime_error>(
+            [](const std::runtime_error& e){
+              // ...
+            });
+        CHECK(caught);
+      });
+}
+
+// Better. Wrap an exception, and rethrow to access it upstream.
+void throwWrappedAndCatchImpl() {
+  makeFuture()
+      .then([](Try<void>&&){
+        return makeFuture<void>(std::runtime_error("oh no"));
+      })
+      .then([](Try<void>&& t) {
+        try {
+          t.value();
+        } catch(const std::runtime_error& e) {
+          // ...
+          return;
+        }
+        CHECK(false);
+      });
+}
+
+// The new way. Wrap an exception, and access it via the wrapper upstream
+void throwWrappedAndCatchWrappedImpl() {
+  makeFuture()
+      .then([](Try<void>&&){
+        return makeFuture<void>(std::runtime_error("oh no"));
+      })
+      .then([](Try<void>&& t){
+        auto caught = t.withException<std::runtime_error>(
+            [](const std::runtime_error& e){
+              // ...
+            });
+        CHECK(caught);
+      });
+}
+
+// Simulate heavy contention on func
+void contend(void(*func)()) {
+  folly::BenchmarkSuspender s;
+  const int N = 100;
+  const int iters = 1000;
+  pthread_barrier_t barrier;
+  pthread_barrier_init(&barrier, nullptr, N+1);
+  std::vector<std::thread> threads;
+  for (int i = 0; i < N; i++) {
+    threads.push_back(std::thread([&](){
+      pthread_barrier_wait(&barrier);
+      for (int j = 0; j < iters; j++) {
+        func();
+      }
+    }));
+  }
+  pthread_barrier_wait(&barrier);
+  s.dismiss();
+  for (auto& t : threads) {
+    t.join();
+  }
+  s.rehire();
+  pthread_barrier_destroy(&barrier);
+}
+
+BENCHMARK(throwAndCatch) {
+  throwAndCatchImpl();
+}
+
+BENCHMARK_RELATIVE(throwAndCatchWrapped) {
+  throwAndCatchWrappedImpl();
+}
+
+BENCHMARK_RELATIVE(throwWrappedAndCatch) {
+  throwWrappedAndCatchImpl();
+}
+
+BENCHMARK_RELATIVE(throwWrappedAndCatchWrapped) {
+  throwWrappedAndCatchWrappedImpl();
+}
+
+BENCHMARK_DRAW_LINE();
+
+BENCHMARK(throwAndCatchContended) {
+  contend(throwAndCatchImpl);
+}
+
+BENCHMARK_RELATIVE(throwAndCatchWrappedContended) {
+  contend(throwAndCatchWrappedImpl);
+}
+
+BENCHMARK_RELATIVE(throwWrappedAndCatchContended) {
+  contend(throwWrappedAndCatchImpl);
+}
+
+BENCHMARK_RELATIVE(throwWrappedAndCatchWrappedContended) {
+  contend(throwWrappedAndCatchWrappedImpl);
+}
+
+int main(int argc, char** argv) {
+  gflags::ParseCommandLineFlags(&argc, &argv, true);
+  folly::runBenchmarks();
+  return 0;
+}
diff --git a/folly/futures/test/ClientCompile.cpp b/folly/futures/test/ClientCompile.cpp
new file mode 100644 (file)
index 0000000..80d20cb
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// amazing what things can go wrong if you include things in an unexpected
+// order.
+#include <folly/futures/Try.h>
+#include <folly/futures/Promise.h>
+#include <folly/futures/Future.h>
+int main() { return 0; }
diff --git a/folly/futures/test/ExecutorTest.cpp b/folly/futures/test/ExecutorTest.cpp
new file mode 100644 (file)
index 0000000..2e9a3f6
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <folly/futures/InlineExecutor.h>
+#include <folly/futures/ManualExecutor.h>
+#include <folly/futures/QueuedImmediateExecutor.h>
+#include <folly/futures/Future.h>
+#include <folly/Baton.h>
+
+using namespace folly::wangle;
+using namespace std::chrono;
+using namespace testing;
+
+TEST(ManualExecutor, runIsStable) {
+  ManualExecutor x;
+  size_t count = 0;
+  auto f1 = [&]() { count++; };
+  auto f2 = [&]() { x.add(f1); x.add(f1); };
+  x.add(f2);
+  x.run();
+}
+
+TEST(ManualExecutor, scheduleDur) {
+  ManualExecutor x;
+  size_t count = 0;
+  milliseconds dur {10};
+  x.schedule([&]{ count++; }, dur);
+  EXPECT_EQ(count, 0);
+  x.run();
+  EXPECT_EQ(count, 0);
+  x.advance(dur/2);
+  EXPECT_EQ(count, 0);
+  x.advance(dur/2);
+  EXPECT_EQ(count, 1);
+}
+
+TEST(ManualExecutor, clockStartsAt0) {
+  ManualExecutor x;
+  EXPECT_EQ(x.now(), x.now().min());
+}
+
+TEST(ManualExecutor, scheduleAbs) {
+  ManualExecutor x;
+  size_t count = 0;
+  x.scheduleAt([&]{ count++; }, x.now() + milliseconds(10));
+  EXPECT_EQ(count, 0);
+  x.advance(milliseconds(10));
+  EXPECT_EQ(count, 1);
+}
+
+TEST(ManualExecutor, advanceTo) {
+  ManualExecutor x;
+  size_t count = 0;
+  x.scheduleAt([&]{ count++; }, steady_clock::now());
+  EXPECT_EQ(count, 0);
+  x.advanceTo(steady_clock::now());
+  EXPECT_EQ(count, 1);
+}
+
+TEST(ManualExecutor, advanceBack) {
+  ManualExecutor x;
+  size_t count = 0;
+  x.advance(microseconds(5));
+  x.schedule([&]{ count++; }, microseconds(6));
+  EXPECT_EQ(count, 0);
+  x.advanceTo(x.now() - microseconds(1));
+  EXPECT_EQ(count, 0);
+}
+
+TEST(ManualExecutor, advanceNeg) {
+  ManualExecutor x;
+  size_t count = 0;
+  x.advance(microseconds(5));
+  x.schedule([&]{ count++; }, microseconds(6));
+  EXPECT_EQ(count, 0);
+  x.advance(microseconds(-1));
+  EXPECT_EQ(count, 0);
+}
+
+TEST(ManualExecutor, waitForDoesNotDeadlock) {
+  ManualExecutor east, west;
+  folly::Baton<> baton;
+  auto f = makeFuture()
+    .via(&east)
+    .then([](Try<void>){ return makeFuture(); })
+    .via(&west);
+  std::thread t([&]{
+    baton.post();
+    west.waitFor(f);
+  });
+  baton.wait();
+  east.run();
+  t.join();
+}
+
+TEST(Executor, InlineExecutor) {
+  InlineExecutor x;
+  size_t counter = 0;
+  x.add([&]{
+    x.add([&]{
+      EXPECT_EQ(counter++, 0);
+    });
+    EXPECT_EQ(counter++, 1);
+  });
+  EXPECT_EQ(counter, 2);
+}
+
+TEST(Executor, QueuedImmediateExecutor) {
+  QueuedImmediateExecutor x;
+  size_t counter = 0;
+  x.add([&]{
+    x.add([&]{
+      EXPECT_EQ(1, counter++);
+    });
+    EXPECT_EQ(0, counter++);
+  });
+  EXPECT_EQ(2, counter);
+}
+
+TEST(Executor, Runnable) {
+  InlineExecutor x;
+  size_t counter = 0;
+  struct Runnable {
+    std::function<void()> fn;
+    void operator()() { fn(); }
+  };
+  Runnable f;
+  f.fn = [&]{ counter++; };
+  x.add(f);
+  EXPECT_EQ(counter, 1);
+}
+
+TEST(Executor, RunnablePtr) {
+  InlineExecutor x;
+  struct Runnable {
+    std::function<void()> fn;
+    void operator()() { fn(); }
+  };
+  size_t counter = 0;
+  auto fnp = std::make_shared<Runnable>();
+  fnp->fn = [&]{ counter++; };
+  x.addPtr(fnp);
+  EXPECT_EQ(counter, 1);
+}
diff --git a/folly/futures/test/FSM.cpp b/folly/futures/test/FSM.cpp
new file mode 100644 (file)
index 0000000..e4fef36
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <folly/futures/detail/FSM.h>
+
+using namespace folly::wangle::detail;
+
+enum class State { A, B };
+
+TEST(FSM, example) {
+  FSM<State> fsm(State::A);
+  int count = 0;
+  int unprotectedCount = 0;
+
+  // somebody set up us the switch
+  auto tryTransition = [&]{
+    switch (fsm.getState()) {
+    case State::A:
+      return fsm.updateState(State::A, State::B, [&]{ count++; });
+    case State::B:
+      return fsm.updateState(State::B, State::A,
+                             [&]{ count--; }, [&]{ unprotectedCount--; });
+    }
+    return false; // unreachable
+  };
+
+  // keep retrying until success (like a cas)
+  while (!tryTransition()) ;
+  EXPECT_EQ(State::B, fsm.getState());
+  EXPECT_EQ(1, count);
+  EXPECT_EQ(0, unprotectedCount);
+
+  while (!tryTransition()) ;
+  EXPECT_EQ(State::A, fsm.getState());
+  EXPECT_EQ(0, count);
+  EXPECT_EQ(-1, unprotectedCount);
+}
+
+TEST(FSM, magicMacrosExample) {
+  struct MyFSM : public FSM<State> {
+    int count = 0;
+    int unprotectedCount = 0;
+    MyFSM() : FSM<State>(State::A) {}
+    void twiddle() {
+      FSM_START
+        FSM_CASE(State::A, State::B, [&]{ count++; });
+        FSM_CASE2(State::B, State::A,
+                  [&]{ count--; }, [&]{ unprotectedCount--; });
+      FSM_END
+    }
+  };
+
+  MyFSM fsm;
+
+  fsm.twiddle();
+  EXPECT_EQ(State::B, fsm.getState());
+  EXPECT_EQ(1, fsm.count);
+  EXPECT_EQ(0, fsm.unprotectedCount);
+
+  fsm.twiddle();
+  EXPECT_EQ(State::A, fsm.getState());
+  EXPECT_EQ(0, fsm.count);
+  EXPECT_EQ(-1, fsm.unprotectedCount);
+}
+
+
+TEST(FSM, ctor) {
+  FSM<State> fsm(State::A);
+  EXPECT_EQ(State::A, fsm.getState());
+}
+
+TEST(FSM, update) {
+  FSM<State> fsm(State::A);
+  EXPECT_TRUE(fsm.updateState(State::A, State::B, []{}));
+  EXPECT_EQ(State::B, fsm.getState());
+}
+
+TEST(FSM, badUpdate) {
+  FSM<State> fsm(State::A);
+  EXPECT_FALSE(fsm.updateState(State::B, State::A, []{}));
+}
+
+TEST(FSM, actionOnUpdate) {
+  FSM<State> fsm(State::A);
+  int count = 0;
+  fsm.updateState(State::A, State::B, [&]{ count++; });
+  EXPECT_EQ(1, count);
+}
+
+TEST(FSM, noActionOnBadUpdate) {
+  FSM<State> fsm(State::A);
+  int count = 0;
+  fsm.updateState(State::B, State::A, [&]{ count++; });
+  EXPECT_EQ(0, count);
+}
+
+TEST(FSM, stateTransitionAfterAction) {
+  FSM<State> fsm(State::A);
+  fsm.updateState(State::A, State::B,
+                  [&]{ EXPECT_EQ(State::A, fsm.getState()); });
+}
diff --git a/folly/futures/test/FutureTest.cpp b/folly/futures/test/FutureTest.cpp
new file mode 100644 (file)
index 0000000..c135bf2
--- /dev/null
@@ -0,0 +1,1204 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <atomic>
+#include <folly/small_vector.h>
+#include <gtest/gtest.h>
+#include <memory>
+#include <string>
+#include <thread>
+#include <type_traits>
+#include <unistd.h>
+#include <folly/Memory.h>
+#include <folly/Executor.h>
+#include <folly/futures/Future.h>
+#include <folly/futures/ManualExecutor.h>
+#include <folly/MPMCQueue.h>
+
+#include <folly/io/async/Request.h>
+
+using namespace folly;
+using namespace folly::wangle;
+using std::pair;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+#define EXPECT_TYPE(x, T) \
+  EXPECT_TRUE((std::is_same<decltype(x), T>::value))
+
+/// Simple executor that does work in another thread
+class ThreadExecutor : public Executor {
+  folly::MPMCQueue<Func> funcs;
+  std::atomic<bool> done {false};
+  std::thread worker;
+  folly::Baton<> baton;
+
+  void work() {
+    baton.post();
+    Func fn;
+    while (!done) {
+      while (!funcs.isEmpty()) {
+        funcs.blockingRead(fn);
+        fn();
+      }
+    }
+  }
+
+ public:
+  explicit ThreadExecutor(size_t n = 1024)
+    : funcs(n), worker(std::bind(&ThreadExecutor::work, this)) {}
+
+  ~ThreadExecutor() {
+    done = true;
+    funcs.write([]{});
+    worker.join();
+  }
+
+  void add(Func fn) override {
+    funcs.blockingWrite(std::move(fn));
+  }
+
+  void waitForStartup() {
+    baton.wait();
+  }
+};
+
+typedef WangleException eggs_t;
+static eggs_t eggs("eggs");
+
+// Future
+
+TEST(Future, onError) {
+  bool theFlag = false;
+  auto flag = [&]{ theFlag = true; };
+#define EXPECT_FLAG() \
+  do { \
+    EXPECT_TRUE(theFlag); \
+    theFlag = false; \
+  } while(0);
+
+#define EXPECT_NO_FLAG() \
+  do { \
+    EXPECT_FALSE(theFlag); \
+    theFlag = false; \
+  } while(0);
+
+  // By reference
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; })
+      .onError([&] (eggs_t& e) { flag(); });
+    EXPECT_FLAG();
+    EXPECT_NO_THROW(f.value());
+  }
+
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; })
+      .onError([&] (eggs_t& e) { flag(); return makeFuture(); });
+    EXPECT_FLAG();
+    EXPECT_NO_THROW(f.value());
+  }
+
+  // By value
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; })
+      .onError([&] (eggs_t e) { flag(); });
+    EXPECT_FLAG();
+    EXPECT_NO_THROW(f.value());
+  }
+
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; })
+      .onError([&] (eggs_t e) { flag(); return makeFuture(); });
+    EXPECT_FLAG();
+    EXPECT_NO_THROW(f.value());
+  }
+
+  // Polymorphic
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; })
+      .onError([&] (std::exception& e) { flag(); });
+    EXPECT_FLAG();
+    EXPECT_NO_THROW(f.value());
+  }
+
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; })
+      .onError([&] (std::exception& e) { flag(); return makeFuture(); });
+    EXPECT_FLAG();
+    EXPECT_NO_THROW(f.value());
+  }
+
+  // Non-exceptions
+  {
+    auto f = makeFuture()
+      .then([] { throw -1; })
+      .onError([&] (int e) { flag(); });
+    EXPECT_FLAG();
+    EXPECT_NO_THROW(f.value());
+  }
+
+  {
+    auto f = makeFuture()
+      .then([] { throw -1; })
+      .onError([&] (int e) { flag(); return makeFuture(); });
+    EXPECT_FLAG();
+    EXPECT_NO_THROW(f.value());
+  }
+
+  // Mutable lambda
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; })
+      .onError([&] (eggs_t& e) mutable { flag(); });
+    EXPECT_FLAG();
+    EXPECT_NO_THROW(f.value());
+  }
+
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; })
+      .onError([&] (eggs_t& e) mutable { flag(); return makeFuture(); });
+    EXPECT_FLAG();
+    EXPECT_NO_THROW(f.value());
+  }
+
+  // No throw
+  {
+    auto f = makeFuture()
+      .then([] { return 42; })
+      .onError([&] (eggs_t& e) { flag(); return -1; });
+    EXPECT_NO_FLAG();
+    EXPECT_EQ(42, f.value());
+  }
+
+  {
+    auto f = makeFuture()
+      .then([] { return 42; })
+      .onError([&] (eggs_t& e) { flag(); return makeFuture<int>(-1); });
+    EXPECT_NO_FLAG();
+    EXPECT_EQ(42, f.value());
+  }
+
+  // Catch different exception
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; })
+      .onError([&] (std::runtime_error& e) { flag(); });
+    EXPECT_NO_FLAG();
+    EXPECT_THROW(f.value(), eggs_t);
+  }
+
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; })
+      .onError([&] (std::runtime_error& e) { flag(); return makeFuture(); });
+    EXPECT_NO_FLAG();
+    EXPECT_THROW(f.value(), eggs_t);
+  }
+
+  // Returned value propagates
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; return 0; })
+      .onError([&] (eggs_t& e) { return 42; });
+    EXPECT_EQ(42, f.value());
+  }
+
+  // Returned future propagates
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; return 0; })
+      .onError([&] (eggs_t& e) { return makeFuture<int>(42); });
+    EXPECT_EQ(42, f.value());
+  }
+
+  // Throw in callback
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; return 0; })
+      .onError([&] (eggs_t& e) { throw e; return -1; });
+    EXPECT_THROW(f.value(), eggs_t);
+  }
+
+  {
+    auto f = makeFuture()
+      .then([] { throw eggs; return 0; })
+      .onError([&] (eggs_t& e) { throw e; return makeFuture<int>(-1); });
+    EXPECT_THROW(f.value(), eggs_t);
+  }
+}
+
+TEST(Future, try) {
+  class A {
+   public:
+    A(int x) : x_(x) {}
+
+    int x() const {
+      return x_;
+    }
+   private:
+    int x_;
+  };
+
+  A a(5);
+  Try<A> t_a(std::move(a));
+
+  Try<void> t_void;
+
+  EXPECT_EQ(5, t_a.value().x());
+}
+
+TEST(Future, special) {
+  EXPECT_FALSE(std::is_copy_constructible<Future<int>>::value);
+  EXPECT_FALSE(std::is_copy_assignable<Future<int>>::value);
+  EXPECT_TRUE(std::is_move_constructible<Future<int>>::value);
+  EXPECT_TRUE(std::is_move_assignable<Future<int>>::value);
+}
+
+TEST(Future, thenTry) {
+  bool flag = false;
+
+  makeFuture<int>(42).then([&](Try<int>&& t) {
+                              flag = true;
+                              EXPECT_EQ(42, t.value());
+                            });
+  EXPECT_TRUE(flag); flag = false;
+
+  makeFuture<int>(42)
+    .then([](Try<int>&& t) { return t.value(); })
+    .then([&](Try<int>&& t) { flag = true; EXPECT_EQ(42, t.value()); });
+  EXPECT_TRUE(flag); flag = false;
+
+  makeFuture().then([&](Try<void>&& t) { flag = true; t.value(); });
+  EXPECT_TRUE(flag); flag = false;
+
+  Promise<void> p;
+  auto f = p.getFuture().then([&](Try<void>&& t) { flag = true; });
+  EXPECT_FALSE(flag);
+  EXPECT_FALSE(f.isReady());
+  p.setValue();
+  EXPECT_TRUE(flag);
+  EXPECT_TRUE(f.isReady());
+}
+
+TEST(Future, thenValue) {
+  bool flag = false;
+  makeFuture<int>(42).then([&](int i){
+    EXPECT_EQ(42, i);
+    flag = true;
+  });
+  EXPECT_TRUE(flag); flag = false;
+
+  makeFuture<int>(42)
+    .then([](int i){ return i; })
+    .then([&](int i) { flag = true; EXPECT_EQ(42, i); });
+  EXPECT_TRUE(flag); flag = false;
+
+  makeFuture().then([&]{
+    flag = true;
+  });
+  EXPECT_TRUE(flag); flag = false;
+
+  auto f = makeFuture<int>(eggs).then([&](int i){});
+  EXPECT_THROW(f.value(), eggs_t);
+
+  f = makeFuture<void>(eggs).then([&]{});
+  EXPECT_THROW(f.value(), eggs_t);
+}
+
+TEST(Future, thenValueFuture) {
+  bool flag = false;
+  makeFuture<int>(42)
+    .then([](int i){ return makeFuture<int>(std::move(i)); })
+    .then([&](Try<int>&& t) { flag = true; EXPECT_EQ(42, t.value()); });
+  EXPECT_TRUE(flag); flag = false;
+
+  makeFuture()
+    .then([]{ return makeFuture(); })
+    .then([&](Try<void>&& t) { flag = true; });
+  EXPECT_TRUE(flag); flag = false;
+}
+
+static string doWorkStatic(Try<string>&& t) {
+  return t.value() + ";static";
+}
+
+TEST(Future, thenFunction) {
+  struct Worker {
+    string doWork(Try<string>&& t) {
+      return t.value() + ";class";
+    }
+    static string doWorkStatic(Try<string>&& t) {
+      return t.value() + ";class-static";
+    }
+  } w;
+
+  auto f = makeFuture<string>("start")
+    .then(doWorkStatic)
+    .then(Worker::doWorkStatic)
+    .then(&w, &Worker::doWork);
+
+  EXPECT_EQ(f.value(), "start;static;class-static;class");
+}
+
+static Future<string> doWorkStaticFuture(Try<string>&& t) {
+  return makeFuture(t.value() + ";static");
+}
+
+TEST(Future, thenFunctionFuture) {
+  struct Worker {
+    Future<string> doWorkFuture(Try<string>&& t) {
+      return makeFuture(t.value() + ";class");
+    }
+    static Future<string> doWorkStaticFuture(Try<string>&& t) {
+      return makeFuture(t.value() + ";class-static");
+    }
+  } w;
+
+  auto f = makeFuture<string>("start")
+    .then(doWorkStaticFuture)
+    .then(Worker::doWorkStaticFuture)
+    .then(&w, &Worker::doWorkFuture);
+
+  EXPECT_EQ(f.value(), "start;static;class-static;class");
+}
+
+TEST(Future, value) {
+  auto f = makeFuture(unique_ptr<int>(new int(42)));
+  auto up = std::move(f.value());
+  EXPECT_EQ(42, *up);
+
+  EXPECT_THROW(makeFuture<int>(eggs).value(), eggs_t);
+}
+
+TEST(Future, isReady) {
+  Promise<int> p;
+  auto f = p.getFuture();
+  EXPECT_FALSE(f.isReady());
+  p.setValue(42);
+  EXPECT_TRUE(f.isReady());
+  }
+
+TEST(Future, futureNotReady) {
+  Promise<int> p;
+  Future<int> f = p.getFuture();
+  EXPECT_THROW(f.value(), eggs_t);
+}
+
+TEST(Future, hasException) {
+  EXPECT_TRUE(makeFuture<int>(eggs).getTry().hasException());
+  EXPECT_FALSE(makeFuture(42).getTry().hasException());
+}
+
+TEST(Future, hasValue) {
+  EXPECT_TRUE(makeFuture(42).getTry().hasValue());
+  EXPECT_FALSE(makeFuture<int>(eggs).getTry().hasValue());
+}
+
+TEST(Future, makeFuture) {
+  EXPECT_TYPE(makeFuture(42), Future<int>);
+  EXPECT_EQ(42, makeFuture(42).value());
+
+  EXPECT_TYPE(makeFuture<float>(42), Future<float>);
+  EXPECT_EQ(42, makeFuture<float>(42).value());
+
+  auto fun = [] { return 42; };
+  EXPECT_TYPE(makeFutureTry(fun), Future<int>);
+  EXPECT_EQ(42, makeFutureTry(fun).value());
+
+  auto failfun = []() -> int { throw eggs; };
+  EXPECT_TYPE(makeFutureTry(failfun), Future<int>);
+  EXPECT_THROW(makeFutureTry(failfun).value(), eggs_t);
+
+  EXPECT_TYPE(makeFuture(), Future<void>);
+}
+
+// Promise
+
+TEST(Promise, special) {
+  EXPECT_FALSE(std::is_copy_constructible<Promise<int>>::value);
+  EXPECT_FALSE(std::is_copy_assignable<Promise<int>>::value);
+  EXPECT_TRUE(std::is_move_constructible<Promise<int>>::value);
+  EXPECT_TRUE(std::is_move_assignable<Promise<int>>::value);
+}
+
+TEST(Promise, getFuture) {
+  Promise<int> p;
+  Future<int> f = p.getFuture();
+  EXPECT_FALSE(f.isReady());
+}
+
+TEST(Promise, setValue) {
+  Promise<int> fund;
+  auto ffund = fund.getFuture();
+  fund.setValue(42);
+  EXPECT_EQ(42, ffund.value());
+
+  struct Foo {
+    string name;
+    int value;
+  };
+
+  Promise<Foo> pod;
+  auto fpod = pod.getFuture();
+  Foo f = {"the answer", 42};
+  pod.setValue(f);
+  Foo f2 = fpod.value();
+  EXPECT_EQ(f.name, f2.name);
+  EXPECT_EQ(f.value, f2.value);
+
+  pod = Promise<Foo>();
+  fpod = pod.getFuture();
+  pod.setValue(std::move(f2));
+  Foo f3 = fpod.value();
+  EXPECT_EQ(f.name, f3.name);
+  EXPECT_EQ(f.value, f3.value);
+
+  Promise<unique_ptr<int>> mov;
+  auto fmov = mov.getFuture();
+  mov.setValue(unique_ptr<int>(new int(42)));
+  unique_ptr<int> ptr = std::move(fmov.value());
+  EXPECT_EQ(42, *ptr);
+
+  Promise<void> v;
+  auto fv = v.getFuture();
+  v.setValue();
+  EXPECT_TRUE(fv.isReady());
+}
+
+TEST(Promise, setException) {
+  {
+    Promise<void> p;
+    auto f = p.getFuture();
+    p.setException(eggs);
+    EXPECT_THROW(f.value(), eggs_t);
+  }
+  {
+    Promise<void> p;
+    auto f = p.getFuture();
+    try {
+      throw eggs;
+    } catch (...) {
+      p.setException(exception_wrapper(std::current_exception()));
+    }
+    EXPECT_THROW(f.value(), eggs_t);
+  }
+}
+
+TEST(Promise, fulfil) {
+  {
+    Promise<int> p;
+    auto f = p.getFuture();
+    p.fulfil([] { return 42; });
+    EXPECT_EQ(42, f.value());
+  }
+  {
+    Promise<int> p;
+    auto f = p.getFuture();
+    p.fulfil([]() -> int { throw eggs; });
+    EXPECT_THROW(f.value(), eggs_t);
+  }
+}
+
+TEST(Future, finish) {
+  auto x = std::make_shared<int>(0);
+  {
+    Promise<int> p;
+    auto f = p.getFuture().then([x](Try<int>&& t) { *x = t.value(); });
+
+    // The callback hasn't executed
+    EXPECT_EQ(0, *x);
+
+    // The callback has a reference to x
+    EXPECT_EQ(2, x.use_count());
+
+    p.setValue(42);
+
+    // the callback has executed
+    EXPECT_EQ(42, *x);
+  }
+  // the callback has been destructed
+  // and has released its reference to x
+  EXPECT_EQ(1, x.use_count());
+}
+
+TEST(Future, unwrap) {
+  Promise<int> a;
+  Promise<int> b;
+
+  auto fa = a.getFuture();
+  auto fb = b.getFuture();
+
+  bool flag1 = false;
+  bool flag2 = false;
+
+  // do a, then do b, and get the result of a + b.
+  Future<int> f = fa.then([&](Try<int>&& ta) {
+    auto va = ta.value();
+    flag1 = true;
+    return fb.then([va, &flag2](Try<int>&& tb) {
+      flag2 = true;
+      return va + tb.value();
+    });
+  });
+
+  EXPECT_FALSE(flag1);
+  EXPECT_FALSE(flag2);
+  EXPECT_FALSE(f.isReady());
+
+  a.setValue(3);
+  EXPECT_TRUE(flag1);
+  EXPECT_FALSE(flag2);
+  EXPECT_FALSE(f.isReady());
+
+  b.setValue(4);
+  EXPECT_TRUE(flag1);
+  EXPECT_TRUE(flag2);
+  EXPECT_EQ(7, f.value());
+}
+
+TEST(Future, whenAll) {
+  // returns a vector variant
+  {
+    vector<Promise<int>> promises(10);
+    vector<Future<int>> futures;
+
+    for (auto& p : promises)
+      futures.push_back(p.getFuture());
+
+    auto allf = whenAll(futures.begin(), futures.end());
+
+    random_shuffle(promises.begin(), promises.end());
+    for (auto& p : promises) {
+      EXPECT_FALSE(allf.isReady());
+      p.setValue(42);
+    }
+
+    EXPECT_TRUE(allf.isReady());
+    auto& results = allf.value();
+    for (auto& t : results) {
+      EXPECT_EQ(42, t.value());
+    }
+  }
+
+  // check error semantics
+  {
+    vector<Promise<int>> promises(4);
+    vector<Future<int>> futures;
+
+    for (auto& p : promises)
+      futures.push_back(p.getFuture());
+
+    auto allf = whenAll(futures.begin(), futures.end());
+
+
+    promises[0].setValue(42);
+    promises[1].setException(eggs);
+
+    EXPECT_FALSE(allf.isReady());
+
+    promises[2].setValue(42);
+
+    EXPECT_FALSE(allf.isReady());
+
+    promises[3].setException(eggs);
+
+    EXPECT_TRUE(allf.isReady());
+    EXPECT_FALSE(allf.getTry().hasException());
+
+    auto& results = allf.value();
+    EXPECT_EQ(42, results[0].value());
+    EXPECT_TRUE(results[1].hasException());
+    EXPECT_EQ(42, results[2].value());
+    EXPECT_TRUE(results[3].hasException());
+  }
+
+  // check that futures are ready in then()
+  {
+    vector<Promise<void>> promises(10);
+    vector<Future<void>> futures;
+
+    for (auto& p : promises)
+      futures.push_back(p.getFuture());
+
+    auto allf = whenAll(futures.begin(), futures.end())
+      .then([](Try<vector<Try<void>>>&& ts) {
+        for (auto& f : ts.value())
+          f.value();
+      });
+
+    random_shuffle(promises.begin(), promises.end());
+    for (auto& p : promises)
+      p.setValue();
+    EXPECT_TRUE(allf.isReady());
+  }
+}
+
+
+TEST(Future, whenAny) {
+  {
+    vector<Promise<int>> promises(10);
+    vector<Future<int>> futures;
+
+    for (auto& p : promises)
+      futures.push_back(p.getFuture());
+
+    for (auto& f : futures) {
+      EXPECT_FALSE(f.isReady());
+    }
+
+    auto anyf = whenAny(futures.begin(), futures.end());
+
+    /* futures were moved in, so these are invalid now */
+    EXPECT_FALSE(anyf.isReady());
+
+    promises[7].setValue(42);
+    EXPECT_TRUE(anyf.isReady());
+    auto& idx_fut = anyf.value();
+
+    auto i = idx_fut.first;
+    EXPECT_EQ(7, i);
+
+    auto& f = idx_fut.second;
+    EXPECT_EQ(42, f.value());
+  }
+
+  // error
+  {
+    vector<Promise<void>> promises(10);
+    vector<Future<void>> futures;
+
+    for (auto& p : promises)
+      futures.push_back(p.getFuture());
+
+    for (auto& f : futures) {
+      EXPECT_FALSE(f.isReady());
+    }
+
+    auto anyf = whenAny(futures.begin(), futures.end());
+
+    EXPECT_FALSE(anyf.isReady());
+
+    promises[3].setException(eggs);
+    EXPECT_TRUE(anyf.isReady());
+    EXPECT_TRUE(anyf.value().second.hasException());
+  }
+
+  // then()
+  {
+    vector<Promise<int>> promises(10);
+    vector<Future<int>> futures;
+
+    for (auto& p : promises)
+      futures.push_back(p.getFuture());
+
+    auto anyf = whenAny(futures.begin(), futures.end())
+      .then([](Try<pair<size_t, Try<int>>>&& f) {
+        EXPECT_EQ(42, f.value().second.value());
+      });
+
+    promises[3].setValue(42);
+    EXPECT_TRUE(anyf.isReady());
+  }
+}
+
+
+TEST(when, already_completed) {
+  {
+    vector<Future<void>> fs;
+    for (int i = 0; i < 10; i++)
+      fs.push_back(makeFuture());
+
+    whenAll(fs.begin(), fs.end())
+      .then([&](Try<vector<Try<void>>>&& t) {
+        EXPECT_EQ(fs.size(), t.value().size());
+      });
+  }
+  {
+    vector<Future<int>> fs;
+    for (int i = 0; i < 10; i++)
+      fs.push_back(makeFuture(i));
+
+    whenAny(fs.begin(), fs.end())
+      .then([&](Try<pair<size_t, Try<int>>>&& t) {
+        auto& p = t.value();
+        EXPECT_EQ(p.first, p.second.value());
+      });
+  }
+}
+
+TEST(when, whenN) {
+  vector<Promise<void>> promises(10);
+  vector<Future<void>> futures;
+
+  for (auto& p : promises)
+    futures.push_back(p.getFuture());
+
+  bool flag = false;
+  size_t n = 3;
+  whenN(futures.begin(), futures.end(), n)
+    .then([&](Try<vector<pair<size_t, Try<void>>>>&& t) {
+      flag = true;
+      auto v = t.value();
+      EXPECT_EQ(n, v.size());
+      for (auto& tt : v)
+        EXPECT_TRUE(tt.second.hasValue());
+    });
+
+  promises[0].setValue();
+  EXPECT_FALSE(flag);
+  promises[1].setValue();
+  EXPECT_FALSE(flag);
+  promises[2].setValue();
+  EXPECT_TRUE(flag);
+}
+
+/* Ensure that we can compile when_{all,any} with folly::small_vector */
+TEST(when, small_vector) {
+
+  static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<void>),
+                "Futures should not be trivially copyable");
+  static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<int>),
+                "Futures should not be trivially copyable");
+
+  using folly::small_vector;
+  {
+    small_vector<Future<void>> futures;
+
+    for (int i = 0; i < 10; i++)
+      futures.push_back(makeFuture());
+
+    auto anyf = whenAny(futures.begin(), futures.end());
+  }
+
+  {
+    small_vector<Future<void>> futures;
+
+    for (int i = 0; i < 10; i++)
+      futures.push_back(makeFuture());
+
+    auto allf = whenAll(futures.begin(), futures.end());
+  }
+}
+
+TEST(Future, whenAllVariadic) {
+  Promise<bool> pb;
+  Promise<int> pi;
+  Future<bool> fb = pb.getFuture();
+  Future<int> fi = pi.getFuture();
+  bool flag = false;
+  whenAll(std::move(fb), std::move(fi))
+    .then([&](Try<std::tuple<Try<bool>, Try<int>>>&& t) {
+      flag = true;
+      EXPECT_TRUE(t.hasValue());
+      EXPECT_TRUE(std::get<0>(t.value()).hasValue());
+      EXPECT_EQ(std::get<0>(t.value()).value(), true);
+      EXPECT_TRUE(std::get<1>(t.value()).hasValue());
+      EXPECT_EQ(std::get<1>(t.value()).value(), 42);
+    });
+  pb.setValue(true);
+  EXPECT_FALSE(flag);
+  pi.setValue(42);
+  EXPECT_TRUE(flag);
+}
+
+TEST(Future, whenAllVariadicReferences) {
+  Promise<bool> pb;
+  Promise<int> pi;
+  Future<bool> fb = pb.getFuture();
+  Future<int> fi = pi.getFuture();
+  bool flag = false;
+  whenAll(fb, fi)
+    .then([&](Try<std::tuple<Try<bool>, Try<int>>>&& t) {
+      flag = true;
+      EXPECT_TRUE(t.hasValue());
+      EXPECT_TRUE(std::get<0>(t.value()).hasValue());
+      EXPECT_EQ(std::get<0>(t.value()).value(), true);
+      EXPECT_TRUE(std::get<1>(t.value()).hasValue());
+      EXPECT_EQ(std::get<1>(t.value()).value(), 42);
+    });
+  pb.setValue(true);
+  EXPECT_FALSE(flag);
+  pi.setValue(42);
+  EXPECT_TRUE(flag);
+}
+
+TEST(Future, whenAll_none) {
+  vector<Future<int>> fs;
+  auto f = whenAll(fs.begin(), fs.end());
+  EXPECT_TRUE(f.isReady());
+}
+
+TEST(Future, throwCaughtInImmediateThen) {
+  // Neither of these should throw "Promise already satisfied"
+  makeFuture().then(
+    [=](Try<void>&&) -> int { throw std::exception(); });
+  makeFuture().then(
+    [=](Try<void>&&) -> Future<int> { throw std::exception(); });
+}
+
+TEST(Future, throwIfFailed) {
+  makeFuture<void>(eggs)
+    .then([=](Try<void>&& t) {
+      EXPECT_THROW(t.throwIfFailed(), eggs_t);
+    });
+  makeFuture()
+    .then([=](Try<void>&& t) {
+      EXPECT_NO_THROW(t.throwIfFailed());
+    });
+
+  makeFuture<int>(eggs)
+    .then([=](Try<int>&& t) {
+      EXPECT_THROW(t.throwIfFailed(), eggs_t);
+    });
+  makeFuture<int>(42)
+    .then([=](Try<int>&& t) {
+      EXPECT_NO_THROW(t.throwIfFailed());
+    });
+}
+
+TEST(Future, waitWithSemaphoreImmediate) {
+  waitWithSemaphore(makeFuture());
+  auto done = waitWithSemaphore(makeFuture(42)).value();
+  EXPECT_EQ(42, done);
+
+  vector<int> v{1,2,3};
+  auto done_v = waitWithSemaphore(makeFuture(v)).value();
+  EXPECT_EQ(v.size(), done_v.size());
+  EXPECT_EQ(v, done_v);
+
+  vector<Future<void>> v_f;
+  v_f.push_back(makeFuture());
+  v_f.push_back(makeFuture());
+  auto done_v_f = waitWithSemaphore(whenAll(v_f.begin(), v_f.end())).value();
+  EXPECT_EQ(2, done_v_f.size());
+
+  vector<Future<bool>> v_fb;
+  v_fb.push_back(makeFuture(true));
+  v_fb.push_back(makeFuture(false));
+  auto fut = whenAll(v_fb.begin(), v_fb.end());
+  auto done_v_fb = std::move(waitWithSemaphore(std::move(fut)).value());
+  EXPECT_EQ(2, done_v_fb.size());
+}
+
+TEST(Future, waitWithSemaphore) {
+  Promise<int> p;
+  Future<int> f = p.getFuture();
+  std::atomic<bool> flag{false};
+  std::atomic<int> result{1};
+  std::atomic<std::thread::id> id;
+
+  std::thread t([&](Future<int>&& tf){
+      auto n = tf.then([&](Try<int> && t) {
+          id = std::this_thread::get_id();
+          return t.value();
+        });
+      flag = true;
+      result.store(waitWithSemaphore(std::move(n)).value());
+    },
+    std::move(f)
+    );
+  while(!flag){}
+  EXPECT_EQ(result.load(), 1);
+  p.setValue(42);
+  t.join();
+  // validate that the callback ended up executing in this thread, which
+  // is more to ensure that this test actually tests what it should
+  EXPECT_EQ(id, std::this_thread::get_id());
+  EXPECT_EQ(result.load(), 42);
+}
+
+TEST(Future, waitWithSemaphoreForTime) {
+ {
+  Promise<int> p;
+  Future<int> f = p.getFuture();
+  auto t = waitWithSemaphore(std::move(f),
+    std::chrono::microseconds(1));
+  EXPECT_FALSE(t.isReady());
+  p.setValue(1);
+  EXPECT_TRUE(t.isReady());
+ }
+ {
+  Promise<int> p;
+  Future<int> f = p.getFuture();
+  p.setValue(1);
+  auto t = waitWithSemaphore(std::move(f),
+    std::chrono::milliseconds(1));
+  EXPECT_TRUE(t.isReady());
+ }
+ {
+  vector<Future<bool>> v_fb;
+  v_fb.push_back(makeFuture(true));
+  v_fb.push_back(makeFuture(false));
+  auto f = whenAll(v_fb.begin(), v_fb.end());
+  auto t = waitWithSemaphore(std::move(f),
+    std::chrono::milliseconds(1));
+  EXPECT_TRUE(t.isReady());
+  EXPECT_EQ(2, t.value().size());
+ }
+ {
+  vector<Future<bool>> v_fb;
+  Promise<bool> p1;
+  Promise<bool> p2;
+  v_fb.push_back(p1.getFuture());
+  v_fb.push_back(p2.getFuture());
+  auto f = whenAll(v_fb.begin(), v_fb.end());
+  auto t = waitWithSemaphore(std::move(f),
+    std::chrono::milliseconds(1));
+  EXPECT_FALSE(t.isReady());
+  p1.setValue(true);
+  EXPECT_FALSE(t.isReady());
+  p2.setValue(true);
+  EXPECT_TRUE(t.isReady());
+ }
+ {
+  auto t = waitWithSemaphore(makeFuture(),
+    std::chrono::milliseconds(1));
+  EXPECT_TRUE(t.isReady());
+ }
+}
+
+TEST(Future, callbackAfterActivate) {
+  Promise<void> p;
+  auto f = p.getFuture();
+  f.deactivate();
+
+  size_t count = 0;
+  f.then([&](Try<void>&&) { count++; });
+
+  p.setValue();
+  EXPECT_EQ(0, count);
+
+  f.activate();
+  EXPECT_EQ(1, count);
+}
+
+TEST(Future, activateOnDestruct) {
+  auto f = std::make_shared<Future<void>>(makeFuture());
+  f->deactivate();
+
+  size_t count = 0;
+  f->then([&](Try<void>&&) { count++; });
+  EXPECT_EQ(0, count);
+
+  f.reset();
+  EXPECT_EQ(1, count);
+}
+
+TEST(Future, viaActsCold) {
+  ManualExecutor x;
+  size_t count = 0;
+
+  auto fv = via(&x);
+  fv.then([&](Try<void>&&) { count++; });
+
+  EXPECT_EQ(0, count);
+
+  fv.activate();
+
+  EXPECT_EQ(1, x.run());
+  EXPECT_EQ(1, count);
+}
+
+TEST(Future, viaIsCold) {
+  ManualExecutor x;
+  EXPECT_FALSE(via(&x).isActive());
+}
+
+TEST(Future, viaRaces) {
+  ManualExecutor x;
+  Promise<void> p;
+  auto tid = std::this_thread::get_id();
+  bool done = false;
+
+  std::thread t1([&] {
+    p.getFuture()
+      .via(&x)
+      .then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
+      .then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
+      .then([&](Try<void>&&) { done = true; });
+  });
+
+  std::thread t2([&] {
+    p.setValue();
+  });
+
+  while (!done) x.run();
+  t1.join();
+  t2.join();
+}
+
+// TODO(#4920689)
+TEST(Future, viaRaces_2stage) {
+  ManualExecutor x;
+  Promise<void> p;
+  auto tid = std::this_thread::get_id();
+  bool done = false;
+
+  std::thread t1([&] {
+    auto f2 = p.getFuture().via(&x);
+    f2.then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
+      .then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
+      .then([&](Try<void>&&) { done = true; });
+
+    // the bug was in the promise being fulfilled before f2 is reactivated. we
+    // could sleep, but yielding should cause this to fail with reasonable
+    // probability
+    std::this_thread::yield();
+    f2.activate();
+  });
+
+  std::thread t2([&] {
+    p.setValue();
+  });
+
+  while (!done) x.run();
+  t1.join();
+  t2.join();
+}
+
+TEST(Future, getFuture_after_setValue) {
+  Promise<int> p;
+  p.setValue(42);
+  EXPECT_EQ(42, p.getFuture().value());
+}
+
+TEST(Future, getFuture_after_setException) {
+  Promise<void> p;
+  p.fulfil([]() -> void { throw std::logic_error("foo"); });
+  EXPECT_THROW(p.getFuture().value(), std::logic_error);
+}
+
+TEST(Future, detachRace) {
+  // Task #5438209
+  // This test is designed to detect a race that was in Core::detachOne()
+  // where detached_ was incremented and then tested, and that
+  // allowed a race where both Promise and Future would think they were the
+  // second and both try to delete. This showed up at scale but was very
+  // difficult to reliably repro in a test. As it is, this only fails about
+  // once in every 1,000 executions. Doing this 1,000 times is going to make a
+  // slow test so I won't do that but if it ever fails, take it seriously, and
+  // run the test binary with "--gtest_repeat=10000 --gtest_filter=*detachRace"
+  // (Don't forget to enable ASAN)
+  auto p = folly::make_unique<Promise<bool>>();
+  auto f = folly::make_unique<Future<bool>>(p->getFuture());
+  folly::Baton<> baton;
+  std::thread t1([&]{
+    baton.post();
+    p.reset();
+  });
+  baton.wait();
+  f.reset();
+  t1.join();
+}
+
+class TestData : public RequestData {
+ public:
+  explicit TestData(int data) : data_(data) {}
+  virtual ~TestData() {}
+  int data_;
+};
+
+TEST(Future, context) {
+
+  // Start a new context
+  RequestContext::create();
+
+  EXPECT_EQ(nullptr, RequestContext::get()->getContextData("test"));
+
+  // Set some test data
+  RequestContext::get()->setContextData(
+    "test",
+    std::unique_ptr<TestData>(new TestData(10)));
+
+  // Start a future
+  Promise<void> p;
+  auto future = p.getFuture().then([&]{
+    // Check that the context followed the future
+    EXPECT_TRUE(RequestContext::get() != nullptr);
+    auto a = dynamic_cast<TestData*>(
+      RequestContext::get()->getContextData("test"));
+    auto data = a->data_;
+    EXPECT_EQ(10, data);
+  });
+
+  // Clear the context
+  RequestContext::setContext(nullptr);
+
+  EXPECT_EQ(nullptr, RequestContext::get()->getContextData("test"));
+
+  // Fulfil the promise
+  p.setValue();
+}
+
+
+// This only fails about 1 in 1k times when the bug is present :(
+TEST(Future, t5506504) {
+  ThreadExecutor x;
+
+  auto fn = [&x]{
+    auto promises = std::make_shared<vector<Promise<void>>>(4);
+    vector<Future<void>> futures;
+
+    for (auto& p : *promises) {
+      futures.emplace_back(
+        p.getFuture()
+        .via(&x)
+        .then([](Try<void>&&){}));
+    }
+
+    x.waitForStartup();
+    x.add([promises]{
+      for (auto& p : *promises) p.setValue();
+    });
+
+    return whenAll(futures.begin(), futures.end());
+  };
+
+  waitWithSemaphore(fn());
+}
+
+// Test of handling of a circular dependency. It's never recommended
+// to have one because of possible memory leaks. Here we test that
+// we can handle freeing of the Future while it is running.
+TEST(Future, CircularDependencySharedPtrSelfReset) {
+  Promise<int64_t> promise;
+  auto ptr = std::make_shared<Future<int64_t>>(promise.getFuture());
+
+  ptr->then(
+    [ptr] (folly::wangle::Try<int64_t>&& uid) mutable {
+      EXPECT_EQ(1, ptr.use_count());
+
+      // Leaving no references to ourselves.
+      ptr.reset();
+      EXPECT_EQ(0, ptr.use_count());
+    }
+  );
+
+  EXPECT_EQ(2, ptr.use_count());
+
+  ptr.reset();
+
+  promise.fulfil([]{return 1l;});
+}
diff --git a/folly/futures/test/Interrupts.cpp b/folly/futures/test/Interrupts.cpp
new file mode 100644 (file)
index 0000000..d4a35a7
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/futures/Future.h>
+#include <folly/futures/Promise.h>
+
+using namespace folly::wangle;
+using folly::exception_wrapper;
+
+TEST(Interrupts, raise) {
+  std::runtime_error eggs("eggs");
+  Promise<void> p;
+  p.setInterruptHandler([&](const exception_wrapper& e) {
+    EXPECT_THROW(e.throwException(), decltype(eggs));
+  });
+  p.getFuture().raise(eggs);
+}
+
+TEST(Interrupts, cancel) {
+  Promise<void> p;
+  p.setInterruptHandler([&](const exception_wrapper& e) {
+    EXPECT_THROW(e.throwException(), FutureCancellation);
+  });
+  p.getFuture().cancel();
+}
+
+TEST(Interrupts, handleThenInterrupt) {
+  Promise<int> p;
+  bool flag = false;
+  p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
+  p.getFuture().cancel();
+  EXPECT_TRUE(flag);
+}
+
+TEST(Interrupts, interruptThenHandle) {
+  Promise<int> p;
+  bool flag = false;
+  p.getFuture().cancel();
+  p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
+  EXPECT_TRUE(flag);
+}
+
+TEST(Interrupts, interruptAfterFulfilNoop) {
+  Promise<void> p;
+  bool flag = false;
+  p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
+  p.setValue();
+  p.getFuture().cancel();
+  EXPECT_FALSE(flag);
+}
+
+TEST(Interrupts, secondInterruptNoop) {
+  Promise<void> p;
+  int count = 0;
+  p.setInterruptHandler([&](const exception_wrapper& e) { count++; });
+  auto f = p.getFuture();
+  f.cancel();
+  f.cancel();
+  EXPECT_EQ(1, count);
+}
diff --git a/folly/futures/test/Thens.cpp b/folly/futures/test/Thens.cpp
new file mode 100644 (file)
index 0000000..1fb33dc
--- /dev/null
@@ -0,0 +1,34 @@
+// This file is @generated by thens.rb. Do not edit directly.
+
+// TODO: fails to compile with clang:dev.  See task #4412111
+#ifndef __clang__
+
+#include <folly/futures/test/Thens.h>
+
+TEST(Future, thenVariants) {
+  SomeClass anObject;
+  folly::Executor* anExecutor;
+
+  {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&&>());}
+  {Future<B> f = someFuture<A>().then([&](Try<A>&&){return someFuture<B>();});}
+  {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&&>);}
+  {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&&>);}
+  {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, A&&>);}
+  {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A&&>());}
+  {Future<B> f = someFuture<A>().then([&](A&&){return someFuture<B>();});}
+  {Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, Try<A>&&>);}
+  {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&&>());}
+  {Future<B> f = someFuture<A>().then([&](Try<A>&&){return B();});}
+  {Future<B> f = someFuture<A>().then(&aFunction<B, A&&>);}
+  {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&&>);}
+  {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, A&&>);}
+  {Future<B> f = someFuture<A>().then(aStdFunction<B, A&&>());}
+  {Future<B> f = someFuture<A>().then([&](A&&){return B();});}
+}
+
+#endif
diff --git a/folly/futures/test/Thens.h b/folly/futures/test/Thens.h
new file mode 100644 (file)
index 0000000..d65d914
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <gtest/gtest.h>
+#include <memory>
+#include <folly/futures/Future.h>
+#include <folly/Executor.h>
+
+using namespace folly::wangle;
+using namespace std;
+using namespace testing;
+
+typedef unique_ptr<int> A;
+struct B {};
+
+template <class T>
+using EnableIfFuture = typename std::enable_if<isFuture<T>::value>::type;
+
+template <class T>
+using EnableUnlessFuture = typename std::enable_if<!isFuture<T>::value>::type;
+
+template <class T>
+Future<T> someFuture() {
+  return makeFuture(T());
+}
+
+template <class Ret, class... Params, typename = void>
+Ret aFunction(Params...);
+
+template <class Ret, class... Params>
+typename std::enable_if<isFuture<Ret>::value, Ret>::type
+aFunction(Params...) {
+  typedef typename Ret::value_type T;
+  return makeFuture(T());
+}
+
+template <class Ret, class... Params>
+typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+aFunction(Params...) {
+  return Ret();
+}
+
+template <class Ret, class... Params>
+std::function<Ret(Params...)>
+aStdFunction(
+    typename std::enable_if<!isFuture<Ret>::value, bool>::type = false) {
+  return [](Params...) -> Ret { return Ret(); };
+}
+
+template <class Ret, class... Params>
+std::function<Ret(Params...)>
+aStdFunction(typename std::enable_if<isFuture<Ret>::value, bool>::type = true) {
+  typedef typename Ret::value_type T;
+  return [](Params...) -> Future<T> { return makeFuture(T()); };
+}
+
+class SomeClass {
+  B b;
+public:
+  template <class Ret, class... Params>
+  static Ret aStaticMethod(Params...);
+
+  template <class Ret, class... Params>
+  static
+  typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+  aStaticMethod(Params...) {
+    return Ret();
+  }
+
+  template <class Ret, class... Params>
+  static
+  typename std::enable_if<isFuture<Ret>::value, Ret>::type
+  aStaticMethod(Params...) {
+    typedef typename Ret::value_type T;
+    return makeFuture(T());
+  }
+
+  template <class Ret, class... Params>
+  Ret aMethod(Params...);
+
+  template <class Ret, class... Params>
+  typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+  aMethod(Params...) {
+    return Ret();
+  }
+
+  template <class Ret, class... Params>
+  typename std::enable_if<isFuture<Ret>::value, Ret>::type
+  aMethod(Params...) {
+    typedef typename Ret::value_type T;
+    return makeFuture(T());
+  }
+};
diff --git a/folly/futures/test/TimekeeperTest.cpp b/folly/futures/test/TimekeeperTest.cpp
new file mode 100644 (file)
index 0000000..2ede467
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <gtest/gtest.h>
+
+#include <folly/futures/Timekeeper.h>
+#include <unistd.h>
+
+using namespace folly::wangle;
+using namespace std::chrono;
+using folly::wangle::Timekeeper;
+using Duration = folly::wangle::Duration;
+
+std::chrono::milliseconds const one_ms(1);
+std::chrono::milliseconds const awhile(10);
+
+std::chrono::steady_clock::time_point now() {
+  return std::chrono::steady_clock::now();
+}
+
+struct TimekeeperFixture : public testing::Test {
+  TimekeeperFixture() :
+    timeLord_(folly::wangle::detail::getTimekeeperSingleton())
+  {}
+
+  Timekeeper* timeLord_;
+};
+
+TEST_F(TimekeeperFixture, after) {
+  Duration waited(0);
+
+  auto t1 = now();
+  auto f = timeLord_->after(awhile);
+  EXPECT_FALSE(f.isReady());
+  f.get();
+  auto t2 = now();
+
+  EXPECT_GE(t2 - t1, awhile);
+}
+
+TEST(Timekeeper, futureGet) {
+  Promise<int> p;
+  std::thread([&]{ p.setValue(42); }).detach();
+  EXPECT_EQ(42, p.getFuture().get());
+}
+
+TEST(Timekeeper, futureGetBeforeTimeout) {
+  Promise<int> p;
+  auto t = std::thread([&]{ p.setValue(42); });
+  // Technically this is a race and if the test server is REALLY overloaded
+  // and it takes more than a second to do that thread it could be flaky. But
+  // I want a low timeout (in human terms) so if this regresses and someone
+  // runs it by hand they're not sitting there forever wondering why it's
+  // blocked, and get a useful error message instead. If it does get flaky,
+  // empirically increase the timeout to the point where it's very improbable.
+  EXPECT_EQ(42, p.getFuture().get(seconds(2)));
+  t.join();
+}
+
+TEST(Timekeeper, futureGetTimeout) {
+  Promise<int> p;
+  EXPECT_THROW(p.getFuture().get(Duration(1)), folly::wangle::TimedOut);
+}
+
+TEST(Timekeeper, futureSleep) {
+  auto t1 = now();
+  futures::sleep(one_ms).get();
+  EXPECT_GE(now() - t1, one_ms);
+}
+
+TEST(Timekeeper, futureDelayed) {
+  auto t1 = now();
+  auto dur = makeFuture()
+    .delayed(one_ms)
+    .then([=]{ return now() - t1; })
+    .get();
+
+  EXPECT_GE(dur, one_ms);
+}
+
+TEST(Timekeeper, futureWithinThrows) {
+  Promise<int> p;
+  auto f = p.getFuture()
+    .within(one_ms)
+    .onError([](TimedOut&) { return -1; });
+
+  EXPECT_EQ(-1, f.get());
+}
+
+TEST(Timekeeper, futureWithinAlreadyComplete) {
+  auto f = makeFuture(42)
+    .within(one_ms)
+    .onError([&](TimedOut&){ return -1; });
+
+  EXPECT_EQ(42, f.get());
+}
+
+TEST(Timekeeper, futureWithinFinishesInTime) {
+  Promise<int> p;
+  auto f = p.getFuture()
+    .within(std::chrono::minutes(1))
+    .onError([&](TimedOut&){ return -1; });
+  p.setValue(42);
+
+  EXPECT_EQ(42, f.get());
+}
+
+TEST(Timekeeper, futureWithinVoidSpecialization) {
+  makeFuture().within(one_ms);
+}
+
+TEST(Timekeeper, futureWithinException) {
+  Promise<void> p;
+  auto f = p.getFuture().within(awhile, std::runtime_error("expected"));
+  EXPECT_THROW(f.get(), std::runtime_error);
+}
diff --git a/folly/futures/test/Try.cpp b/folly/futures/test/Try.cpp
new file mode 100644 (file)
index 0000000..5846f62
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/Memory.h>
+#include <folly/futures/Try.h>
+
+using namespace folly::wangle;
+
+TEST(Try, makeTryFunction) {
+  auto func = []() {
+    return folly::make_unique<int>(1);
+  };
+
+  auto result = makeTryFunction(func);
+  EXPECT_TRUE(result.hasValue());
+  EXPECT_EQ(*result.value(), 1);
+}
+
+TEST(Try, makeTryFunctionThrow) {
+  auto func = []() {
+    throw std::runtime_error("Runtime");
+    return folly::make_unique<int>(1);
+  };
+
+  auto result = makeTryFunction(func);
+  EXPECT_TRUE(result.hasException<std::runtime_error>());
+}
+
+TEST(Try, makeTryFunctionVoid) {
+  auto func = []() {
+    return;
+  };
+
+  auto result = makeTryFunction(func);
+  EXPECT_TRUE(result.hasValue());
+}
+
+TEST(Try, makeTryFunctionVoidThrow) {
+  auto func = []() {
+    throw std::runtime_error("Runtime");
+    return;
+  };
+
+  auto result = makeTryFunction(func);
+  EXPECT_TRUE(result.hasException<std::runtime_error>());
+}
diff --git a/folly/futures/test/ViaTest.cpp b/folly/futures/test/ViaTest.cpp
new file mode 100644 (file)
index 0000000..d940e10
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <thread>
+
+#include <folly/futures/Future.h>
+#include <folly/futures/InlineExecutor.h>
+#include <folly/futures/ManualExecutor.h>
+
+using namespace folly::wangle;
+
+struct ManualWaiter {
+  explicit ManualWaiter(std::shared_ptr<ManualExecutor> ex) : ex(ex) {}
+
+  void makeProgress() {
+    ex->wait();
+    ex->run();
+  }
+
+  std::shared_ptr<ManualExecutor> ex;
+};
+
+struct ViaFixture : public testing::Test {
+  ViaFixture() :
+    westExecutor(new ManualExecutor),
+    eastExecutor(new ManualExecutor),
+    waiter(new ManualWaiter(westExecutor)),
+    done(false)
+  {
+    t = std::thread([=] {
+      ManualWaiter eastWaiter(eastExecutor);
+      while (!done)
+        eastWaiter.makeProgress();
+      });
+  }
+
+  ~ViaFixture() {
+    done = true;
+    eastExecutor->add([=]() { });
+    t.join();
+  }
+
+  void addAsync(int a, int b, std::function<void(int&&)>&& cob) {
+    eastExecutor->add([=]() {
+      cob(a + b);
+    });
+  }
+
+  std::shared_ptr<ManualExecutor> westExecutor;
+  std::shared_ptr<ManualExecutor> eastExecutor;
+  std::shared_ptr<ManualWaiter> waiter;
+  InlineExecutor inlineExecutor;
+  bool done;
+  std::thread t;
+};
+
+TEST(Via, exception_on_launch) {
+  auto future = makeFuture<int>(std::runtime_error("E"));
+  EXPECT_THROW(future.value(), std::runtime_error);
+}
+
+TEST(Via, then_value) {
+  auto future = makeFuture(std::move(1))
+    .then([](Try<int>&& t) {
+      return t.value() == 1;
+    })
+    ;
+
+  EXPECT_TRUE(future.value());
+}
+
+TEST(Via, then_future) {
+  auto future = makeFuture(1)
+    .then([](Try<int>&& t) {
+      return makeFuture(t.value() == 1);
+    })
+    ;
+  EXPECT_TRUE(future.value());
+}
+
+static Future<std::string> doWorkStatic(Try<std::string>&& t) {
+  return makeFuture(t.value() + ";static");
+}
+
+TEST(Via, then_function) {
+  struct Worker {
+    Future<std::string> doWork(Try<std::string>&& t) {
+      return makeFuture(t.value() + ";class");
+    }
+    static Future<std::string> doWorkStatic(Try<std::string>&& t) {
+      return makeFuture(t.value() + ";class-static");
+    }
+  } w;
+
+  auto f = makeFuture(std::string("start"))
+    .then(doWorkStatic)
+    .then(Worker::doWorkStatic)
+    .then(&w, &Worker::doWork)
+    ;
+
+  EXPECT_EQ(f.value(), "start;static;class-static;class");
+}
+
+TEST_F(ViaFixture, deactivateChain) {
+  bool flag = false;
+  auto f = makeFuture().deactivate();
+  EXPECT_FALSE(f.isActive());
+  auto f2 = f.then([&](Try<void>){ flag = true; });
+  EXPECT_FALSE(flag);
+}
+
+TEST_F(ViaFixture, deactivateActivateChain) {
+  bool flag = false;
+  // you can do this all day long with temporaries.
+  auto f1 = makeFuture().deactivate().activate().deactivate();
+  // Chaining on activate/deactivate requires an rvalue, so you have to move
+  // one of these two ways (if you're not using a temporary).
+  auto f2 = std::move(f1).activate();
+  f2.deactivate();
+  auto f3 = std::move(f2.activate());
+  f3.then([&](Try<void>){ flag = true; });
+  EXPECT_TRUE(flag);
+}
+
+TEST_F(ViaFixture, thread_hops) {
+  auto westThreadId = std::this_thread::get_id();
+  auto f = via(eastExecutor.get()).then([=](Try<void>&& t) {
+    EXPECT_NE(std::this_thread::get_id(), westThreadId);
+    return makeFuture<int>(1);
+  }).via(westExecutor.get()
+  ).then([=](Try<int>&& t) {
+    EXPECT_EQ(std::this_thread::get_id(), westThreadId);
+    return t.value();
+  });
+  while (!f.isReady()) {
+    waiter->makeProgress();
+  }
+  EXPECT_EQ(f.value(), 1);
+}
+
+TEST_F(ViaFixture, chain_vias) {
+  auto westThreadId = std::this_thread::get_id();
+  auto f = via(eastExecutor.get()).then([=](Try<void>&& t) {
+    EXPECT_NE(std::this_thread::get_id(), westThreadId);
+    return makeFuture<int>(1);
+  }).then([=](Try<int>&& t) {
+    int val = t.value();
+    return makeFuture(std::move(val)).via(westExecutor.get())
+      .then([=](Try<int>&& t) mutable {
+        EXPECT_EQ(std::this_thread::get_id(), westThreadId);
+        return t.value();
+      });
+  }).then([=](Try<int>&& t) {
+    EXPECT_EQ(std::this_thread::get_id(), westThreadId);
+    return t.value();
+  });
+
+  while (!f.isReady()) {
+    waiter->makeProgress();
+  }
+  EXPECT_EQ(f.value(), 1);
+}
+
+TEST_F(ViaFixture, bareViaAssignment) {
+  auto f = via(eastExecutor.get());
+}
+TEST_F(ViaFixture, viaAssignment) {
+  // via()&&
+  auto f = makeFuture().via(eastExecutor.get());
+  // via()&
+  auto f2 = f.via(eastExecutor.get());
+}
diff --git a/folly/futures/test/main.cpp b/folly/futures/test/main.cpp
new file mode 100644 (file)
index 0000000..7dbf27d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/folly/futures/test/thens.rb b/folly/futures/test/thens.rb
new file mode 100755 (executable)
index 0000000..7b2fa69
--- /dev/null
@@ -0,0 +1,79 @@
+#!/usr/bin/env ruby
+
+# ruby thens.rb > Thens.cpp
+
+# An exercise in combinatorics.
+# (ordinary/static function, member function, std::function, lambda)
+# X
+# returns (Future<R>, R)
+# X
+# accepts (Try<T>&&, Try<T> const&, Try<T>, T&&, T const&, T, nothing)
+
+def test(*args)
+  args = args.join(", ")
+  [
+  "{Future<B> f = someFuture<A>().then(#{args});}",
+  #"{Future<B> f = makeFuture(A()).then(#{args}, anExecutor);}",
+  ]
+end
+
+def retval(ret)
+  {
+    "Future<B>" => "someFuture<B>()",
+    "Try<B>" => "Try<B>(B())",
+    "B" => "B()"
+  }[ret]
+end
+
+return_types = [
+  "Future<B>",
+  "B",
+  #"Try<B>",
+]
+param_types = [
+    "Try<A>&&",
+    #"Try<A> const&",
+    #"Try<A>",
+    #"Try<A>&",
+    "A&&",
+    #"A const&",
+    #"A",
+    #"A&",
+    #"",
+  ]
+
+tests = (
+  return_types.map { |ret|
+    param_types.map { |param|
+      both = "#{ret}, #{param}"
+      [
+        ["&aFunction<#{both}>"],
+        ["&SomeClass::aStaticMethod<#{both}>"],
+        # TODO switch these around (std::bind-style)
+        ["&anObject", "&SomeClass::aMethod<#{both}>"],
+        ["aStdFunction<#{both}>()"],
+        ["[&](#{param}){return #{retval(ret)};}"],
+      ]
+    }
+  }.flatten(2) + [
+    #[""],
+  ]
+).map {|a| test(a)}.flatten
+
+print <<EOF
+// This file is #{"@"}generated by thens.rb. Do not edit directly.
+
+// TODO: fails to compile with clang:dev.  See task #4412111
+#ifndef __clang__
+
+#include <folly/futures/test/Thens.h>
+
+TEST(Future, thenVariants) {
+  SomeClass anObject;
+  folly::Executor* anExecutor;
+
+  #{tests.join("\n  ")}
+}
+
+#endif
+EOF
index 8e134a3f160fdfafc677deb5bd9d1c1e25f91180..92829436edfdbb7ffa8c31e7e8202f8dbed63de2 100644 (file)
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <folly/wangle/futures/Future.h>
+#include <folly/futures/Future.h>
 #include <folly/wangle/channel/ChannelPipeline.h>
 #include <folly/io/IOBuf.h>
 #include <folly/io/IOBufQueue.h>
index 59ea3ae446d1afe2b8fbc8691a40cd1d983837d8..00982f4a9e31e3d540752155e8e1732d0d7fc664 100644 (file)
@@ -17,7 +17,7 @@
 #pragma once
 
 #include <folly/io/async/AsyncTransport.h>
-#include <folly/wangle/futures/Future.h>
+#include <folly/futures/Future.h>
 #include <folly/ExceptionWrapper.h>
 
 namespace folly { namespace wangle {
index 6536efacd41149b63fce13b473c47c2fccc8bccb..1a1a0a3128c96ad33ffb7c1a1e9ff6827c9b8a6d 100644 (file)
@@ -17,7 +17,7 @@
 #pragma once
 
 #include <folly/wangle/channel/ChannelHandlerContext.h>
-#include <folly/wangle/futures/Future.h>
+#include <folly/futures/Future.h>
 #include <folly/io/async/AsyncTransport.h>
 #include <folly/io/async/DelayedDestruction.h>
 #include <folly/ExceptionWrapper.h>
index 8aeedff83844fe791deff7fb6b0eee71cf6245be..a3e18c5adf2711f5e1dfa2d023c2aeee8834bcfc 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #pragma once
-#include <folly/wangle/futures/Future.h>
+#include <folly/futures/Future.h>
 
 namespace folly { namespace wangle {
 
diff --git a/folly/wangle/futures/Deprecated.h b/folly/wangle/futures/Deprecated.h
deleted file mode 100644 (file)
index 75937b1..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-#define DEPRECATED __attribute__((__deprecated__))
diff --git a/folly/wangle/futures/Future-inl.h b/folly/wangle/futures/Future-inl.h
deleted file mode 100644 (file)
index 61c386a..0000000
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <chrono>
-#include <thread>
-
-#include <folly/Baton.h>
-#include <folly/wangle/futures/detail/Core.h>
-#include <folly/wangle/futures/Timekeeper.h>
-
-namespace folly { namespace wangle {
-
-class Timekeeper;
-
-namespace detail {
-  Timekeeper* getTimekeeperSingleton();
-}
-
-template <typename T>
-struct isFuture {
-  static const bool value = false;
-};
-
-template <typename T>
-struct isFuture<Future<T> > {
-  static const bool value = true;
-};
-
-template <class T>
-Future<T>::Future(Future<T>&& other) noexcept : core_(nullptr) {
-  *this = std::move(other);
-}
-
-template <class T>
-Future<T>& Future<T>::operator=(Future<T>&& other) {
-  std::swap(core_, other.core_);
-  return *this;
-}
-
-template <class T>
-Future<T>::~Future() {
-  detach();
-}
-
-template <class T>
-void Future<T>::detach() {
-  if (core_) {
-    core_->detachFuture();
-    core_ = nullptr;
-  }
-}
-
-template <class T>
-void Future<T>::throwIfInvalid() const {
-  if (!core_)
-    throw NoState();
-}
-
-template <class T>
-template <class F>
-void Future<T>::setCallback_(F&& func) {
-  throwIfInvalid();
-  core_->setCallback(std::move(func));
-}
-
-// Variant: f.then([](Try<T>&& t){ return t.value(); });
-template <class T>
-template <class F>
-typename std::enable_if<
-  !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
-  Future<typename std::result_of<F(Try<T>&&)>::type> >::type
-Future<T>::then(F&& func) {
-  typedef typename std::result_of<F(Try<T>&&)>::type B;
-
-  throwIfInvalid();
-
-  // wrap these so we can move them into the lambda
-  folly::MoveWrapper<Promise<B>> p;
-  folly::MoveWrapper<F> funcm(std::forward<F>(func));
-
-  // grab the Future now before we lose our handle on the Promise
-  auto f = p->getFuture();
-
-  /* This is a bit tricky.
-
-     We can't just close over *this in case this Future gets moved. So we
-     make a new dummy Future. We could figure out something more
-     sophisticated that avoids making a new Future object when it can, as an
-     optimization. But this is correct.
-
-     core_ can't be moved, it is explicitly disallowed (as is copying). But
-     if there's ever a reason to allow it, this is one place that makes that
-     assumption and would need to be fixed. We use a standard shared pointer
-     for core_ (by copying it in), which means in essence obj holds a shared
-     pointer to itself.  But this shouldn't leak because Promise will not
-     outlive the continuation, because Promise will setException() with a
-     broken Promise if it is destructed before completed. We could use a
-     weak pointer but it would have to be converted to a shared pointer when
-     func is executed (because the Future returned by func may possibly
-     persist beyond the callback, if it gets moved), and so it is an
-     optimization to just make it shared from the get-go.
-
-     We have to move in the Promise and func using the MoveWrapper
-     hack. (func could be copied but it's a big drag on perf).
-
-     Two subtle but important points about this design. detail::Core has no
-     back pointers to Future or Promise, so if Future or Promise get moved
-     (and they will be moved in performant code) we don't have to do
-     anything fancy. And because we store the continuation in the
-     detail::Core, not in the Future, we can execute the continuation even
-     after the Future has gone out of scope. This is an intentional design
-     decision. It is likely we will want to be able to cancel a continuation
-     in some circumstances, but I think it should be explicit not implicit
-     in the destruction of the Future used to create it.
-     */
-  setCallback_(
-    [p, funcm](Try<T>&& t) mutable {
-      p->fulfil([&]() {
-        return (*funcm)(std::move(t));
-      });
-    });
-
-  return f;
-}
-
-// Variant: f.then([](T&& t){ return t; });
-template <class T>
-template <class F>
-typename std::enable_if<
-  !std::is_same<T, void>::value &&
-  !isFuture<typename std::result_of<
-    F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
-  Future<typename std::result_of<
-    F(typename detail::AliasIfVoid<T>::type&&)>::type> >::type
-Future<T>::then(F&& func) {
-  typedef typename std::result_of<F(T&&)>::type B;
-
-  throwIfInvalid();
-
-  folly::MoveWrapper<Promise<B>> p;
-  folly::MoveWrapper<F> funcm(std::forward<F>(func));
-  auto f = p->getFuture();
-
-  setCallback_(
-    [p, funcm](Try<T>&& t) mutable {
-      if (t.hasException()) {
-        p->setException(std::move(t.exception()));
-      } else {
-        p->fulfil([&]() {
-          return (*funcm)(std::move(t.value()));
-        });
-      }
-    });
-
-  return f;
-}
-
-// Variant: f.then([](){ return; });
-template <class T>
-template <class F>
-typename std::enable_if<
-  std::is_same<T, void>::value &&
-  !isFuture<typename std::result_of<F()>::type>::value,
-  Future<typename std::result_of<F()>::type> >::type
-Future<T>::then(F&& func) {
-  typedef typename std::result_of<F()>::type B;
-
-  throwIfInvalid();
-
-  folly::MoveWrapper<Promise<B>> p;
-  folly::MoveWrapper<F> funcm(std::forward<F>(func));
-  auto f = p->getFuture();
-
-  setCallback_(
-    [p, funcm](Try<T>&& t) mutable {
-      if (t.hasException()) {
-        p->setException(std::move(t.exception()));
-      } else {
-        p->fulfil([&]() {
-          return (*funcm)();
-        });
-      }
-    });
-
-  return f;
-}
-
-// Variant: f.then([](Try<T>&& t){ return makeFuture<T>(t.value()); });
-template <class T>
-template <class F>
-typename std::enable_if<
-  isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
-  Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
-Future<T>::then(F&& func) {
-  typedef typename std::result_of<F(Try<T>&&)>::type::value_type B;
-
-  throwIfInvalid();
-
-  // wrap these so we can move them into the lambda
-  folly::MoveWrapper<Promise<B>> p;
-  folly::MoveWrapper<F> funcm(std::forward<F>(func));
-
-  // grab the Future now before we lose our handle on the Promise
-  auto f = p->getFuture();
-
-  setCallback_(
-    [p, funcm](Try<T>&& t) mutable {
-      try {
-        auto f2 = (*funcm)(std::move(t));
-        // that didn't throw, now we can steal p
-        f2.setCallback_([p](Try<B>&& b) mutable {
-          p->fulfilTry(std::move(b));
-        });
-      } catch (const std::exception& e) {
-        p->setException(exception_wrapper(std::current_exception(), e));
-      } catch (...) {
-        p->setException(exception_wrapper(std::current_exception()));
-      }
-    });
-
-  return f;
-}
-
-// Variant: f.then([](T&& t){ return makeFuture<T>(t); });
-template <class T>
-template <class F>
-typename std::enable_if<
-  !std::is_same<T, void>::value &&
-  isFuture<typename std::result_of<
-    F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
-  Future<typename std::result_of<
-    F(typename detail::AliasIfVoid<T>::type&&)>::type::value_type> >::type
-Future<T>::then(F&& func) {
-  typedef typename std::result_of<F(T&&)>::type::value_type B;
-
-  throwIfInvalid();
-
-  folly::MoveWrapper<Promise<B>> p;
-  folly::MoveWrapper<F> funcm(std::forward<F>(func));
-  auto f = p->getFuture();
-
-  setCallback_(
-    [p, funcm](Try<T>&& t) mutable {
-      if (t.hasException()) {
-        p->setException(std::move(t.exception()));
-      } else {
-        try {
-          auto f2 = (*funcm)(std::move(t.value()));
-          f2.setCallback_([p](Try<B>&& b) mutable {
-            p->fulfilTry(std::move(b));
-          });
-        } catch (const std::exception& e) {
-          p->setException(exception_wrapper(std::current_exception(), e));
-        } catch (...) {
-          p->setException(exception_wrapper(std::current_exception()));
-        }
-      }
-    });
-
-  return f;
-}
-
-// Variant: f.then([](){ return makeFuture(); });
-template <class T>
-template <class F>
-typename std::enable_if<
-  std::is_same<T, void>::value &&
-  isFuture<typename std::result_of<F()>::type>::value,
-  Future<typename std::result_of<F()>::type::value_type> >::type
-Future<T>::then(F&& func) {
-  typedef typename std::result_of<F()>::type::value_type B;
-
-  throwIfInvalid();
-
-  folly::MoveWrapper<Promise<B>> p;
-  folly::MoveWrapper<F> funcm(std::forward<F>(func));
-
-  auto f = p->getFuture();
-
-  setCallback_(
-    [p, funcm](Try<T>&& t) mutable {
-      if (t.hasException()) {
-        p->setException(t.exception());
-      } else {
-        try {
-          auto f2 = (*funcm)();
-          f2.setCallback_([p](Try<B>&& b) mutable {
-            p->fulfilTry(std::move(b));
-          });
-        } catch (const std::exception& e) {
-          p->setException(exception_wrapper(std::current_exception(), e));
-        } catch (...) {
-          p->setException(exception_wrapper(std::current_exception()));
-        }
-      }
-    });
-
-  return f;
-}
-
-template <class T>
-Future<void> Future<T>::then() {
-  return then([] (Try<T>&& t) {});
-}
-
-// onError where the callback returns T
-template <class T>
-template <class F>
-typename std::enable_if<
-  !detail::Extract<F>::ReturnsFuture::value,
-  Future<T>>::type
-Future<T>::onError(F&& func) {
-  typedef typename detail::Extract<F>::FirstArg Exn;
-  static_assert(
-      std::is_same<typename detail::Extract<F>::RawReturn, T>::value,
-      "Return type of onError callback must be T or Future<T>");
-
-  Promise<T> p;
-  auto f = p.getFuture();
-  auto pm = folly::makeMoveWrapper(std::move(p));
-  auto funcm = folly::makeMoveWrapper(std::move(func));
-  setCallback_([pm, funcm](Try<T>&& t) mutable {
-    if (!t.template withException<Exn>([&] (Exn& e) {
-          pm->fulfil([&]{
-            return (*funcm)(e);
-          });
-        })) {
-      pm->fulfilTry(std::move(t));
-    }
-  });
-
-  return f;
-}
-
-// onError where the callback returns Future<T>
-template <class T>
-template <class F>
-typename std::enable_if<
-  detail::Extract<F>::ReturnsFuture::value,
-  Future<T>>::type
-Future<T>::onError(F&& func) {
-  static_assert(
-      std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
-      "Return type of onError callback must be T or Future<T>");
-  typedef typename detail::Extract<F>::FirstArg Exn;
-
-  Promise<T> p;
-  auto f = p.getFuture();
-  auto pm = folly::makeMoveWrapper(std::move(p));
-  auto funcm = folly::makeMoveWrapper(std::move(func));
-  setCallback_([pm, funcm](Try<T>&& t) mutable {
-    if (!t.template withException<Exn>([&] (Exn& e) {
-          try {
-            auto f2 = (*funcm)(e);
-            f2.setCallback_([pm](Try<T>&& t2) mutable {
-              pm->fulfilTry(std::move(t2));
-            });
-          } catch (const std::exception& e2) {
-            pm->setException(exception_wrapper(std::current_exception(), e2));
-          } catch (...) {
-            pm->setException(exception_wrapper(std::current_exception()));
-          }
-        })) {
-      pm->fulfilTry(std::move(t));
-    }
-  });
-
-  return f;
-}
-
-template <class T>
-typename std::add_lvalue_reference<T>::type Future<T>::value() {
-  throwIfInvalid();
-
-  return core_->getTry().value();
-}
-
-template <class T>
-typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
-  throwIfInvalid();
-
-  return core_->getTry().value();
-}
-
-template <class T>
-Try<T>& Future<T>::getTry() {
-  throwIfInvalid();
-
-  return core_->getTry();
-}
-
-template <class T>
-template <typename Executor>
-inline Future<T> Future<T>::via(Executor* executor) && {
-  throwIfInvalid();
-
-  this->deactivate();
-  core_->setExecutor(executor);
-
-  return std::move(*this);
-}
-
-template <class T>
-template <typename Executor>
-inline Future<T> Future<T>::via(Executor* executor) & {
-  throwIfInvalid();
-
-  MoveWrapper<Promise<T>> p;
-  auto f = p->getFuture();
-  then([p](Try<T>&& t) mutable { p->fulfilTry(std::move(t)); });
-  return std::move(f).via(executor);
-}
-
-template <class T>
-bool Future<T>::isReady() const {
-  throwIfInvalid();
-  return core_->ready();
-}
-
-template <class T>
-void Future<T>::raise(exception_wrapper exception) {
-  core_->raise(std::move(exception));
-}
-
-// makeFuture
-
-template <class T>
-Future<typename std::decay<T>::type> makeFuture(T&& t) {
-  Promise<typename std::decay<T>::type> p;
-  p.setValue(std::forward<T>(t));
-  return p.getFuture();
-}
-
-inline // for multiple translation units
-Future<void> makeFuture() {
-  Promise<void> p;
-  p.setValue();
-  return p.getFuture();
-}
-
-template <class F>
-auto makeFutureTry(
-    F&& func,
-    typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
-    -> Future<decltype(func())> {
-  Promise<decltype(func())> p;
-  p.fulfil(
-    [&func]() {
-      return (func)();
-    });
-  return p.getFuture();
-}
-
-template <class F>
-auto makeFutureTry(F const& func) -> Future<decltype(func())> {
-  F copy = func;
-  return makeFutureTry(std::move(copy));
-}
-
-template <class T>
-Future<T> makeFuture(std::exception_ptr const& e) {
-  Promise<T> p;
-  p.setException(e);
-  return p.getFuture();
-}
-
-template <class T>
-Future<T> makeFuture(exception_wrapper ew) {
-  Promise<T> p;
-  p.setException(std::move(ew));
-  return p.getFuture();
-}
-
-template <class T, class E>
-typename std::enable_if<std::is_base_of<std::exception, E>::value,
-                        Future<T>>::type
-makeFuture(E const& e) {
-  Promise<T> p;
-  p.setException(make_exception_wrapper<E>(e));
-  return p.getFuture();
-}
-
-template <class T>
-Future<T> makeFuture(Try<T>&& t) {
-  if (t.hasException()) {
-    return makeFuture<T>(std::move(t.exception()));
-  } else {
-    return makeFuture<T>(std::move(t.value()));
-  }
-}
-
-template <>
-inline Future<void> makeFuture(Try<void>&& t) {
-  if (t.hasException()) {
-    return makeFuture<void>(std::move(t.exception()));
-  } else {
-    return makeFuture();
-  }
-}
-
-// via
-template <typename Executor>
-Future<void> via(Executor* executor) {
-  return makeFuture().via(executor);
-}
-
-// when (variadic)
-
-template <typename... Fs>
-typename detail::VariadicContext<
-  typename std::decay<Fs>::type::value_type...>::type
-whenAll(Fs&&... fs)
-{
-  auto ctx =
-    new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
-  ctx->total = sizeof...(fs);
-  auto f_saved = ctx->p.getFuture();
-  detail::whenAllVariadicHelper(ctx,
-    std::forward<typename std::decay<Fs>::type>(fs)...);
-  return f_saved;
-}
-
-// when (iterator)
-
-template <class InputIterator>
-Future<
-  std::vector<
-  Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
-whenAll(InputIterator first, InputIterator last)
-{
-  typedef
-    typename std::iterator_traits<InputIterator>::value_type::value_type T;
-
-  if (first >= last) {
-    return makeFuture(std::vector<Try<T>>());
-  }
-  size_t n = std::distance(first, last);
-
-  auto ctx = new detail::WhenAllContext<T>();
-
-  ctx->results.resize(n);
-
-  auto f_saved = ctx->p.getFuture();
-
-  for (size_t i = 0; first != last; ++first, ++i) {
-     assert(i < n);
-     auto& f = *first;
-     f.setCallback_([ctx, i, n](Try<T>&& t) {
-         ctx->results[i] = std::move(t);
-         if (++ctx->count == n) {
-           ctx->p.setValue(std::move(ctx->results));
-           delete ctx;
-         }
-       });
-  }
-
-  return f_saved;
-}
-
-template <class InputIterator>
-Future<
-  std::pair<size_t,
-            Try<
-              typename
-              std::iterator_traits<InputIterator>::value_type::value_type> > >
-whenAny(InputIterator first, InputIterator last) {
-  typedef
-    typename std::iterator_traits<InputIterator>::value_type::value_type T;
-
-  auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
-  auto f_saved = ctx->p.getFuture();
-
-  for (size_t i = 0; first != last; first++, i++) {
-    auto& f = *first;
-    f.setCallback_([i, ctx](Try<T>&& t) {
-      if (!ctx->done.exchange(true)) {
-        ctx->p.setValue(std::make_pair(i, std::move(t)));
-      }
-      ctx->decref();
-    });
-  }
-
-  return f_saved;
-}
-
-template <class InputIterator>
-Future<std::vector<std::pair<size_t, Try<typename
-  std::iterator_traits<InputIterator>::value_type::value_type>>>>
-whenN(InputIterator first, InputIterator last, size_t n) {
-  typedef typename
-    std::iterator_traits<InputIterator>::value_type::value_type T;
-  typedef std::vector<std::pair<size_t, Try<T>>> V;
-
-  struct ctx_t {
-    V v;
-    size_t completed;
-    Promise<V> p;
-  };
-  auto ctx = std::make_shared<ctx_t>();
-  ctx->completed = 0;
-
-  // for each completed Future, increase count and add to vector, until we
-  // have n completed futures at which point we fulfil our Promise with the
-  // vector
-  auto it = first;
-  size_t i = 0;
-  while (it != last) {
-    it->then([ctx, n, i](Try<T>&& t) {
-      auto& v = ctx->v;
-      auto c = ++ctx->completed;
-      if (c <= n) {
-        assert(ctx->v.size() < n);
-        v.push_back(std::make_pair(i, std::move(t)));
-        if (c == n) {
-          ctx->p.fulfilTry(Try<V>(std::move(v)));
-        }
-      }
-    });
-
-    it++;
-    i++;
-  }
-
-  if (i < n) {
-    ctx->p.setException(std::runtime_error("Not enough futures"));
-  }
-
-  return ctx->p.getFuture();
-}
-
-template <typename T>
-Future<T>
-waitWithSemaphore(Future<T>&& f) {
-  Baton<> baton;
-  auto done = f.then([&](Try<T> &&t) {
-    baton.post();
-    return std::move(t.value());
-  });
-  baton.wait();
-  while (!done.isReady()) {
-    // There's a race here between the return here and the actual finishing of
-    // the future. f is completed, but the setup may not have finished on done
-    // after the baton has posted.
-    std::this_thread::yield();
-  }
-  return done;
-}
-
-template<>
-inline Future<void> waitWithSemaphore<void>(Future<void>&& f) {
-  Baton<> baton;
-  auto done = f.then([&](Try<void> &&t) {
-    baton.post();
-    t.value();
-  });
-  baton.wait();
-  while (!done.isReady()) {
-    // There's a race here between the return here and the actual finishing of
-    // the future. f is completed, but the setup may not have finished on done
-    // after the baton has posted.
-    std::this_thread::yield();
-  }
-  return done;
-}
-
-template <typename T, class Dur>
-Future<T>
-waitWithSemaphore(Future<T>&& f, Dur timeout) {
-  auto baton = std::make_shared<Baton<>>();
-  auto done = f.then([baton](Try<T> &&t) {
-    baton->post();
-    return std::move(t.value());
-  });
-  baton->timed_wait(std::chrono::system_clock::now() + timeout);
-  return done;
-}
-
-template <class Dur>
-Future<void>
-waitWithSemaphore(Future<void>&& f, Dur timeout) {
-  auto baton = std::make_shared<Baton<>>();
-  auto done = f.then([baton](Try<void> &&t) {
-    baton->post();
-    t.value();
-  });
-  baton->timed_wait(std::chrono::system_clock::now() + timeout);
-  return done;
-}
-
-namespace {
-  template <class T>
-  void getWaitHelper(Future<T>* f) {
-    // If we already have a value do the cheap thing
-    if (f->isReady()) {
-      return;
-    }
-
-    folly::Baton<> baton;
-    f->then([&](Try<T> const&) {
-      baton.post();
-    });
-    baton.wait();
-  }
-
-  template <class T>
-  Future<T> getWaitTimeoutHelper(Future<T>* f, Duration dur) {
-    // TODO make and use variadic whenAny #5877971
-    Promise<T> p;
-    auto token = std::make_shared<std::atomic<bool>>();
-    folly::Baton<> baton;
-
-    folly::wangle::detail::getTimekeeperSingleton()->after(dur)
-      .then([&,token](Try<void> const& t) {
-        if (token->exchange(true) == false) {
-          try {
-            t.value();
-            p.setException(TimedOut());
-          } catch (std::exception const& e) {
-            p.setException(exception_wrapper(std::current_exception(), e));
-          } catch (...) {
-            p.setException(exception_wrapper(std::current_exception()));
-          }
-          baton.post();
-        }
-      });
-
-    f->then([&, token](Try<T>&& t) {
-      if (token->exchange(true) == false) {
-        p.fulfilTry(std::move(t));
-        baton.post();
-      }
-    });
-
-    baton.wait();
-    return p.getFuture();
-  }
-}
-
-template <class T>
-T Future<T>::get() {
-  getWaitHelper(this);
-
-  // Big assumption here: the then() call above, since it doesn't move out
-  // the value, leaves us with a value to return here. This would be a big
-  // no-no in user code, but I'm invoking internal developer privilege. This
-  // is slightly more efficient (save a move()) especially if there's an
-  // exception (save a throw).
-  return std::move(value());
-}
-
-template <>
-inline void Future<void>::get() {
-  getWaitHelper(this);
-  value();
-}
-
-template <class T>
-T Future<T>::get(Duration dur) {
-  return std::move(getWaitTimeoutHelper(this, dur).value());
-}
-
-template <>
-inline void Future<void>::get(Duration dur) {
-  getWaitTimeoutHelper(this, dur).value();
-}
-
-template <class T>
-Future<T> Future<T>::within(Duration dur, Timekeeper* tk) {
-  return within(dur, TimedOut(), tk);
-}
-
-template <class T>
-template <class E>
-Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
-
-  struct Context {
-    Context(E ex) : exception(std::move(ex)), promise(), token(false) {}
-    E exception;
-    Promise<T> promise;
-    std::atomic<bool> token;
-  };
-  auto ctx = std::make_shared<Context>(std::move(e));
-
-  if (!tk) {
-    tk = folly::wangle::detail::getTimekeeperSingleton();
-  }
-
-  tk->after(dur)
-    .then([ctx](Try<void> const& t) {
-      if (ctx->token.exchange(true) == false) {
-        try {
-          t.throwIfFailed();
-          ctx->promise.setException(std::move(ctx->exception));
-        } catch (std::exception const& e2) {
-          ctx->promise.setException(
-              exception_wrapper(std::current_exception(), e2));
-        } catch (...) {
-          ctx->promise.setException(
-              exception_wrapper(std::current_exception()));
-        }
-      }
-    });
-
-  this->then([ctx](Try<T>&& t) {
-    if (ctx->token.exchange(true) == false) {
-      ctx->promise.fulfilTry(std::move(t));
-    }
-  });
-
-  return ctx->promise.getFuture();
-}
-
-template <class T>
-Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) {
-  return whenAll(*this, futures::sleep(dur, tk))
-    .then([](Try<std::tuple<Try<T>, Try<void>>>&& tup) {
-      Try<T>& t = std::get<0>(tup.value());
-      return makeFuture<T>(std::move(t));
-    });
-}
-
-}}
-
-// I haven't included a Future<T&> specialization because I don't forsee us
-// using it, however it is not difficult to add when needed. Refer to
-// Future<void> for guidance. std::future and boost::future code would also be
-// instructive.
diff --git a/folly/wangle/futures/Future.cpp b/folly/wangle/futures/Future.cpp
deleted file mode 100644 (file)
index 41bff82..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <folly/wangle/futures/Future.h>
-#include <folly/wangle/futures/detail/ThreadWheelTimekeeper.h>
-#include <folly/Likely.h>
-
-namespace folly { namespace wangle { namespace futures {
-
-Future<void> sleep(Duration dur, Timekeeper* tk) {
-  if (LIKELY(!tk)) {
-    tk = detail::getTimekeeperSingleton();
-  }
-  return tk->after(dur);
-}
-
-}}}
diff --git a/folly/wangle/futures/Future.h b/folly/wangle/futures/Future.h
deleted file mode 100644 (file)
index f94a6b7..0000000
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <algorithm>
-#include <exception>
-#include <functional>
-#include <memory>
-#include <type_traits>
-#include <vector>
-
-#include <folly/MoveWrapper.h>
-#include <folly/wangle/futures/Deprecated.h>
-#include <folly/wangle/futures/Promise.h>
-#include <folly/wangle/futures/Try.h>
-#include <folly/wangle/futures/WangleException.h>
-#include <folly/wangle/futures/detail/Types.h>
-
-namespace folly { namespace wangle {
-
-template <class> struct Promise;
-
-namespace detail {
-
-template <class> struct Core;
-template <class...> struct VariadicContext;
-
-template <class T>
-struct AliasIfVoid {
-  typedef typename std::conditional<
-    std::is_same<T, void>::value,
-    int,
-    T>::type type;
-};
-
-
-template <typename T>
-struct IsFuture : std::integral_constant<bool, false> {
-    typedef T Inner;
-};
-
-template <template <typename T> class Future, typename T>
-struct IsFuture<Future<T>> : std::integral_constant<bool, true> {
-    typedef T Inner;
-};
-
-template <typename...>
-struct ArgType;
-
-template <typename Arg, typename... Args>
-struct ArgType<Arg, Args...> {
-  typedef Arg FirstArg;
-};
-
-template <>
-struct ArgType<> {
-  typedef void FirstArg;
-};
-
-template <typename L>
-struct Extract : Extract<decltype(&L::operator())> { };
-
-template <typename Class, typename R, typename... Args>
-struct Extract<R(Class::*)(Args...) const> {
-  typedef IsFuture<R> ReturnsFuture;
-  typedef Future<typename ReturnsFuture::Inner> Return;
-  typedef typename ReturnsFuture::Inner RawReturn;
-  typedef typename ArgType<Args...>::FirstArg FirstArg;
-};
-
-template <typename Class, typename R, typename... Args>
-struct Extract<R(Class::*)(Args...)> {
-  typedef IsFuture<R> ReturnsFuture;
-  typedef Future<typename ReturnsFuture::Inner> Return;
-  typedef typename ReturnsFuture::Inner RawReturn;
-  typedef typename ArgType<Args...>::FirstArg FirstArg;
-};
-
-
-} // detail
-
-struct Timekeeper;
-
-template <typename T> struct isFuture;
-
-/// 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
-/// some cases). This is the least-bad naming scheme we could think of. Some
-/// of the functions herein have really-likely-to-collide names, like "map"
-/// and "sleep".
-namespace futures {
-  /// Returns a Future that will complete after the specified duration. The
-  /// Duration typedef of a `std::chrono` duration type indicates the
-  /// resolution you can expect to be meaningful (milliseconds at the time of
-  /// writing). Normally you wouldn't need to specify a Timekeeper, we will
-  /// use the global wangle timekeeper (we run a thread whose job it is to
-  /// keep time for wangle timeouts) but we provide the option for power
-  /// users.
-  ///
-  /// The Timekeeper thread will be lazily created the first time it is
-  /// needed. If your program never uses any timeouts or other time-based
-  /// Futures you will pay no Timekeeper thread overhead.
-  Future<void> sleep(Duration, Timekeeper* = nullptr);
-}
-
-template <class T>
-class Future {
- public:
-  typedef T value_type;
-
-  // not copyable
-  Future(Future const&) = delete;
-  Future& operator=(Future const&) = delete;
-
-  // movable
-  Future(Future&&) noexcept;
-  Future& operator=(Future&&);
-
-  ~Future();
-
-  /** Return the reference to result. Should not be called if !isReady().
-    Will rethrow the exception if an exception has been
-    captured.
-
-    This function is not thread safe - the returned Future can only
-    be executed from the thread that the executor runs it in.
-    See below for a thread safe version
-    */
-  typename std::add_lvalue_reference<T>::type
-  value();
-  typename std::add_lvalue_reference<const T>::type
-  value() const;
-
-  /// Returns an inactive Future which will call back on the other side of
-  /// executor (when it is activated).
-  ///
-  /// NB remember that Futures activate when they destruct. This is good,
-  /// it means that this will work:
-  ///
-  ///   f.via(e).then(a).then(b);
-  ///
-  /// a and b will execute in the same context (the far side of e), because
-  /// the Future (temporary variable) created by via(e) does not call back
-  /// until it destructs, which is after then(a) and then(b) have been wired
-  /// up.
-  ///
-  /// But this is still racy:
-  ///
-  ///   f = f.via(e).then(a);
-  ///   f.then(b);
-  // The ref-qualifier allows for `this` to be moved out so we
-  // don't get access-after-free situations in chaining.
-  // https://akrzemi1.wordpress.com/2014/06/02/ref-qualifiers/
-  template <typename Executor>
-  Future<T> via(Executor* executor) &&;
-
-  /// This variant creates a new future, where the ref-qualifier && version
-  /// moves `this` out. This one is less efficient but avoids confusing users
-  /// when "return f.via(x);" fails.
-  template <typename Executor>
-  Future<T> via(Executor* executor) &;
-
-  /** True when the result (or exception) is ready. */
-  bool isReady() const;
-
-  /** A reference to the Try of the value */
-  Try<T>& getTry();
-
-  /// Block until the future is fulfilled. Returns the value (moved out), or
-  /// throws the exception. The future must not already have a callback.
-  T get();
-
-  /// Block until the future is fulfilled, or until timed out. Returns the
-  /// value (moved out), or throws the exception (which might be a TimedOut
-  /// exception).
-  T get(Duration dur);
-
-  /** When this Future has completed, execute func which is a function that
-    takes a Try<T>&&. A Future for the return type of func is
-    returned. e.g.
-
-    Future<string> f2 = f1.then([](Try<T>&&) { return string("foo"); });
-
-    The Future given to the functor is ready, and the functor may call
-    value(), which may rethrow if this has captured an exception. If func
-    throws, the exception will be captured in the Future that is returned.
-    */
-  /* TODO n3428 and other async frameworks have something like then(scheduler,
-     Future), we might want to support a similar API which could be
-     implemented a little more efficiently than
-     f.via(executor).then(callback) */
-  template <class F>
-  typename std::enable_if<
-    !isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
-    Future<typename std::result_of<F(Try<T>&&)>::type> >::type
-  then(F&& func);
-
-  /// Variant where func takes a T directly, bypassing a try. Any exceptions
-  /// will be implicitly passed on to the resultant Future.
-  ///
-  ///   Future<int> f = makeFuture<int>(42).then([](int i) { return i+1; });
-  template <class F>
-  typename std::enable_if<
-    !std::is_same<T, void>::value &&
-    !isFuture<typename std::result_of<
-      F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
-    Future<typename std::result_of<
-      F(typename detail::AliasIfVoid<T>::type&&)>::type> >::type
-  then(F&& func);
-
-  /// Like the above variant, but for void futures. That is, func takes no
-  /// argument.
-  ///
-  ///   Future<int> f = makeFuture().then([] { return 42; });
-  template <class F>
-  typename std::enable_if<
-    std::is_same<T, void>::value &&
-    !isFuture<typename std::result_of<F()>::type>::value,
-    Future<typename std::result_of<F()>::type> >::type
-  then(F&& func);
-
-  /// Variant where func returns a Future<T> instead of a T. e.g.
-  ///
-  ///   Future<string> f2 = f1.then(
-  ///     [](Try<T>&&) { return makeFuture<string>("foo"); });
-  template <class F>
-  typename std::enable_if<
-    isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
-    Future<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
-  then(F&& func);
-
-  /// Variant where func returns a Future<T2> and takes a T directly, bypassing
-  /// a Try. Any exceptions will be implicitly passed on to the resultant
-  /// Future. For example,
-  ///
-  ///   Future<int> f = makeFuture<int>(42).then(
-  ///     [](int i) { return makeFuture<int>(i+1); });
-  template <class F>
-  typename std::enable_if<
-    !std::is_same<T, void>::value &&
-    isFuture<typename std::result_of<
-      F(typename detail::AliasIfVoid<T>::type&&)>::type>::value,
-    Future<typename std::result_of<
-      F(typename detail::AliasIfVoid<T>::type&&)>::type::value_type> >::type
-  then(F&& func);
-
-  /// Like the above variant, but for void futures. That is, func takes no
-  /// argument and returns a future.
-  ///
-  ///   Future<int> f = makeFuture().then(
-  ///     [] { return makeFuture<int>(42); });
-  template <class F>
-  typename std::enable_if<
-    std::is_same<T, void>::value &&
-    isFuture<typename std::result_of<F()>::type>::value,
-    Future<typename std::result_of<F()>::type::value_type> >::type
-  then(F&& func);
-
-  /// Variant where func is an ordinary function (static method, method)
-  ///
-  ///   R doWork(Try<T>&&);
-  ///
-  ///   Future<R> f2 = f1.then(doWork);
-  ///
-  /// or
-  ///
-  ///   struct Worker {
-  ///     static R doWork(Try<T>&&); }
-  ///
-  ///   Future<R> f2 = f1.then(&Worker::doWork);
-  template <class = T, class R = std::nullptr_t>
-  typename std::enable_if<!isFuture<R>::value, Future<R>>::type
-  inline then(R(*func)(Try<T>&&)) {
-    return then([func](Try<T>&& t) {
-      return (*func)(std::move(t));
-    });
-  }
-
-  /// Variant where func returns a Future<R> instead of a R. e.g.
-  ///
-  ///   struct Worker {
-  ///     Future<R> doWork(Try<T>&&); }
-  ///
-  ///   Future<R> f2 = f1.then(&Worker::doWork);
-  template <class = T, class R = std::nullptr_t>
-  typename std::enable_if<isFuture<R>::value, R>::type
-  inline then(R(*func)(Try<T>&&)) {
-    return then([func](Try<T>&& t) {
-      return (*func)(std::move(t));
-    });
-  }
-
-  /// Variant where func is an member function
-  ///
-  ///   struct Worker {
-  ///     R doWork(Try<T>&&); }
-  ///
-  ///   Worker *w;
-  ///   Future<R> f2 = f1.then(w, &Worker::doWork);
-  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
-  typename std::enable_if<!isFuture<R>::value, Future<R>>::type
-  inline then(Caller *instance, R(Caller::*func)(Try<T>&&)) {
-    return then([instance, func](Try<T>&& t) {
-      return (instance->*func)(std::move(t));
-    });
-  }
-
-  // Same as above, but func takes void instead of Try<void>&&
-  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
-  typename std::enable_if<
-      std::is_same<T, void>::value && !isFuture<R>::value, Future<R>>::type
-  inline then(Caller *instance, R(Caller::*func)()) {
-    return then([instance, func]() {
-      return (instance->*func)();
-    });
-  }
-
-  // Same as above, but func takes T&& instead of Try<T>&&
-  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
-  typename std::enable_if<
-      !std::is_same<T, void>::value && !isFuture<R>::value, Future<R>>::type
-  inline then(
-      Caller *instance,
-      R(Caller::*func)(typename detail::AliasIfVoid<T>::type&&)) {
-    return then([instance, func](T&& t) {
-      return (instance->*func)(std::move(t));
-    });
-  }
-
-  /// Variant where func returns a Future<R> instead of a R. e.g.
-  ///
-  ///   struct Worker {
-  ///     Future<R> doWork(Try<T>&&); }
-  ///
-  ///   Worker *w;
-  ///   Future<R> f2 = f1.then(w, &Worker::doWork);
-  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
-  typename std::enable_if<isFuture<R>::value, R>::type
-  inline then(Caller *instance, R(Caller::*func)(Try<T>&&)) {
-    return then([instance, func](Try<T>&& t) {
-      return (instance->*func)(std::move(t));
-    });
-  }
-
-  // Same as above, but func takes void instead of Try<void>&&
-  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
-  typename std::enable_if<
-      std::is_same<T, void>::value && isFuture<R>::value, R>::type
-  inline then(Caller *instance, R(Caller::*func)()) {
-    return then([instance, func]() {
-      return (instance->*func)();
-    });
-  }
-
-  // Same as above, but func takes T&& instead of Try<T>&&
-  template <class = T, class R = std::nullptr_t, class Caller = std::nullptr_t>
-  typename std::enable_if<
-      !std::is_same<T, void>::value && isFuture<R>::value, R>::type
-  inline then(
-      Caller *instance,
-      R(Caller::*func)(typename detail::AliasIfVoid<T>::type&&)) {
-    return then([instance, func](T&& t) {
-      return (instance->*func)(std::move(t));
-    });
-  }
-
-  /// Convenience method for ignoring the value and creating a Future<void>.
-  /// Exceptions still propagate.
-  Future<void> then();
-
-  /// Set an error callback for this Future. The callback should take a single
-  /// argument of the type that you want to catch, and should return a value of
-  /// the same type as this Future, or a Future of that type (see overload
-  /// below). For instance,
-  ///
-  /// makeFuture()
-  ///   .then([] {
-  ///     throw std::runtime_error("oh no!");
-  ///     return 42;
-  ///   })
-  ///   .onError([] (std::runtime_error& e) {
-  ///     LOG(INFO) << "std::runtime_error: " << e.what();
-  ///     return -1; // or makeFuture<int>(-1)
-  ///   });
-  template <class F>
-  typename std::enable_if<
-    !detail::Extract<F>::ReturnsFuture::value,
-    Future<T>>::type
-  onError(F&& func);
-
-  /// Overload of onError where the error callback returns a Future<T>
-  template <class F>
-  typename std::enable_if<
-    detail::Extract<F>::ReturnsFuture::value,
-    Future<T>>::type
-  onError(F&& func);
-
-  /// This is not the method you're looking for.
-  ///
-  /// This needs to be public because it's used by make* and when*, and it's
-  /// not worth listing all those and their fancy template signatures as
-  /// friends. But it's not for public consumption.
-  template <class F>
-  void setCallback_(F&& func);
-
-  /// A Future's callback is executed when all three of these conditions have
-  /// become true: it has a value (set by the Promise), it has a callback (set
-  /// by then), and it is active (active by default).
-  ///
-  /// Inactive Futures will activate upon destruction.
-  Future<T>& activate() & {
-    core_->activate();
-    return *this;
-  }
-  Future<T>& deactivate() & {
-    core_->deactivate();
-    return *this;
-  }
-  Future<T> activate() && {
-    core_->activate();
-    return std::move(*this);
-  }
-  Future<T> deactivate() && {
-    core_->deactivate();
-    return std::move(*this);
-  }
-
-  bool isActive() {
-    return core_->isActive();
-  }
-
-  template <class E>
-  void raise(E&& exception) {
-    raise(make_exception_wrapper<typename std::remove_reference<E>::type>(
-        std::move(exception)));
-  }
-
-  /// Raise an interrupt. If the promise holder has an interrupt
-  /// handler it will be called and potentially stop asynchronous work from
-  /// being done. This is advisory only - a promise holder may not set an
-  /// interrupt handler, or may do anything including ignore. But, if you know
-  /// your future supports this the most likely result is stopping or
-  /// preventing the asynchronous operation (if in time), and the promise
-  /// holder setting an exception on the future. (That may happen
-  /// asynchronously, of course.)
-  void raise(exception_wrapper interrupt);
-
-  void cancel() {
-    raise(FutureCancellation());
-  }
-
-  /// Throw TimedOut if this Future does not complete within the given
-  /// duration from now. The optional Timeekeeper is as with futures::sleep().
-  Future<T> within(Duration, Timekeeper* = nullptr);
-
-  /// Throw the given exception if this Future does not complete within the
-  /// given duration from now. The optional Timeekeeper is as with
-  /// futures::sleep().
-  template <class E>
-  Future<T> within(Duration, E exception, Timekeeper* = nullptr);
-
-  /// Delay the completion of this Future for at least this duration from
-  /// now. The optional Timekeeper is as with futures::sleep().
-  Future<T> delayed(Duration, Timekeeper* = nullptr);
-
- private:
-  typedef detail::Core<T>* corePtr;
-
-  // shared core state object
-  corePtr core_;
-
-  explicit
-  Future(corePtr obj) : core_(obj) {}
-
-  void detach();
-
-  void throwIfInvalid() const;
-
-  friend class Promise<T>;
-};
-
-/**
-  Make a completed Future by moving in a value. e.g.
-
-    string foo = "foo";
-    auto f = makeFuture(std::move(foo));
-
-  or
-
-    auto f = makeFuture<string>("foo");
-*/
-template <class T>
-Future<typename std::decay<T>::type> makeFuture(T&& t);
-
-/** Make a completed void Future. */
-Future<void> makeFuture();
-
-/** Make a completed Future by executing a function. If the function throws
-  we capture the exception, otherwise we capture the result. */
-template <class F>
-auto makeFutureTry(
-  F&& func,
-  typename std::enable_if<
-    !std::is_reference<F>::value, bool>::type sdf = false)
-  -> Future<decltype(func())>;
-
-template <class F>
-auto makeFutureTry(
-  F const& func)
-  -> Future<decltype(func())>;
-
-/// Make a failed Future from an exception_ptr.
-/// Because the Future's type cannot be inferred you have to specify it, e.g.
-///
-///   auto f = makeFuture<string>(std::current_exception());
-template <class T>
-Future<T> makeFuture(std::exception_ptr const& e) DEPRECATED;
-
-/// Make a failed Future from an exception_wrapper.
-template <class T>
-Future<T> makeFuture(exception_wrapper ew);
-
-/** Make a Future from an exception type E that can be passed to
-  std::make_exception_ptr(). */
-template <class T, class E>
-typename std::enable_if<std::is_base_of<std::exception, E>::value,
-                        Future<T>>::type
-makeFuture(E const& e);
-
-/** Make a Future out of a Try */
-template <class T>
-Future<T> makeFuture(Try<T>&& t);
-
-/*
- * Return a new Future that will call back on the given Executor.
- * This is just syntactic sugar for makeFuture().via(executor)
- *
- * @param executor the Executor to call back on
- *
- * @returns a void Future that will call back on the given executor
- */
-template <typename Executor>
-Future<void> via(Executor* executor);
-
-/** When all the input Futures complete, the returned Future will complete.
-  Errors do not cause early termination; this Future will always succeed
-  after all its Futures have finished (whether successfully or with an
-  error).
-
-  The Futures are moved in, so your copies are invalid. If you need to
-  chain further from these Futures, use the variant with an output iterator.
-
-  XXX is this still true?
-  This function is thread-safe for Futures running on different threads.
-
-  The return type for Future<T> input is a Future<std::vector<Try<T>>>
-  */
-template <class InputIterator>
-Future<std::vector<Try<
-  typename std::iterator_traits<InputIterator>::value_type::value_type>>>
-whenAll(InputIterator first, InputIterator last);
-
-/// This version takes a varying number of Futures instead of an iterator.
-/// The return type for (Future<T1>, Future<T2>, ...) input
-/// is a Future<std::tuple<Try<T1>, Try<T2>, ...>>.
-/// The Futures are moved in, so your copies are invalid.
-template <typename... Fs>
-typename detail::VariadicContext<
-  typename std::decay<Fs>::type::value_type...>::type
-whenAll(Fs&&... fs);
-
-/** The result is a pair of the index of the first Future to complete and
-  the Try. If multiple Futures complete at the same time (or are already
-  complete when passed in), the "winner" is chosen non-deterministically.
-
-  This function is thread-safe for Futures running on different threads.
-  */
-template <class InputIterator>
-Future<std::pair<
-  size_t,
-  Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
-whenAny(InputIterator first, InputIterator last);
-
-/** when n Futures have completed, the Future completes with a vector of
-  the index and Try of those n Futures (the indices refer to the original
-  order, but the result vector will be in an arbitrary order)
-
-  Not thread safe.
-  */
-template <class InputIterator>
-Future<std::vector<std::pair<
-  size_t,
-  Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>>
-whenN(InputIterator first, InputIterator last, size_t n);
-
-/** Wait for the given future to complete on a semaphore. Returns a completed
- * future containing the result.
- *
- * NB if the promise for the future would be fulfilled in the same thread that
- * you call this, it will deadlock.
- */
-template <class T>
-Future<T> waitWithSemaphore(Future<T>&& f);
-
-/** Wait for up to `timeout` for the given future to complete. Returns a future
- * which may or may not be completed depending whether the given future
- * completed in time
- *
- * Note: each call to this starts a (short-lived) thread and allocates memory.
- */
-template <typename T, class Dur>
-Future<T> waitWithSemaphore(Future<T>&& f, Dur timeout);
-
-}} // folly::wangle
-
-#include <folly/wangle/futures/Future-inl.h>
diff --git a/folly/wangle/futures/InlineExecutor.cpp b/folly/wangle/futures/InlineExecutor.cpp
deleted file mode 100644 (file)
index 1ef2f06..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
diff --git a/folly/wangle/futures/InlineExecutor.h b/folly/wangle/futures/InlineExecutor.h
deleted file mode 100644 (file)
index e692408..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-#include <folly/Executor.h>
-
-namespace folly { namespace wangle {
-
-  /// When work is "queued", execute it immediately inline.
-  /// Usually when you think you want this, you actually want a
-  /// QueuedImmediateExecutor.
-  class InlineExecutor : public Executor {
-   public:
-    void add(Func f) override {
-      f();
-    }
-  };
-
-}}
diff --git a/folly/wangle/futures/ManualExecutor.cpp b/folly/wangle/futures/ManualExecutor.cpp
deleted file mode 100644 (file)
index 9b68b1a..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <folly/wangle/futures/ManualExecutor.h>
-
-#include <string.h>
-#include <string>
-#include <tuple>
-
-#include <stdexcept>
-
-namespace folly { namespace wangle {
-
-ManualExecutor::ManualExecutor() {
-  if (sem_init(&sem_, 0, 0) == -1) {
-    throw std::runtime_error(std::string("sem_init: ") + strerror(errno));
-  }
-}
-
-void ManualExecutor::add(Func callback) {
-  std::lock_guard<std::mutex> lock(lock_);
-  funcs_.push(std::move(callback));
-  sem_post(&sem_);
-}
-
-size_t ManualExecutor::run() {
-  size_t count;
-  size_t n;
-  Func func;
-
-  {
-    std::lock_guard<std::mutex> lock(lock_);
-
-    while (!scheduledFuncs_.empty()) {
-      auto& sf = scheduledFuncs_.top();
-      if (sf.time > now_)
-        break;
-      funcs_.push(sf.func);
-      scheduledFuncs_.pop();
-    }
-
-    n = funcs_.size();
-  }
-
-  for (count = 0; count < n; count++) {
-    {
-      std::lock_guard<std::mutex> lock(lock_);
-      if (funcs_.empty()) {
-        break;
-      }
-
-      // Balance the semaphore so it doesn't grow without bound
-      // if nobody is calling wait().
-      // This may fail (with EAGAIN), that's fine.
-      sem_trywait(&sem_);
-
-      func = std::move(funcs_.front());
-      funcs_.pop();
-    }
-    func();
-  }
-
-  return count;
-}
-
-void ManualExecutor::wait() {
-  while (true) {
-    {
-      std::lock_guard<std::mutex> lock(lock_);
-      if (!funcs_.empty())
-        break;
-    }
-
-    auto ret = sem_wait(&sem_);
-    if (ret == 0) {
-      break;
-    }
-    if (errno != EINVAL) {
-      throw std::runtime_error(std::string("sem_wait: ") + strerror(errno));
-    }
-  }
-}
-
-void ManualExecutor::advanceTo(TimePoint const& t) {
-  if (t > now_) {
-    now_ = t;
-  }
-  run();
-}
-
-}} // namespace
diff --git a/folly/wangle/futures/ManualExecutor.h b/folly/wangle/futures/ManualExecutor.h
deleted file mode 100644 (file)
index 72a1c1d..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-#include <folly/wangle/futures/ScheduledExecutor.h>
-#include <semaphore.h>
-#include <memory>
-#include <mutex>
-#include <queue>
-#include <cstdio>
-
-namespace folly { namespace wangle {
-  /// A ManualExecutor only does work when you turn the crank, by calling
-  /// run() or indirectly with makeProgress() or waitFor().
-  ///
-  /// The clock for a manual executor starts at 0 and advances only when you
-  /// ask it to. i.e. time is also under manual control.
-  ///
-  /// NB No attempt has been made to make anything other than add and schedule
-  /// threadsafe.
-  class ManualExecutor : public ScheduledExecutor {
-   public:
-    ManualExecutor();
-
-    void add(Func) override;
-
-    /// Do work. Returns the number of functions that were executed (maybe 0).
-    /// Non-blocking, in the sense that we don't wait for work (we can't
-    /// control whether one of the functions blocks).
-    /// This is stable, it will not chase an ever-increasing tail of work.
-    /// This also means, there may be more work available to perform at the
-    /// moment that this returns.
-    size_t run();
-
-    /// Wait for work to do.
-    void wait();
-
-    /// Wait for work to do, and do it.
-    void makeProgress() {
-      wait();
-      run();
-    }
-
-    /// makeProgress until this Future is ready.
-    template <class F> void waitFor(F const& f) {
-      // TODO(5427828)
-#if 0
-      while (!f.isReady())
-        makeProgress();
-#else
-      while (!f.isReady()) {
-        run();
-      }
-#endif
-
-    }
-
-    virtual void scheduleAt(Func&& f, TimePoint const& t) override {
-      std::lock_guard<std::mutex> lock(lock_);
-      scheduledFuncs_.emplace(t, std::move(f));
-      sem_post(&sem_);
-    }
-
-    /// Advance the clock. The clock never advances on its own.
-    /// Advancing the clock causes some work to be done, if work is available
-    /// to do (perhaps newly available because of the advanced clock).
-    /// If dur is <= 0 this is a noop.
-    void advance(Duration const& dur) {
-      advanceTo(now_ + dur);
-    }
-
-    /// Advance the clock to this absolute time. If t is <= now(),
-    /// this is a noop.
-    void advanceTo(TimePoint const& t);
-
-    TimePoint now() override { return now_; }
-
-   private:
-    std::mutex lock_;
-    std::queue<Func> funcs_;
-    sem_t sem_;
-
-    // helper class to enable ordering of scheduled events in the priority
-    // queue
-    struct ScheduledFunc {
-      TimePoint time;
-      size_t ordinal;
-      Func func;
-
-      ScheduledFunc(TimePoint const& t, Func&& f)
-        : time(t), func(std::move(f))
-      {
-        static size_t seq = 0;
-        ordinal = seq++;
-      }
-
-      bool operator<(ScheduledFunc const& b) const {
-        if (time == b.time)
-          return ordinal < b.ordinal;
-        return time < b.time;
-      }
-    };
-    std::priority_queue<ScheduledFunc> scheduledFuncs_;
-    TimePoint now_ = now_.min();
-  };
-
-}}
diff --git a/folly/wangle/futures/OpaqueCallbackShunt.h b/folly/wangle/futures/OpaqueCallbackShunt.h
deleted file mode 100644 (file)
index 2e7dbd1..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <folly/wangle/futures/Promise.h>
-
-namespace folly { namespace wangle {
-
-/// These classes help you wrap an existing C style callback function
-/// into a Future.
-///
-///   void legacy_send_async(..., void (*cb)(void*), void*);
-///
-///   Future<T> wrappedSendAsync(T&& obj) {
-///     auto handle = new OpaqueCallbackShunt<T>(obj);
-///     auto future = handle->promise_.getFuture();
-///     legacy_send_async(..., OpaqueCallbackShunt<T>::callback, handle)
-///     return future;
-///   }
-///
-/// If the legacy function doesn't conform to void (*cb)(void*), use a lambda:
-///
-///   auto cb = [](t1*, t2*, void* arg) {
-///     OpaqueCallbackShunt<T>::callback(arg);
-///   };
-///   legacy_send_async(..., cb, handle);
-
-template <typename T>
-class OpaqueCallbackShunt {
-public:
-  explicit OpaqueCallbackShunt(T&& obj)
-    : obj_(std::move(obj)) { }
-  static void callback(void* arg) {
-    std::unique_ptr<OpaqueCallbackShunt<T>> handle(
-      static_cast<OpaqueCallbackShunt<T>*>(arg));
-    handle->promise_.setValue(std::move(handle->obj_));
-  }
-  folly::wangle::Promise<T> promise_;
-private:
-  T obj_;
-};
-
-}} // folly::wangle
diff --git a/folly/wangle/futures/Promise-inl.h b/folly/wangle/futures/Promise-inl.h
deleted file mode 100644 (file)
index 2ded443..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <atomic>
-#include <thread>
-
-#include <folly/wangle/futures/WangleException.h>
-#include <folly/wangle/futures/detail/Core.h>
-
-namespace folly { namespace wangle {
-
-template <class T>
-Promise<T>::Promise() : retrieved_(false), core_(new detail::Core<T>())
-{}
-
-template <class T>
-Promise<T>::Promise(Promise<T>&& other) : core_(nullptr) {
-  *this = std::move(other);
-}
-
-template <class T>
-Promise<T>& Promise<T>::operator=(Promise<T>&& other) {
-  std::swap(core_, other.core_);
-  std::swap(retrieved_, other.retrieved_);
-  return *this;
-}
-
-template <class T>
-void Promise<T>::throwIfFulfilled() {
-  if (!core_)
-    throw NoState();
-  if (core_->ready())
-    throw PromiseAlreadySatisfied();
-}
-
-template <class T>
-void Promise<T>::throwIfRetrieved() {
-  if (retrieved_)
-    throw FutureAlreadyRetrieved();
-}
-
-template <class T>
-Promise<T>::~Promise() {
-  detach();
-}
-
-template <class T>
-void Promise<T>::detach() {
-  if (core_) {
-    if (!retrieved_)
-      core_->detachFuture();
-    core_->detachPromise();
-    core_ = nullptr;
-  }
-}
-
-template <class T>
-Future<T> Promise<T>::getFuture() {
-  throwIfRetrieved();
-  retrieved_ = true;
-  return Future<T>(core_);
-}
-
-template <class T>
-template <class E>
-typename std::enable_if<std::is_base_of<std::exception, E>::value>::type
-Promise<T>::setException(E const& e) {
-  setException(make_exception_wrapper<E>(e));
-}
-
-template <class T>
-void Promise<T>::setException(std::exception_ptr const& ep) {
-  try {
-    std::rethrow_exception(ep);
-  } catch (const std::exception& e) {
-    setException(exception_wrapper(std::current_exception(), e));
-  } catch (...) {
-    setException(exception_wrapper(std::current_exception()));
-  }
-}
-
-template <class T>
-void Promise<T>::setException(exception_wrapper ew) {
-  throwIfFulfilled();
-  core_->setResult(Try<T>(std::move(ew)));
-}
-
-template <class T>
-void Promise<T>::setInterruptHandler(
-  std::function<void(exception_wrapper const&)> fn) {
-  core_->setInterruptHandler(std::move(fn));
-}
-
-template <class T>
-void Promise<T>::fulfilTry(Try<T>&& t) {
-  throwIfFulfilled();
-  core_->setResult(std::move(t));
-}
-
-template <class T>
-template <class M>
-void Promise<T>::setValue(M&& v) {
-  static_assert(!std::is_same<T, void>::value,
-                "Use setValue() instead");
-
-  fulfilTry(Try<T>(std::forward<M>(v)));
-}
-
-template <class T>
-void Promise<T>::setValue() {
-  static_assert(std::is_same<T, void>::value,
-                "Use setValue(value) instead");
-
-  fulfilTry(Try<void>());
-}
-
-template <class T>
-template <class F>
-void Promise<T>::fulfil(F&& func) {
-  throwIfFulfilled();
-  fulfilTry(makeTryFunction(std::forward<F>(func)));
-}
-
-}}
diff --git a/folly/wangle/futures/Promise.h b/folly/wangle/futures/Promise.h
deleted file mode 100644 (file)
index af324a9..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <folly/wangle/futures/Deprecated.h>
-#include <folly/wangle/futures/Try.h>
-#include <functional>
-
-namespace folly { namespace wangle {
-
-// forward declaration
-template <class T> class Future;
-
-template <class T>
-class Promise {
-public:
-  Promise();
-  ~Promise();
-
-  // not copyable
-  Promise(Promise const&) = delete;
-  Promise& operator=(Promise const&) = delete;
-
-  // movable
-  Promise(Promise<T>&&);
-  Promise& operator=(Promise<T>&&);
-
-  /** Return a Future tied to the shared core state. This can be called only
-    once, thereafter Future already retrieved exception will be raised. */
-  Future<T> getFuture();
-
-  /** Fulfil the Promise with an exception_wrapper */
-  void setException(exception_wrapper ew);
-
-  /** Fulfil the Promise with an exception_ptr, e.g.
-    try {
-      ...
-    } catch (...) {
-      p.setException(std::current_exception());
-    }
-    */
-  void setException(std::exception_ptr const&) DEPRECATED;
-
-  /** Fulfil the Promise with an exception type E, which can be passed to
-    std::make_exception_ptr(). Useful for originating exceptions. If you
-    caught an exception the exception_wrapper form is more appropriate.
-    */
-  template <class E>
-  typename std::enable_if<std::is_base_of<std::exception, E>::value>::type
-  setException(E const&);
-
-  /// Set an interrupt handler to handle interrupts. See the documentation for
-  /// Future::raise(). Your handler can do whatever it wants, but if you
-  /// bother to set one then you probably will want to fulfil the promise with
-  /// an exception (or special value) indicating how the interrupt was
-  /// handled.
-  void setInterruptHandler(std::function<void(exception_wrapper const&)>);
-
-  /** Fulfil this Promise (only for Promise<void>) */
-  void setValue();
-
-  /** Set the value (use perfect forwarding for both move and copy) */
-  template <class M>
-  void setValue(M&& value);
-
-  void fulfilTry(Try<T>&& t);
-
-  /** Fulfil this Promise with the result of a function that takes no
-    arguments and returns something implicitly convertible to T.
-    Captures exceptions. e.g.
-
-    p.fulfil([] { do something that may throw; return a T; });
-  */
-  template <class F>
-  void fulfil(F&& func);
-
-private:
-  typedef typename Future<T>::corePtr corePtr;
-
-  // Whether the Future has been retrieved (a one-time operation).
-  bool retrieved_;
-
-  // shared core state object
-  corePtr core_;
-
-  void throwIfFulfilled();
-  void throwIfRetrieved();
-  void detach();
-};
-
-}}
-
-#include <folly/wangle/futures/Future.h>
-#include <folly/wangle/futures/Promise-inl.h>
diff --git a/folly/wangle/futures/QueuedImmediateExecutor.cpp b/folly/wangle/futures/QueuedImmediateExecutor.cpp
deleted file mode 100644 (file)
index b82a486..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <folly/wangle/futures/QueuedImmediateExecutor.h>
-#include <folly/ThreadLocal.h>
-#include <queue>
-
-namespace folly { namespace wangle {
-
-void QueuedImmediateExecutor::add(Func callback) {
-  thread_local std::queue<Func> q;
-
-  if (q.empty()) {
-    q.push(std::move(callback));
-    while (!q.empty()) {
-      q.front()();
-      q.pop();
-    }
-  } else {
-    q.push(callback);
-  }
-}
-
-}} // namespace
diff --git a/folly/wangle/futures/QueuedImmediateExecutor.h b/folly/wangle/futures/QueuedImmediateExecutor.h
deleted file mode 100644 (file)
index a82c32d..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <folly/Executor.h>
-
-namespace folly { namespace wangle {
-
-/**
- * Runs inline like InlineExecutor, but with a queue so that any tasks added
- * to this executor by one of its own callbacks will be queued instead of
- * executed inline (nested). This is usually better behavior than Inline.
- */
-class QueuedImmediateExecutor : public Executor {
- public:
-  void add(Func) override;
-};
-
-}} // namespace
diff --git a/folly/wangle/futures/README.md b/folly/wangle/futures/README.md
deleted file mode 100644 (file)
index a23d7c6..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-# Wangle
-Wangle is a framework for expressing asynchronous code in C++ using the Future pattern.
-
-**wan•gle** |ˈwaNGgÉ™l| informal  
-*verb*  
-Obtain (something that is desired) by persuading others to comply or by manipulating events.
-
-*noun*  
-A framework for expressing asynchronous control flow in C++, that is composable and easily translated to/from synchronous code.
-
-*synonyms*  
-[Finagle](http://twitter.github.io/finagle/)
-
-Wangle is a futures-based async framework inspired by [Twitter's Finagle](http://twitter.github.io/finagle/) (which is in scala), and (loosely) building upon the existing (but anemic) Futures code found in the C++11 standard ([`std::future`](http://en.cppreference.com/w/cpp/thread/future)) and [`boost::future`](http://www.boost.org/doc/libs/1_53_0/boost/thread/future.hpp) (especially >= 1.53.0). Although inspired by the std::future interface, it is not syntactically drop-in compatible because some ideas didn't translate well enough and we decided to break from the API. But semantically, it should be straightforward to translate from existing std::future code to Wangle.
-
-The primary semantic differences are that Wangle Futures and Promises are not threadsafe; and as does `boost::future`, Wangle supports continuing callbacks (`then()`) and there are helper methods `whenAll()` and `whenAny()` which are important compositional building blocks.
-
-## Brief Synopsis
-
-```C++
-#include <folly/wangle/futures/Future.h>
-using namespace folly::wangle;
-using namespace std;
-
-void foo(int x) {
-  // do something with x
-  cout << "foo(" << x << ")" << endl;
-}
-
-// ...
-
-  cout << "making Promise" << endl;
-  Promise<int> p;
-  Future<int> f = p.getFuture();
-  f.then(
-    [](Try<int>&& t) {
-      foo(t.value());
-    });
-  cout << "Future chain made" << endl;
-
-// ... now perhaps in another event callback
-
-  cout << "fulfilling Promise" << endl;
-  p.setValue(42);
-  cout << "Promise fulfilled" << endl;
-```
-
-This would print:
-  
-```
-making Promise
-Future chain made
-fulfilling Promise
-foo(42)
-Promise fulfilled
-```
-
-## User Guide
-
-Let's begin with an example. Consider a simplified Memcache client class with this interface:
-
-```C++
-class MemcacheClient {
- public:
-  struct GetReply {
-    enum class Result {
-      FOUND,
-      NOT_FOUND,
-      SERVER_ERROR,
-    };
-
-    Result result;
-    // The value when result is FOUND,
-    // The error message when result is SERVER_ERROR or CLIENT_ERROR
-    // undefined otherwise
-    std::string value;
-  };
-
-  GetReply get(std::string key);
-};
-```
-
-This API is synchronous, i.e. when you call `get()` you have to wait for the result. This is very simple, but unfortunately it is also very easy to write very slow code using synchronous APIs.
-
-Now, consider this traditional asynchronous signature for `get()`:
-
-```C++
-int get(std::string key, std::function<void(GetReply)> callback);
-```
-
-When you call `get()`, your asynchronous operation begins and when it finishes your callback will be called with the result. (Unless something goes drastically wrong and you get an error code from `get()`.) Very performant code can be written with an API like this, but for nontrivial applications the code descends into a special kind of spaghetti code affectionately referred to as "callback hell".
-
-The Future-based API looks like this:
-
-```C++
-Future<GetReply> get(std::string key);
-```
-
-A `Future<GetReply>` is a placeholder for the `GetReply` that we will eventually get. A Future usually starts life out "unfulfilled", or incomplete, i.e.:
-
-```C++
-fut.isReady() == false
-fut.value()  // will throw an exception because the Future is not ready
-```
-
-At some point in the future, the Future will have been fulfilled, and we can access its value.
-
-```C++
-fut.isReady() == true
-GetReply& reply = fut.value();
-```
-
-Futures support exceptions. If something exceptional happened, your Future may represent an exception instead of a value. In that case:
-
-```C++
-fut.isReady() == true
-fut.value() // will rethrow the exception
-```
-
-Just what is exceptional depends on the API. In our example we have chosen not to raise exceptions for `SERVER_ERROR`, but represent this explicitly in the `GetReply` object. On the other hand, an astute Memcache veteran would notice that we left `CLIENT_ERROR` out of `GetReply::Result`, and perhaps a `CLIENT_ERROR` would have been raised as an exception, because `CLIENT_ERROR` means there's a bug in the library and this would be truly exceptional. These decisions are judgement calls by the API designer. The important thing is that exceptional conditions (including and especially spurious exceptions that nobody expects) get captured and can be handled higher up the "stack".
-
-So far we have described a way to initiate an asynchronous operation via an API that returns a Future, and then sometime later after it is fulfilled, we get its value. This is slightly more useful than a synchronous API, but it's not yet ideal. There are two more very important pieces to the puzzle.
-
-First, we can aggregate Futures, to define a new Future that completes after some or all of the aggregated Futures complete.  Consider two examples: fetching a batch of requests and waiting for all of them, and fetching a group of requests and waiting for only one of them.
-
-```C++
-vector<Future<GetReply>> futs;
-for (auto& key : keys) {
-  futs.push_back(mc.get(key));
-}
-auto all = whenAll(futs.begin(), futs.end());
-
-vector<Future<GetReply>> futs;
-for (auto& key : keys) {
-  futs.push_back(mc.get(key));
-}
-auto any = whenAny(futs.begin(), futs.end());
-```
-
-`all` and `any` are Futures (for the exact type and usage see the header files).  They will be complete when all/one of `futs` are complete, respectively. (There is also `whenN()` for when you need *some*.)
-
-Second, we can attach callbacks to a Future, and chain them together monadically. An example will clarify:
-
-```C++
-Future<GetReply> fut1 = mc.get("foo");
-
-Future<string> fut2 = fut1.then(
-  [](Try<GetReply>&& t) {
-    if (t.value().result == MemcacheClient::GetReply::Result::FOUND)
-      return t.value().value;
-    throw SomeException("No value");
-  });
-
-Future<void> fut3 = fut2.then(
-  [](Try<string>&& t) {
-    try {
-      cout << t.value() << endl;
-    } catch (std::exception const& e) {
-      cerr << e.what() << endl;
-    }
-  });
-```
-
-That example is a little contrived but the idea is that you can transform a result from one type to another, potentially in a chain, and unhandled errors propagate. Of course, the intermediate variables are optional. `Try<T>` is the object wrapper that supports both value and exception.
-
-Using `then` to add callbacks is idiomatic. It brings all the code into one place, which avoids callback hell.
-
-Up to this point we have skirted around the matter of waiting for Futures. You may never need to wait for a Future, because your code is event-driven and all follow-up action happens in a then-block. But if want to have a batch workflow, where you initiate a batch of asynchronous operations and then wait for them all to finish at a synchronization point, then you will want to wait for a Future.
-
-Other future frameworks like Finagle and std::future/boost::future, give you the ability to wait directly on a Future, by calling `fut.wait()` (naturally enough). Wangle has diverged from this pattern because we don't want to be in the business of dictating how your thread waits. We may work out something that we feel is sufficiently general, in the meantime adapt this spin loop to however your thread should wait:
-
-  while (!f.isReady()) {}
-
-(Hint: you might want to use an event loop or a semaphore or something. You probably don't want to just spin like this.)
-
-Wangle is partially threadsafe. A Promise or Future can migrate between threads as long as there's a full memory barrier of some sort. `Future::then` and `Promise::setValue` (and all variants that boil down to those two calls) can be called from different threads. BUT, be warned that you might be surprised about which thread your callback executes on. Let's consider an example.
-
-```C++
-// Thread A
-Promise<void> p;
-auto f = p.getFuture();
-
-// Thread B
-f.then(x).then(y).then(z);
-
-// Thread A
-p.setValue();
-```
-
-This is legal and technically threadsafe. However, it is important to realize that you do not know in which thread `x`, `y`, and/or `z` will execute. Maybe they will execute in Thread A when `p.setValue()` is called. Or, maybe they will execute in Thread B when `f.then` is called. Or, maybe `x` will execute in Thread B, but `y` and/or `z` will execute in Thread A. There's a race between `setValue` and `then`—whichever runs last will execute the callback. The only guarantee is that one of them will run the callback.
-
-Naturally, you will want some control over which thread executes callbacks. We have a few mechanisms to help.
-
-The first and most useful is `via`, which passes execution through an `Executor`, which usually has the effect of running the callback in a new thread.
-```C++
-aFuture
-  .then(x)
-  .via(e1).then(y1).then(y2)
-  .via(e2).then(z);
-```
-`x` will execute in the current thread. `y1` and `y2` will execute in the thread on the other side of `e1`, and `z` will execute in the thread on the other side of `e2`. `y1` and `y2` will execute on the same thread, whichever thread that is. If `e1` and `e2` execute in different threads than the current thread, then the final callback does not happen in the current thread. If you want to get back to the current thread, you need to get there via an executor.
-
-This works because `via` returns a deactivated ("cold") Future, which blocks the propagation of callbacks until it is activated. Activation happens either explicitly (`activate`) or implicitly when the Future returned by `via` is destructed. In this example, there is no ambiguity about in which context any of the callbacks happen (including `y2`), because propagation is blocked at the `via` callsites until after everything is wired up (temporaries are destructed after the calls to `then` have completed).
-
-You can still have a race after `via` if you break it into multiple statements, e.g. in this counterexample:
-```C++
-f = f.via(e1).then(y1).then(y2); // nothing racy here
-f2.then(y3); // racy
-```
-
-## You make me Promises, Promises
-
-If you are wrapping an asynchronous operation, or providing an asynchronous API to users, then you will want to make Promises. Every Future has a corresponding Promise (except Futures that spring into existence already completed, with `makeFuture()`). Promises are simple, you make one, you extract the Future, and you fulfil it with a value or an exception. Example:
-
-```C++
-Promise<int> p;
-Future<int> f = p.getFuture();
-
-f.isReady() == false
-
-p.setValue(42);
-
-f.isReady() == true
-f.value() == 42
-```
-
-and an exception example:
-
-```C++
-Promise<int> p;
-Future<int> f = p.getFuture();
-
-f.isReady() == false
-
-p.setException(std::runtime_error("Fail"));
-
-f.isReady() == true
-f.value() // throws the exception
-```
-
-It's good practice to use fulfil which takes a function and automatically captures exceptions, e.g.
-
-```C++
-Promise<int> p;
-p.fulfil([]{
-  try {
-    // do stuff that may throw
-    return 42;
-  } catch (MySpecialException const& e) {
-    // handle it
-    return 7;
-  }
-  // Any exceptions that we didn't catch, will be caught for us
-});
-```
-
-## FAQ
-
-### Why not use std::future?
-No callback support.
-See also http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf
-
-### Why not use boost::future?
-- 1.53 is brand new, and not in fbcode
-- It's still a bit buggy/bleeding-edge
-- They haven't fleshed out the threading model very well yet, e.g. every single `then` currently spawns a new thread unless you explicitly ask it to work on this thread only, and there is no support for executors yet.
-
-### Why use heap-allocated shared state? Why is Promise not a subclass of Future?
-C++. It boils down to wanting to return a Future by value for performance (move semantics and compiler optimizations), and programmer sanity, and needing a reference to the shared state by both the user (which holds the Future) and the asynchronous operation (which holds the Promise), and allowing either to go out of scope.
-
-### What about proper continuations? Futures suck.
-People mean two things here, they either mean using continuations (as in CSP) or they mean using generators which require continuations. It's important to know those are two distinct questions, but in our context the answer is the same because continuations are a prerequisite for generators.
-
-C++ doesn't directly support continuations very well. But there are some ways to do them in C/C++ that rely on some rather low-level facilities like `setjmp` and `longjmp` (among others). So yes, they are possible (cf. [Mordor](https://github.com/ccutrer/mordor)).
-
-The tradeoff is memory. Each continuation has a stack, and that stack is usually fixed-size and has to be big enough to support whatever ordinary computation you might want to do on it. So each living continuation requires a relatively large amount of memory. If you know the number of continuations will be small, this might be a good fit. In particular, it might be faster and the code might read cleaner.
-
-Wangle takes the middle road between callback hell and continuations, one which has been trodden and proved useful in other languages. It doesn't claim to be the best model for all situations. Use your tools wisely.
diff --git a/folly/wangle/futures/ScheduledExecutor.h b/folly/wangle/futures/ScheduledExecutor.h
deleted file mode 100644 (file)
index 94850c2..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <folly/Executor.h>
-#include <chrono>
-#include <memory>
-#include <stdexcept>
-
-namespace folly { namespace wangle {
-  // An executor that supports timed scheduling. Like RxScheduler.
-  class ScheduledExecutor : public Executor {
-   public:
-     // Reality is that better than millisecond resolution is very hard to
-     // achieve. However, we reserve the right to be incredible.
-     typedef std::chrono::microseconds Duration;
-     typedef std::chrono::steady_clock::time_point TimePoint;
-
-     virtual ~ScheduledExecutor() = default;
-
-     virtual void add(Func) override = 0;
-
-     /// Alias for add() (for Rx consistency)
-     void schedule(Func&& a) { add(std::move(a)); }
-
-     /// Schedule a Func to be executed after dur time has elapsed
-     /// Expect millisecond resolution at best.
-     void schedule(Func&& a, Duration const& dur) {
-       scheduleAt(std::move(a), now() + dur);
-     }
-
-     /// Schedule a Func to be executed at time t, or as soon afterward as
-     /// possible. Expect millisecond resolution at best. Must be threadsafe.
-     virtual void scheduleAt(Func&& a, TimePoint const& t) {
-       throw std::logic_error("unimplemented");
-     }
-
-     /// Get this executor's notion of time. Must be threadsafe.
-     virtual TimePoint now() {
-       return std::chrono::steady_clock::now();
-     }
-  };
-}}
diff --git a/folly/wangle/futures/Timekeeper.h b/folly/wangle/futures/Timekeeper.h
deleted file mode 100644 (file)
index f765fab..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <folly/wangle/futures/detail/Types.h>
-
-namespace folly { namespace wangle {
-
-template <class> struct Future;
-
-/// A Timekeeper handles the details of keeping time and fulfilling delay
-/// promises. The returned Future<void> will either complete after the
-/// elapsed time, or in the event of some kind of exceptional error may hold
-/// an exception. These Futures respond to cancellation. If you use a lot of
-/// Delays and many of them ultimately are unneeded (as would be the case for
-/// Delays that are used to trigger timeouts of async operations), then you
-/// can and should cancel them to reclaim resources.
-///
-/// Users will typically get one of these via Future::sleep(Duration) or
-/// use them implicitly behind the scenes by passing a timeout to some Future
-/// operation.
-///
-/// Although we don't formally alias Delay = Future<void>,
-/// that's an appropriate term for it. People will probably also call these
-/// Timeouts, and that's ok I guess, but that term is so overloaded I thought
-/// it made sense to introduce a cleaner term.
-///
-/// Remember that Duration is a std::chrono duration (millisecond resolution
-/// at the time of writing).
-class Timekeeper {
- public:
-  virtual ~Timekeeper() = default;
-
-  /// Returns a future that will complete after the given duration with the
-  /// elapsed time. Exceptional errors can happen but they must be
-  /// exceptional. Use the steady (monotonic) clock.
-  ///
-  /// You may cancel this Future to reclaim resources.
-  ///
-  /// This future probably completes on the timer thread. You should almost
-  /// certainly follow it with a via() call or the accuracy of other timers
-  /// will suffer.
-  virtual Future<void> after(Duration) = 0;
-
-  /// Returns a future that will complete at the requested time.
-  ///
-  /// You may cancel this Future to reclaim resources.
-  ///
-  /// NB This is sugar for `after(when - now)`, so while you are welcome to
-  /// use a std::chrono::system_clock::time_point it will not track changes to
-  /// the system clock but rather execute that many milliseconds in the future
-  /// according to the steady clock.
-  template <class Clock>
-  Future<void> at(std::chrono::time_point<Clock> when);
-};
-
-}}
-
-// now get those definitions
-#include <folly/wangle/futures/Future.h>
-
-// finally we can use Future
-namespace folly { namespace wangle {
-
-  template <class Clock>
-  Future<void> Timekeeper::at(std::chrono::time_point<Clock> when) {
-    auto now = Clock::now();
-
-    if (when <= now) {
-      return makeFuture();
-    }
-
-    return after(when - now);
-  }
-
-}}
diff --git a/folly/wangle/futures/Try-inl.h b/folly/wangle/futures/Try-inl.h
deleted file mode 100644 (file)
index 63a005b..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stdexcept>
-
-#include <folly/wangle/futures/WangleException.h>
-
-namespace folly { namespace wangle {
-
-template <class T>
-Try<T>::Try(Try<T>&& t) : contains_(t.contains_) {
-  if (contains_ == Contains::VALUE) {
-    new (&value_)T(std::move(t.value_));
-  } else if (contains_ == Contains::EXCEPTION) {
-    new (&e_)std::unique_ptr<exception_wrapper>(std::move(t.e_));
-  }
-}
-
-template <class T>
-Try<T>& Try<T>::operator=(Try<T>&& t) {
-  this->~Try();
-  contains_ = t.contains_;
-  if (contains_ == Contains::VALUE) {
-    new (&value_)T(std::move(t.value_));
-  } else if (contains_ == Contains::EXCEPTION) {
-    new (&e_)std::unique_ptr<exception_wrapper>(std::move(t.e_));
-  }
-  return *this;
-}
-
-template <class T>
-Try<T>::~Try() {
-  if (contains_ == Contains::VALUE) {
-    value_.~T();
-  } else if (contains_ == Contains::EXCEPTION) {
-    e_.~unique_ptr<exception_wrapper>();
-  }
-}
-
-template <class T>
-T& Try<T>::value() {
-  throwIfFailed();
-  return value_;
-}
-
-template <class T>
-const T& Try<T>::value() const {
-  throwIfFailed();
-  return value_;
-}
-
-template <class T>
-void Try<T>::throwIfFailed() const {
-  if (contains_ != Contains::VALUE) {
-    if (contains_ == Contains::EXCEPTION) {
-      e_->throwException();
-    } else {
-      throw UsingUninitializedTry();
-    }
-  }
-}
-
-void Try<void>::throwIfFailed() const {
-  if (!hasValue_) {
-    e_->throwException();
-  }
-}
-
-template <typename T>
-inline T moveFromTry(wangle::Try<T>&& t) {
-  return std::move(t.value());
-}
-
-inline void moveFromTry(wangle::Try<void>&& t) {
-  return t.value();
-}
-
-template <typename F>
-typename std::enable_if<
-  !std::is_same<typename std::result_of<F()>::type, void>::value,
-  Try<typename std::result_of<F()>::type>>::type
-makeTryFunction(F&& f) {
-  typedef typename std::result_of<F()>::type ResultType;
-  try {
-    return Try<ResultType>(f());
-  } catch (std::exception& e) {
-    return Try<ResultType>(exception_wrapper(std::current_exception(), e));
-  } catch (...) {
-    return Try<ResultType>(exception_wrapper(std::current_exception()));
-  }
-}
-
-template <typename F>
-typename std::enable_if<
-  std::is_same<typename std::result_of<F()>::type, void>::value,
-  Try<void>>::type
-makeTryFunction(F&& f) {
-  try {
-    f();
-    return Try<void>();
-  } catch (std::exception& e) {
-    return Try<void>(exception_wrapper(std::current_exception(), e));
-  } catch (...) {
-    return Try<void>(exception_wrapper(std::current_exception()));
-  }
-}
-
-}}
diff --git a/folly/wangle/futures/Try.h b/folly/wangle/futures/Try.h
deleted file mode 100644 (file)
index b262556..0000000
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <type_traits>
-#include <exception>
-#include <algorithm>
-#include <folly/ExceptionWrapper.h>
-#include <folly/Likely.h>
-#include <folly/Memory.h>
-#include <folly/wangle/futures/Deprecated.h>
-#include <folly/wangle/futures/WangleException.h>
-
-namespace folly { namespace wangle {
-
-/*
- * Try<T> is a wrapper that contains either an instance of T, an exception, or
- * nothing. Its primary use case is as a representation of a Promise or Future's
- * result and so it provides a number of methods that are useful in that
- * context. Exceptions are stored as exception_wrappers so that the user can
- * minimize rethrows if so desired.
- *
- * There is a specialization, Try<void>, which represents either success
- * or an exception.
- */
-template <class T>
-class Try {
-  static_assert(!std::is_reference<T>::value,
-                "Try may not be used with reference types");
-
-  enum class Contains {
-    VALUE,
-    EXCEPTION,
-    NOTHING,
-  };
-
- public:
-  /*
-   * The value type for the Try
-   */
-  typedef T element_type;
-
-  /*
-   * Construct an empty Try
-   */
-  Try() : contains_(Contains::NOTHING) {}
-
-  /*
-   * Construct a Try with a value by copy
-   *
-   * @param v The value to copy in
-   */
-  explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
-
-  /*
-   * Construct a Try with a value by move
-   *
-   * @param v The value to move in
-   */
-  explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
-
-  /*
-   * Construct a Try with an exception_wrapper
-   *
-   * @param e The exception_wrapper
-   */
-  explicit Try(exception_wrapper e)
-    : contains_(Contains::EXCEPTION),
-      e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
-
-  /*
-   * DEPRECATED
-   * Construct a Try with an exception_pointer
-   *
-   * @param ep The exception_pointer. Will be rethrown.
-   */
-  explicit Try(std::exception_ptr ep) DEPRECATED
-    : contains_(Contains::EXCEPTION) {
-    try {
-      std::rethrow_exception(ep);
-    } catch (const std::exception& e) {
-      e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
-    } catch (...) {
-      e_ = folly::make_unique<exception_wrapper>(std::current_exception());
-    }
-  }
-
-  // Move constructor
-  Try(Try<T>&& t);
-  // Move assigner
-  Try& operator=(Try<T>&& t);
-
-  // Non-copyable
-  Try(const Try<T>& t) = delete;
-  // Non-copyable
-  Try& operator=(const Try<T>& t) = delete;
-
-  ~Try();
-
-  /*
-   * Get a mutable reference to the contained value. If the Try contains an
-   * exception it will be rethrown.
-   *
-   * @returns mutable reference to the contained value
-   */
-  T& value();
-  /*
-   * Get a const reference to the contained value. If the Try contains an
-   * exception it will be rethrown.
-   *
-   * @returns const reference to the contained value
-   */
-  const T& value() const;
-
-  /*
-   * If the Try contains an exception, rethrow it. Otherwise do nothing.
-   */
-  void throwIfFailed() const;
-
-  /*
-   * Const dereference operator. If the Try contains an exception it will be
-   * rethrown.
-   *
-   * @returns const reference to the contained value
-   */
-  const T& operator*() const { return value(); }
-  /*
-   * Dereference operator. If the Try contains an exception it will be rethrown.
-   *
-   * @returns mutable reference to the contained value
-   */
-  T& operator*() { return value(); }
-
-  /*
-   * Const arrow operator. If the Try contains an exception it will be
-   * rethrown.
-   *
-   * @returns const reference to the contained value
-   */
-  const T* operator->() const { return &value(); }
-  /*
-   * Arrow operator. If the Try contains an exception it will be rethrown.
-   *
-   * @returns mutable reference to the contained value
-   */
-  T* operator->() { return &value(); }
-
-  /*
-   * @returns True if the Try contains a value, false otherwise
-   */
-  bool hasValue() const { return contains_ == Contains::VALUE; }
-  /*
-   * @returns True if the Try contains an exception, false otherwise
-   */
-  bool hasException() const { return contains_ == Contains::EXCEPTION; }
-
-  /*
-   * @returns True if the Try contains an exception of type Ex, false otherwise
-   */
-  template <class Ex>
-  bool hasException() const {
-    return hasException() && e_->is_compatible_with<Ex>();
-  }
-
-  exception_wrapper& exception() {
-    if (UNLIKELY(!hasException())) {
-      throw WangleException("exception(): Try does not contain an exception");
-    }
-    return *e_;
-  }
-
-  /*
-   * If the Try contains an exception and it is of type Ex, execute func(Ex)
-   *
-   * @param func a function that takes a single parameter of type const Ex&
-   *
-   * @returns True if the Try held an Ex and func was executed, false otherwise
-   */
-  template <class Ex, class F>
-  bool withException(F func) const {
-    if (!hasException()) {
-      return false;
-    }
-    return e_->with_exception<Ex>(std::move(func));
-  }
-
- private:
-  Contains contains_;
-  union {
-    T value_;
-    std::unique_ptr<exception_wrapper> e_;
-  };
-};
-
-/*
- * Specialization of Try for void value type. Encapsulates either success or an
- * exception.
- */
-template <>
-class Try<void> {
- public:
-  // Construct a Try holding a successful and void result
-  Try() : hasValue_(true) {}
-
-  /*
-   * Construct a Try with an exception_wrapper
-   *
-   * @param e The exception_wrapper
-   */
-  explicit Try(exception_wrapper e)
-    : hasValue_(false),
-      e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
-
-  /*
-   * DEPRECATED
-   * Construct a Try with an exception_pointer
-   *
-   * @param ep The exception_pointer. Will be rethrown.
-   */
-  explicit Try(std::exception_ptr ep) DEPRECATED : hasValue_(false) {
-    try {
-      std::rethrow_exception(ep);
-    } catch (const std::exception& e) {
-      e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
-    } catch (...) {
-      e_ = folly::make_unique<exception_wrapper>(std::current_exception());
-    }
-  }
-
-  // Copy assigner
-  Try& operator=(const Try<void>& t) {
-    hasValue_ = t.hasValue_;
-    if (t.e_) {
-      e_ = folly::make_unique<exception_wrapper>(*t.e_);
-    }
-    return *this;
-  }
-  // Copy constructor
-  Try(const Try<void>& t) {
-    *this = t;
-  }
-
-  // If the Try contains an exception, throws it
-  void value() const { throwIfFailed(); }
-  // Dereference operator. If the Try contains an exception, throws it
-  void operator*() const { return value(); }
-
-  // If the Try contains an exception, throws it
-  inline void throwIfFailed() const;
-
-  // @returns False if the Try contains an exception, true otherwise
-  bool hasValue() const { return hasValue_; }
-  // @returns True if the Try contains an exception, false otherwise
-  bool hasException() const { return !hasValue_; }
-
-  // @returns True if the Try contains an exception of type Ex, false otherwise
-  template <class Ex>
-  bool hasException() const {
-    return hasException() && e_->is_compatible_with<Ex>();
-  }
-
-  /*
-   * @throws WangleException if the Try doesn't contain an exception
-   *
-   * @returns mutable reference to the exception contained by this Try
-   */
-  exception_wrapper& exception() {
-    if (UNLIKELY(!hasException())) {
-      throw WangleException("exception(): Try does not contain an exception");
-    }
-    return *e_;
-  }
-
-  /*
-   * If the Try contains an exception and it is of type Ex, execute func(Ex)
-   *
-   * @param func a function that takes a single parameter of type const Ex&
-   *
-   * @returns True if the Try held an Ex and func was executed, false otherwise
-   */
-  template <class Ex, class F>
-  bool withException(F func) const {
-    if (!hasException()) {
-      return false;
-    }
-    return e_->with_exception<Ex>(std::move(func));
-  }
-
- private:
-  bool hasValue_;
-  std::unique_ptr<exception_wrapper> e_{nullptr};
-};
-
-/*
- * Extracts value from try and returns it. Throws if try contained an exception.
- *
- * @param t Try to extract value from
- *
- * @returns value contained in t
- */
-template <typename T>
-T moveFromTry(wangle::Try<T>&& t);
-
-/*
- * Throws if try contained an exception.
- *
- * @param t Try to move from
- */
-void moveFromTry(wangle::Try<void>&& t);
-
-/*
- * @param f a function to execute and capture the result of (value or exception)
- *
- * @returns Try holding the result of f
- */
-template <typename F>
-typename std::enable_if<
-  !std::is_same<typename std::result_of<F()>::type, void>::value,
-  Try<typename std::result_of<F()>::type>>::type
-makeTryFunction(F&& f);
-
-/*
- * Specialization of makeTryFunction for void
- *
- * @param f a function to execute and capture the result of
- *
- * @returns Try<void> holding the result of f
- */
-template <typename F>
-typename std::enable_if<
-  std::is_same<typename std::result_of<F()>::type, void>::value,
-  Try<void>>::type
-makeTryFunction(F&& f);
-
-
-}}
-
-#include <folly/wangle/futures/Try-inl.h>
diff --git a/folly/wangle/futures/WangleException.h b/folly/wangle/futures/WangleException.h
deleted file mode 100644 (file)
index 0d97130..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <exception>
-#include <string>
-
-namespace folly { namespace wangle {
-
-class WangleException : public std::exception {
-
-public:
-
-  explicit WangleException(std::string message_arg)
-    : message(message_arg) {}
-
-  ~WangleException() throw(){}
-
-  virtual const char *what() const throw() {
-    return message.c_str();
-  }
-
-  bool operator==(const WangleException &other) const{
-    return other.message == this->message;
-  }
-
-  bool operator!=(const WangleException &other) const{
-    return !(*this == other);
-  }
-
-  protected:
-    std::string message;
-};
-
-class BrokenPromise : public WangleException {
-  public:
-    explicit BrokenPromise() :
-      WangleException("Broken promise") { }
-};
-
-class NoState : public WangleException {
-  public:
-    explicit NoState() : WangleException("No state") { }
-};
-
-class PromiseAlreadySatisfied : public WangleException {
-  public:
-    explicit PromiseAlreadySatisfied() :
-      WangleException("Promise already satisfied") { }
-};
-
-class FutureNotReady : public WangleException {
-  public:
-    explicit FutureNotReady() :
-      WangleException("Future not ready") { }
-};
-
-class FutureAlreadyRetrieved : public WangleException {
-  public:
-    explicit FutureAlreadyRetrieved () :
-      WangleException("Future already retrieved") { }
-};
-
-class UsingUninitializedTry : public WangleException {
-  public:
-    explicit UsingUninitializedTry() :
-      WangleException("Using unitialized try") { }
-};
-
-class FutureCancellation : public WangleException {
- public:
-  FutureCancellation() : WangleException("Future was cancelled") {}
-};
-
-class TimedOut : public WangleException {
- public:
-  TimedOut() : WangleException("Timed out") {}
-};
-
-}}
diff --git a/folly/wangle/futures/detail/Core.h b/folly/wangle/futures/detail/Core.h
deleted file mode 100644 (file)
index ae08102..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <atomic>
-#include <mutex>
-#include <stdexcept>
-#include <vector>
-
-#include <folly/Optional.h>
-#include <folly/SmallLocks.h>
-
-#include <folly/wangle/futures/Try.h>
-#include <folly/wangle/futures/Promise.h>
-#include <folly/wangle/futures/Future.h>
-#include <folly/Executor.h>
-#include <folly/wangle/futures/detail/FSM.h>
-
-#include <folly/io/async/Request.h>
-
-namespace folly { namespace wangle { namespace detail {
-
-// As of GCC 4.8.1, the std::function in libstdc++ optimizes only for pointers
-// to functions, using a helper avoids a call to malloc.
-template<typename T>
-void empty_callback(Try<T>&&) { }
-
-enum class State {
-  Waiting,
-  Interruptible,
-  Interrupted,
-  Done,
-};
-
-/** The shared state object for Future and Promise. */
-template<typename T>
-class Core : protected FSM<State> {
- public:
-  // This must be heap-constructed. There's probably a way to enforce that in
-  // code but since this is just internal detail code and I don't know how
-  // off-hand, I'm punting.
-  Core() : FSM<State>(State::Waiting) {}
-  ~Core() {
-    assert(calledBack_);
-    assert(detached_ == 2);
-  }
-
-  // not copyable
-  Core(Core const&) = delete;
-  Core& operator=(Core const&) = delete;
-
-  // not movable (see comment in the implementation of Future::then)
-  Core(Core&&) noexcept = delete;
-  Core& operator=(Core&&) = delete;
-
-  Try<T>& getTry() {
-    if (ready()) {
-      return *result_;
-    } else {
-      throw FutureNotReady();
-    }
-  }
-
-  template <typename F>
-  void setCallback(F func) {
-    auto setCallback_ = [&]{
-      if (callback_) {
-        throw std::logic_error("setCallback called twice");
-      }
-
-      context_ = RequestContext::saveContext();
-      callback_ = std::move(func);
-    };
-
-    FSM_START
-      case State::Waiting:
-      case State::Interruptible:
-      case State::Interrupted:
-        FSM_UPDATE(state, setCallback_);
-        break;
-
-      case State::Done:
-        FSM_UPDATE2(State::Done,
-          setCallback_,
-          [&]{ maybeCallback(); });
-        break;
-    FSM_END
-  }
-
-  void setResult(Try<T>&& t) {
-    FSM_START
-      case State::Waiting:
-      case State::Interruptible:
-      case State::Interrupted:
-        FSM_UPDATE2(State::Done,
-          [&]{ result_ = std::move(t); },
-          [&]{ maybeCallback(); });
-        break;
-
-      case State::Done:
-        throw std::logic_error("setResult called twice");
-    FSM_END
-  }
-
-  bool ready() const {
-    return getState() == State::Done;
-  }
-
-  // Called by a destructing Future
-  void detachFuture() {
-    if (!callback_) {
-      setCallback(empty_callback<T>);
-    }
-    activate();
-    detachOne();
-  }
-
-  // Called by a destructing Promise
-  void detachPromise() {
-    if (!ready()) {
-      setResult(Try<T>(exception_wrapper(BrokenPromise())));
-    }
-    detachOne();
-  }
-
-  void deactivate() {
-    active_ = false;
-  }
-
-  void activate() {
-    active_ = true;
-    if (ready()) {
-      maybeCallback();
-    }
-  }
-
-  bool isActive() { return active_; }
-
-  void setExecutor(Executor* x) {
-    executor_ = x;
-  }
-
-  void raise(exception_wrapper const& e) {
-    FSM_START
-      case State::Interruptible:
-        FSM_UPDATE2(State::Interrupted,
-          [&]{ interrupt_ = folly::make_unique<exception_wrapper>(e); },
-          [&]{ interruptHandler_(*interrupt_); });
-        break;
-
-      case State::Waiting:
-      case State::Interrupted:
-        FSM_UPDATE(State::Interrupted,
-          [&]{ interrupt_ = folly::make_unique<exception_wrapper>(e); });
-        break;
-
-      case State::Done:
-        FSM_BREAK
-    FSM_END
-  }
-
-  void setInterruptHandler(std::function<void(exception_wrapper const&)> fn) {
-    FSM_START
-      case State::Waiting:
-      case State::Interruptible:
-        FSM_UPDATE(State::Interruptible,
-          [&]{ interruptHandler_ = std::move(fn); });
-        break;
-
-      case State::Interrupted:
-        fn(*interrupt_);
-        FSM_BREAK
-
-      case State::Done:
-        FSM_BREAK
-    FSM_END
-  }
-
- private:
-  void maybeCallback() {
-    assert(ready());
-    if (isActive() && callback_) {
-      if (!calledBack_.exchange(true)) {
-        // TODO(5306911) we should probably try/catch
-        Executor* x = executor_;
-
-        RequestContext::setContext(context_);
-        if (x) {
-          MoveWrapper<std::function<void(Try<T>&&)>> cb(std::move(callback_));
-          MoveWrapper<folly::Optional<Try<T>>> val(std::move(result_));
-          x->add([cb, val]() mutable { (*cb)(std::move(**val)); });
-        } else {
-          callback_(std::move(*result_));
-        }
-      }
-    }
-  }
-
-  void detachOne() {
-    auto d = ++detached_;
-    assert(d >= 1);
-    assert(d <= 2);
-    if (d == 2) {
-      // we should have already executed the callback with the value
-      assert(calledBack_);
-      delete this;
-    }
-  }
-
-  folly::Optional<Try<T>> result_;
-  std::function<void(Try<T>&&)> callback_;
-  std::shared_ptr<RequestContext> context_{nullptr};
-  std::atomic<bool> calledBack_ {false};
-  std::atomic<unsigned char> detached_ {0};
-  std::atomic<bool> active_ {true};
-  std::atomic<Executor*> executor_ {nullptr};
-  std::unique_ptr<exception_wrapper> interrupt_;
-  std::function<void(exception_wrapper const&)> interruptHandler_;
-};
-
-template <typename... Ts>
-struct VariadicContext {
-  VariadicContext() : total(0), count(0) {}
-  Promise<std::tuple<Try<Ts>... > > p;
-  std::tuple<Try<Ts>... > results;
-  size_t total;
-  std::atomic<size_t> count;
-  typedef Future<std::tuple<Try<Ts>...>> type;
-};
-
-template <typename... Ts, typename THead, typename... Fs>
-typename std::enable_if<sizeof...(Fs) == 0, void>::type
-whenAllVariadicHelper(VariadicContext<Ts...> *ctx, THead&& head, Fs&&... tail) {
-  head.setCallback_([ctx](Try<typename THead::value_type>&& t) {
-    std::get<sizeof...(Ts) - sizeof...(Fs) - 1>(ctx->results) = std::move(t);
-    if (++ctx->count == ctx->total) {
-      ctx->p.setValue(std::move(ctx->results));
-      delete ctx;
-    }
-  });
-}
-
-template <typename... Ts, typename THead, typename... Fs>
-typename std::enable_if<sizeof...(Fs) != 0, void>::type
-whenAllVariadicHelper(VariadicContext<Ts...> *ctx, THead&& head, Fs&&... tail) {
-  head.setCallback_([ctx](Try<typename THead::value_type>&& t) {
-    std::get<sizeof...(Ts) - sizeof...(Fs) - 1>(ctx->results) = std::move(t);
-    if (++ctx->count == ctx->total) {
-      ctx->p.setValue(std::move(ctx->results));
-      delete ctx;
-    }
-  });
-  // template tail-recursion
-  whenAllVariadicHelper(ctx, std::forward<Fs>(tail)...);
-}
-
-template <typename T>
-struct WhenAllContext {
-  WhenAllContext() : count(0) {}
-  Promise<std::vector<Try<T> > > p;
-  std::vector<Try<T> > results;
-  std::atomic<size_t> count;
-};
-
-template <typename T>
-struct WhenAnyContext {
-  explicit WhenAnyContext(size_t n) : done(false), ref_count(n) {};
-  Promise<std::pair<size_t, Try<T>>> p;
-  std::atomic<bool> done;
-  std::atomic<size_t> ref_count;
-  void decref() {
-    if (--ref_count == 0) {
-      delete this;
-    }
-  }
-};
-
-}}} // namespace
diff --git a/folly/wangle/futures/detail/FSM.h b/folly/wangle/futures/detail/FSM.h
deleted file mode 100644 (file)
index be4eb8a..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <atomic>
-#include <mutex>
-#include <folly/SmallLocks.h>
-
-namespace folly { namespace wangle { namespace detail {
-
-/// Finite State Machine helper base class.
-/// Inherit from this.
-/// For best results, use an "enum class" for Enum.
-template <class Enum>
-class FSM {
-private:
-  // I am not templatizing this because folly::MicroSpinLock needs to be
-  // zero-initialized (or call init) which isn't generic enough for something
-  // that behaves like std::mutex. :(
-  using Mutex = folly::MicroSpinLock;
-  Mutex mutex_ {0};
-
-  // This might not be necessary for all Enum types, e.g. anything
-  // that is atomically updated in practice on this CPU and there's no risk
-  // of returning a bogus state because of tearing.
-  // An optimization would be to use a static conditional on the Enum type.
-  std::atomic<Enum> state_;
-
-public:
-  explicit FSM(Enum startState) : state_(startState) {}
-
-  Enum getState() const {
-    return state_.load(std::memory_order_relaxed);
-  }
-
-  /// Atomically do a state transition with accompanying action.
-  /// The action will see the old state.
-  /// @returns true on success, false and action unexecuted otherwise
-  template <class F>
-  bool updateState(Enum A, Enum B, F const& action) {
-    std::lock_guard<Mutex> lock(mutex_);
-    if (state_ != A) return false;
-    action();
-    state_ = B;
-    return true;
-  }
-
-  /// Atomically do a state transition with accompanying action. Then do the
-  /// unprotected action without holding the lock. If the atomic transition
-  /// fails, returns false and neither action was executed.
-  ///
-  /// This facilitates code like this:
-  ///   bool done = false;
-  ///   while (!done) {
-  ///     switch (getState()) {
-  ///     case State::Foo:
-  ///       done = updateState(State::Foo, State::Bar,
-  ///           [&]{ /* do protected stuff */ },
-  ///           [&]{ /* do unprotected stuff */});
-  ///       break;
-  ///
-  /// Which reads nicer than code like this:
-  ///   while (true) {
-  ///     switch (getState()) {
-  ///     case State::Foo:
-  ///       if (!updateState(State::Foo, State::Bar,
-  ///           [&]{ /* do protected stuff */ })) {
-  ///         continue;
-  ///       }
-  ///       /* do unprotected stuff */
-  ///       return; // or otherwise break out of the loop
-  ///
-  /// The protected action will see the old state, and the unprotected action
-  /// will see the new state.
-  template <class F1, class F2>
-  bool updateState(Enum A, Enum B,
-                   F1 const& protectedAction, F2 const& unprotectedAction) {
-    bool result = updateState(A, B, protectedAction);
-    if (result) {
-      unprotectedAction();
-    }
-    return result;
-  }
-};
-
-#define FSM_START \
-  {bool done = false; while (!done) { auto state = getState(); switch (state) {
-
-#define FSM_UPDATE2(b, protectedAction, unprotectedAction) \
-    done = updateState(state, (b), (protectedAction), (unprotectedAction));
-
-#define FSM_UPDATE(b, action) FSM_UPDATE2((b), (action), []{})
-
-#define FSM_CASE(a, b, action) \
-  case (a): \
-    FSM_UPDATE((b), (action)); \
-    break;
-
-#define FSM_CASE2(a, b, protectedAction, unprotectedAction) \
-  case (a): \
-    FSM_UPDATE2((b), (protectedAction), (unprotectedAction)); \
-    break;
-
-#define FSM_BREAK done = true; break;
-#define FSM_END }}}
-
-
-}}}
diff --git a/folly/wangle/futures/detail/ThreadWheelTimekeeper.cpp b/folly/wangle/futures/detail/ThreadWheelTimekeeper.cpp
deleted file mode 100644 (file)
index d3c6315..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "ThreadWheelTimekeeper.h"
-
-#include <folly/experimental/Singleton.h>
-#include <folly/wangle/futures/Future.h>
-#include <future>
-
-namespace folly { namespace wangle { namespace detail {
-
-namespace {
-  Singleton<ThreadWheelTimekeeper> timekeeperSingleton_;
-
-  // Our Callback object for HHWheelTimer
-  struct WTCallback : public folly::HHWheelTimer::Callback {
-    // Only allow creation by this factory, to ensure heap allocation.
-    static WTCallback* create() {
-      // optimization opportunity: memory pool
-      return new WTCallback();
-    }
-
-    Future<void> getFuture() {
-      return promise_.getFuture();
-    }
-
-   protected:
-    Promise<void> promise_;
-
-    explicit WTCallback() {
-      promise_.setInterruptHandler(
-        std::bind(&WTCallback::interruptHandler, this));
-    }
-
-    void timeoutExpired() noexcept override {
-      promise_.setValue();
-      delete this;
-    }
-
-    void interruptHandler() {
-      cancelTimeout();
-      delete this;
-    }
-  };
-
-} // namespace
-
-
-ThreadWheelTimekeeper::ThreadWheelTimekeeper() :
-  thread_([this]{ eventBase_.loopForever(); }),
-  wheelTimer_(new HHWheelTimer(&eventBase_, std::chrono::milliseconds(1)))
-{
-  eventBase_.waitUntilRunning();
-  eventBase_.runInEventBaseThread([this]{
-    // 15 characters max
-    eventBase_.setName("FutureTimekeepr");
-  });
-}
-
-ThreadWheelTimekeeper::~ThreadWheelTimekeeper() {
-  eventBase_.runInEventBaseThread([this]{
-    wheelTimer_->cancelAll();
-  });
-  eventBase_.terminateLoopSoon();
-  thread_.join();
-}
-
-Future<void> ThreadWheelTimekeeper::after(Duration dur) {
-  auto cob = WTCallback::create();
-  auto f = cob->getFuture();
-  eventBase_.runInEventBaseThread([=]{
-    wheelTimer_->scheduleTimeout(cob, dur);
-  });
-  return f;
-}
-
-Timekeeper* getTimekeeperSingleton() {
-  return timekeeperSingleton_.get_fast();
-}
-
-}}}
diff --git a/folly/wangle/futures/detail/ThreadWheelTimekeeper.h b/folly/wangle/futures/detail/ThreadWheelTimekeeper.h
deleted file mode 100644 (file)
index 35e895d..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <folly/wangle/futures/Future.h>
-#include <folly/wangle/futures/Timekeeper.h>
-#include <folly/io/async/EventBase.h>
-#include <folly/io/async/HHWheelTimer.h>
-#include <thread>
-
-namespace folly { namespace wangle { namespace detail {
-
-/// The default Timekeeper implementation which uses a HHWheelTimer on an
-/// EventBase in a dedicated thread. Users needn't deal with this directly, it
-/// is used by default by Future methods that work with timeouts.
-class ThreadWheelTimekeeper : public Timekeeper {
- public:
-  /// But it doesn't *have* to be a singleton.
-  ThreadWheelTimekeeper();
-  ~ThreadWheelTimekeeper();
-
-  /// Implement the Timekeeper interface
-  /// This future *does* complete on the timer thread. You should almost
-  /// certainly follow it with a via() call or the accuracy of other timers
-  /// will suffer.
-  Future<void> after(Duration) override;
-
- protected:
-  folly::EventBase eventBase_;
-  std::thread thread_;
-  HHWheelTimer::UniquePtr wheelTimer_;
-};
-
-Timekeeper* getTimekeeperSingleton();
-
-}}}
diff --git a/folly/wangle/futures/detail/Types.h b/folly/wangle/futures/detail/Types.h
deleted file mode 100644 (file)
index 57b93e0..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <chrono>
-
-namespace folly { namespace wangle {
-
-using Duration = std::chrono::milliseconds;
-
-}}
diff --git a/folly/wangle/futures/test/Benchmark.cpp b/folly/wangle/futures/test/Benchmark.cpp
deleted file mode 100644 (file)
index dc811ce..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gflags/gflags.h>
-#include <folly/Baton.h>
-#include <folly/Benchmark.h>
-#include <folly/wangle/futures/Future.h>
-#include <folly/wangle/futures/Promise.h>
-#include <semaphore.h>
-#include <vector>
-
-using namespace folly::wangle;
-using namespace std;
-
-namespace {
-
-template <class T>
-T incr(Try<T>&& t) {
-  return t.value() + 1;
-}
-
-void someThens(size_t n) {
-  auto f = makeFuture<int>(42);
-  for (size_t i = 0; i < n; i++) {
-    f = f.then(incr<int>);
-  }
-}
-
-} // anonymous namespace
-
-BENCHMARK(constantFuture) {
-  makeFuture(42);
-}
-
-// This shouldn't get too far below 100%
-BENCHMARK_RELATIVE(promiseAndFuture) {
-  Promise<int> p;
-  Future<int> f = p.getFuture();
-  p.setValue(42);
-  f.value();
-}
-
-// The higher the better. At the time of writing, it's only about 40% :(
-BENCHMARK_RELATIVE(withThen) {
-  Promise<int> p;
-  Future<int> f = p.getFuture().then(incr<int>);
-  p.setValue(42);
-  f.value();
-}
-
-// thens
-BENCHMARK_DRAW_LINE()
-
-BENCHMARK(oneThen) {
-  someThens(1);
-}
-
-// look for >= 50% relative
-BENCHMARK_RELATIVE(twoThens) {
-  someThens(2);
-}
-
-// look for >= 25% relative
-BENCHMARK_RELATIVE(fourThens) {
-  someThens(4);
-}
-
-// look for >= 1% relative
-BENCHMARK_RELATIVE(hundredThens) {
-  someThens(100);
-}
-
-// Lock contention. Although in practice fulfil()s tend to be temporally
-// separate from then()s, still sometimes they will be concurrent. So the
-// higher this number is, the better.
-BENCHMARK_DRAW_LINE()
-
-BENCHMARK(no_contention) {
-  vector<Promise<int>> promises(10000);
-  vector<Future<int>> futures;
-  std::thread producer, consumer;
-
-  BENCHMARK_SUSPEND {
-    folly::Baton<> b1, b2;
-    for (auto& p : promises)
-      futures.push_back(p.getFuture());
-
-    consumer = std::thread([&]{
-      b1.post();
-      for (auto& f : futures) f.then(incr<int>);
-    });
-    consumer.join();
-
-    producer = std::thread([&]{
-      b2.post();
-      for (auto& p : promises) p.setValue(42);
-    });
-
-    b1.wait();
-    b2.wait();
-  }
-
-  // The only thing we are measuring is how long fulfil + callbacks take
-  producer.join();
-}
-
-BENCHMARK_RELATIVE(contention) {
-  vector<Promise<int>> promises(10000);
-  vector<Future<int>> futures;
-  std::thread producer, consumer;
-  sem_t sem;
-  sem_init(&sem, 0, 0);
-
-  BENCHMARK_SUSPEND {
-    folly::Baton<> b1, b2;
-    for (auto& p : promises)
-      futures.push_back(p.getFuture());
-
-    consumer = std::thread([&]{
-      b1.post();
-      for (auto& f : futures) {
-        sem_wait(&sem);
-        f.then(incr<int>);
-      }
-    });
-
-    producer = std::thread([&]{
-      b2.post();
-      for (auto& p : promises) {
-        sem_post(&sem);
-        p.setValue(42);
-      }
-    });
-
-    b1.wait();
-    b2.wait();
-  }
-
-  // The astute reader will notice that we're not *precisely* comparing apples
-  // to apples here. Well, maybe it's like comparing Granny Smith to
-  // Braeburn or something. In the serial version, we waited for the futures
-  // to be all set up, but here we are probably still doing that work
-  // (although in parallel). But even though there is more work (on the order
-  // of 2x), it is being done by two threads. Hopefully most of the difference
-  // we see is due to lock contention and not false parallelism.
-  //
-  // Be warned that if the box is under heavy load, this will greatly skew
-  // these results (scheduling overhead will begin to dwarf lock contention).
-  // I'm not sure but I'd guess in Windtunnel this will mean large variance,
-  // because I expect they load the boxes as much as they can?
-  consumer.join();
-  producer.join();
-}
-
-BENCHMARK_DRAW_LINE();
-
-// The old way. Throw an exception, and rethrow to access it upstream.
-void throwAndCatchImpl() {
-  makeFuture()
-      .then([](Try<void>&&){ throw std::runtime_error("oh no"); })
-      .then([](Try<void>&& t) {
-        try {
-          t.value();
-        } catch(const std::runtime_error& e) {
-          // ...
-          return;
-        }
-        CHECK(false);
-      });
-}
-
-// Not much better. Throw an exception, and access it via the wrapper upstream.
-// Actually a little worse due to wrapper overhead. then() won't know that the
-// exception is a runtime_error, so will have to store it as an exception_ptr
-// anyways. withException will therefore have to rethrow. Note that if we threw
-// std::exception instead, we would see some wins, as that's the type then()
-// will try to wrap, so no exception_ptrs/rethrows are necessary.
-void throwAndCatchWrappedImpl() {
-  makeFuture()
-      .then([](Try<void>&&){ throw std::runtime_error("oh no"); })
-      .then([](Try<void>&& t) {
-        auto caught = t.withException<std::runtime_error>(
-            [](const std::runtime_error& e){
-              // ...
-            });
-        CHECK(caught);
-      });
-}
-
-// Better. Wrap an exception, and rethrow to access it upstream.
-void throwWrappedAndCatchImpl() {
-  makeFuture()
-      .then([](Try<void>&&){
-        return makeFuture<void>(std::runtime_error("oh no"));
-      })
-      .then([](Try<void>&& t) {
-        try {
-          t.value();
-        } catch(const std::runtime_error& e) {
-          // ...
-          return;
-        }
-        CHECK(false);
-      });
-}
-
-// The new way. Wrap an exception, and access it via the wrapper upstream
-void throwWrappedAndCatchWrappedImpl() {
-  makeFuture()
-      .then([](Try<void>&&){
-        return makeFuture<void>(std::runtime_error("oh no"));
-      })
-      .then([](Try<void>&& t){
-        auto caught = t.withException<std::runtime_error>(
-            [](const std::runtime_error& e){
-              // ...
-            });
-        CHECK(caught);
-      });
-}
-
-// Simulate heavy contention on func
-void contend(void(*func)()) {
-  folly::BenchmarkSuspender s;
-  const int N = 100;
-  const int iters = 1000;
-  pthread_barrier_t barrier;
-  pthread_barrier_init(&barrier, nullptr, N+1);
-  std::vector<std::thread> threads;
-  for (int i = 0; i < N; i++) {
-    threads.push_back(std::thread([&](){
-      pthread_barrier_wait(&barrier);
-      for (int j = 0; j < iters; j++) {
-        func();
-      }
-    }));
-  }
-  pthread_barrier_wait(&barrier);
-  s.dismiss();
-  for (auto& t : threads) {
-    t.join();
-  }
-  s.rehire();
-  pthread_barrier_destroy(&barrier);
-}
-
-BENCHMARK(throwAndCatch) {
-  throwAndCatchImpl();
-}
-
-BENCHMARK_RELATIVE(throwAndCatchWrapped) {
-  throwAndCatchWrappedImpl();
-}
-
-BENCHMARK_RELATIVE(throwWrappedAndCatch) {
-  throwWrappedAndCatchImpl();
-}
-
-BENCHMARK_RELATIVE(throwWrappedAndCatchWrapped) {
-  throwWrappedAndCatchWrappedImpl();
-}
-
-BENCHMARK_DRAW_LINE();
-
-BENCHMARK(throwAndCatchContended) {
-  contend(throwAndCatchImpl);
-}
-
-BENCHMARK_RELATIVE(throwAndCatchWrappedContended) {
-  contend(throwAndCatchWrappedImpl);
-}
-
-BENCHMARK_RELATIVE(throwWrappedAndCatchContended) {
-  contend(throwWrappedAndCatchImpl);
-}
-
-BENCHMARK_RELATIVE(throwWrappedAndCatchWrappedContended) {
-  contend(throwWrappedAndCatchWrappedImpl);
-}
-
-int main(int argc, char** argv) {
-  gflags::ParseCommandLineFlags(&argc, &argv, true);
-  folly::runBenchmarks();
-  return 0;
-}
diff --git a/folly/wangle/futures/test/ClientCompile.cpp b/folly/wangle/futures/test/ClientCompile.cpp
deleted file mode 100644 (file)
index ab18d12..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// amazing what things can go wrong if you include things in an unexpected
-// order.
-#include <folly/wangle/futures/Try.h>
-#include <folly/wangle/futures/Promise.h>
-#include <folly/wangle/futures/Future.h>
-int main() { return 0; }
diff --git a/folly/wangle/futures/test/ExecutorTest.cpp b/folly/wangle/futures/test/ExecutorTest.cpp
deleted file mode 100644 (file)
index 67f43ec..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-#include <folly/wangle/futures/InlineExecutor.h>
-#include <folly/wangle/futures/ManualExecutor.h>
-#include <folly/wangle/futures/QueuedImmediateExecutor.h>
-#include <folly/wangle/futures/Future.h>
-#include <folly/Baton.h>
-
-using namespace folly::wangle;
-using namespace std::chrono;
-using namespace testing;
-
-TEST(ManualExecutor, runIsStable) {
-  ManualExecutor x;
-  size_t count = 0;
-  auto f1 = [&]() { count++; };
-  auto f2 = [&]() { x.add(f1); x.add(f1); };
-  x.add(f2);
-  x.run();
-}
-
-TEST(ManualExecutor, scheduleDur) {
-  ManualExecutor x;
-  size_t count = 0;
-  milliseconds dur {10};
-  x.schedule([&]{ count++; }, dur);
-  EXPECT_EQ(count, 0);
-  x.run();
-  EXPECT_EQ(count, 0);
-  x.advance(dur/2);
-  EXPECT_EQ(count, 0);
-  x.advance(dur/2);
-  EXPECT_EQ(count, 1);
-}
-
-TEST(ManualExecutor, clockStartsAt0) {
-  ManualExecutor x;
-  EXPECT_EQ(x.now(), x.now().min());
-}
-
-TEST(ManualExecutor, scheduleAbs) {
-  ManualExecutor x;
-  size_t count = 0;
-  x.scheduleAt([&]{ count++; }, x.now() + milliseconds(10));
-  EXPECT_EQ(count, 0);
-  x.advance(milliseconds(10));
-  EXPECT_EQ(count, 1);
-}
-
-TEST(ManualExecutor, advanceTo) {
-  ManualExecutor x;
-  size_t count = 0;
-  x.scheduleAt([&]{ count++; }, steady_clock::now());
-  EXPECT_EQ(count, 0);
-  x.advanceTo(steady_clock::now());
-  EXPECT_EQ(count, 1);
-}
-
-TEST(ManualExecutor, advanceBack) {
-  ManualExecutor x;
-  size_t count = 0;
-  x.advance(microseconds(5));
-  x.schedule([&]{ count++; }, microseconds(6));
-  EXPECT_EQ(count, 0);
-  x.advanceTo(x.now() - microseconds(1));
-  EXPECT_EQ(count, 0);
-}
-
-TEST(ManualExecutor, advanceNeg) {
-  ManualExecutor x;
-  size_t count = 0;
-  x.advance(microseconds(5));
-  x.schedule([&]{ count++; }, microseconds(6));
-  EXPECT_EQ(count, 0);
-  x.advance(microseconds(-1));
-  EXPECT_EQ(count, 0);
-}
-
-TEST(ManualExecutor, waitForDoesNotDeadlock) {
-  ManualExecutor east, west;
-  folly::Baton<> baton;
-  auto f = makeFuture()
-    .via(&east)
-    .then([](Try<void>){ return makeFuture(); })
-    .via(&west);
-  std::thread t([&]{
-    baton.post();
-    west.waitFor(f);
-  });
-  baton.wait();
-  east.run();
-  t.join();
-}
-
-TEST(Executor, InlineExecutor) {
-  InlineExecutor x;
-  size_t counter = 0;
-  x.add([&]{
-    x.add([&]{
-      EXPECT_EQ(counter++, 0);
-    });
-    EXPECT_EQ(counter++, 1);
-  });
-  EXPECT_EQ(counter, 2);
-}
-
-TEST(Executor, QueuedImmediateExecutor) {
-  QueuedImmediateExecutor x;
-  size_t counter = 0;
-  x.add([&]{
-    x.add([&]{
-      EXPECT_EQ(1, counter++);
-    });
-    EXPECT_EQ(0, counter++);
-  });
-  EXPECT_EQ(2, counter);
-}
-
-TEST(Executor, Runnable) {
-  InlineExecutor x;
-  size_t counter = 0;
-  struct Runnable {
-    std::function<void()> fn;
-    void operator()() { fn(); }
-  };
-  Runnable f;
-  f.fn = [&]{ counter++; };
-  x.add(f);
-  EXPECT_EQ(counter, 1);
-}
-
-TEST(Executor, RunnablePtr) {
-  InlineExecutor x;
-  struct Runnable {
-    std::function<void()> fn;
-    void operator()() { fn(); }
-  };
-  size_t counter = 0;
-  auto fnp = std::make_shared<Runnable>();
-  fnp->fn = [&]{ counter++; };
-  x.addPtr(fnp);
-  EXPECT_EQ(counter, 1);
-}
diff --git a/folly/wangle/futures/test/FSM.cpp b/folly/wangle/futures/test/FSM.cpp
deleted file mode 100644 (file)
index ff75f86..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-#include <folly/wangle/futures/detail/FSM.h>
-
-using namespace folly::wangle::detail;
-
-enum class State { A, B };
-
-TEST(FSM, example) {
-  FSM<State> fsm(State::A);
-  int count = 0;
-  int unprotectedCount = 0;
-
-  // somebody set up us the switch
-  auto tryTransition = [&]{
-    switch (fsm.getState()) {
-    case State::A:
-      return fsm.updateState(State::A, State::B, [&]{ count++; });
-    case State::B:
-      return fsm.updateState(State::B, State::A,
-                             [&]{ count--; }, [&]{ unprotectedCount--; });
-    }
-    return false; // unreachable
-  };
-
-  // keep retrying until success (like a cas)
-  while (!tryTransition()) ;
-  EXPECT_EQ(State::B, fsm.getState());
-  EXPECT_EQ(1, count);
-  EXPECT_EQ(0, unprotectedCount);
-
-  while (!tryTransition()) ;
-  EXPECT_EQ(State::A, fsm.getState());
-  EXPECT_EQ(0, count);
-  EXPECT_EQ(-1, unprotectedCount);
-}
-
-TEST(FSM, magicMacrosExample) {
-  struct MyFSM : public FSM<State> {
-    int count = 0;
-    int unprotectedCount = 0;
-    MyFSM() : FSM<State>(State::A) {}
-    void twiddle() {
-      FSM_START
-        FSM_CASE(State::A, State::B, [&]{ count++; });
-        FSM_CASE2(State::B, State::A,
-                  [&]{ count--; }, [&]{ unprotectedCount--; });
-      FSM_END
-    }
-  };
-
-  MyFSM fsm;
-
-  fsm.twiddle();
-  EXPECT_EQ(State::B, fsm.getState());
-  EXPECT_EQ(1, fsm.count);
-  EXPECT_EQ(0, fsm.unprotectedCount);
-
-  fsm.twiddle();
-  EXPECT_EQ(State::A, fsm.getState());
-  EXPECT_EQ(0, fsm.count);
-  EXPECT_EQ(-1, fsm.unprotectedCount);
-}
-
-
-TEST(FSM, ctor) {
-  FSM<State> fsm(State::A);
-  EXPECT_EQ(State::A, fsm.getState());
-}
-
-TEST(FSM, update) {
-  FSM<State> fsm(State::A);
-  EXPECT_TRUE(fsm.updateState(State::A, State::B, []{}));
-  EXPECT_EQ(State::B, fsm.getState());
-}
-
-TEST(FSM, badUpdate) {
-  FSM<State> fsm(State::A);
-  EXPECT_FALSE(fsm.updateState(State::B, State::A, []{}));
-}
-
-TEST(FSM, actionOnUpdate) {
-  FSM<State> fsm(State::A);
-  int count = 0;
-  fsm.updateState(State::A, State::B, [&]{ count++; });
-  EXPECT_EQ(1, count);
-}
-
-TEST(FSM, noActionOnBadUpdate) {
-  FSM<State> fsm(State::A);
-  int count = 0;
-  fsm.updateState(State::B, State::A, [&]{ count++; });
-  EXPECT_EQ(0, count);
-}
-
-TEST(FSM, stateTransitionAfterAction) {
-  FSM<State> fsm(State::A);
-  fsm.updateState(State::A, State::B,
-                  [&]{ EXPECT_EQ(State::A, fsm.getState()); });
-}
diff --git a/folly/wangle/futures/test/FutureTest.cpp b/folly/wangle/futures/test/FutureTest.cpp
deleted file mode 100644 (file)
index 939ff2e..0000000
+++ /dev/null
@@ -1,1204 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <algorithm>
-#include <atomic>
-#include <folly/small_vector.h>
-#include <gtest/gtest.h>
-#include <memory>
-#include <string>
-#include <thread>
-#include <type_traits>
-#include <unistd.h>
-#include <folly/Memory.h>
-#include <folly/Executor.h>
-#include <folly/wangle/futures/Future.h>
-#include <folly/wangle/futures/ManualExecutor.h>
-#include <folly/MPMCQueue.h>
-
-#include <folly/io/async/Request.h>
-
-using namespace folly;
-using namespace folly::wangle;
-using std::pair;
-using std::string;
-using std::unique_ptr;
-using std::vector;
-
-#define EXPECT_TYPE(x, T) \
-  EXPECT_TRUE((std::is_same<decltype(x), T>::value))
-
-/// Simple executor that does work in another thread
-class ThreadExecutor : public Executor {
-  folly::MPMCQueue<Func> funcs;
-  std::atomic<bool> done {false};
-  std::thread worker;
-  folly::Baton<> baton;
-
-  void work() {
-    baton.post();
-    Func fn;
-    while (!done) {
-      while (!funcs.isEmpty()) {
-        funcs.blockingRead(fn);
-        fn();
-      }
-    }
-  }
-
- public:
-  explicit ThreadExecutor(size_t n = 1024)
-    : funcs(n), worker(std::bind(&ThreadExecutor::work, this)) {}
-
-  ~ThreadExecutor() {
-    done = true;
-    funcs.write([]{});
-    worker.join();
-  }
-
-  void add(Func fn) override {
-    funcs.blockingWrite(std::move(fn));
-  }
-
-  void waitForStartup() {
-    baton.wait();
-  }
-};
-
-typedef WangleException eggs_t;
-static eggs_t eggs("eggs");
-
-// Future
-
-TEST(Future, onError) {
-  bool theFlag = false;
-  auto flag = [&]{ theFlag = true; };
-#define EXPECT_FLAG() \
-  do { \
-    EXPECT_TRUE(theFlag); \
-    theFlag = false; \
-  } while(0);
-
-#define EXPECT_NO_FLAG() \
-  do { \
-    EXPECT_FALSE(theFlag); \
-    theFlag = false; \
-  } while(0);
-
-  // By reference
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; })
-      .onError([&] (eggs_t& e) { flag(); });
-    EXPECT_FLAG();
-    EXPECT_NO_THROW(f.value());
-  }
-
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; })
-      .onError([&] (eggs_t& e) { flag(); return makeFuture(); });
-    EXPECT_FLAG();
-    EXPECT_NO_THROW(f.value());
-  }
-
-  // By value
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; })
-      .onError([&] (eggs_t e) { flag(); });
-    EXPECT_FLAG();
-    EXPECT_NO_THROW(f.value());
-  }
-
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; })
-      .onError([&] (eggs_t e) { flag(); return makeFuture(); });
-    EXPECT_FLAG();
-    EXPECT_NO_THROW(f.value());
-  }
-
-  // Polymorphic
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; })
-      .onError([&] (std::exception& e) { flag(); });
-    EXPECT_FLAG();
-    EXPECT_NO_THROW(f.value());
-  }
-
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; })
-      .onError([&] (std::exception& e) { flag(); return makeFuture(); });
-    EXPECT_FLAG();
-    EXPECT_NO_THROW(f.value());
-  }
-
-  // Non-exceptions
-  {
-    auto f = makeFuture()
-      .then([] { throw -1; })
-      .onError([&] (int e) { flag(); });
-    EXPECT_FLAG();
-    EXPECT_NO_THROW(f.value());
-  }
-
-  {
-    auto f = makeFuture()
-      .then([] { throw -1; })
-      .onError([&] (int e) { flag(); return makeFuture(); });
-    EXPECT_FLAG();
-    EXPECT_NO_THROW(f.value());
-  }
-
-  // Mutable lambda
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; })
-      .onError([&] (eggs_t& e) mutable { flag(); });
-    EXPECT_FLAG();
-    EXPECT_NO_THROW(f.value());
-  }
-
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; })
-      .onError([&] (eggs_t& e) mutable { flag(); return makeFuture(); });
-    EXPECT_FLAG();
-    EXPECT_NO_THROW(f.value());
-  }
-
-  // No throw
-  {
-    auto f = makeFuture()
-      .then([] { return 42; })
-      .onError([&] (eggs_t& e) { flag(); return -1; });
-    EXPECT_NO_FLAG();
-    EXPECT_EQ(42, f.value());
-  }
-
-  {
-    auto f = makeFuture()
-      .then([] { return 42; })
-      .onError([&] (eggs_t& e) { flag(); return makeFuture<int>(-1); });
-    EXPECT_NO_FLAG();
-    EXPECT_EQ(42, f.value());
-  }
-
-  // Catch different exception
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; })
-      .onError([&] (std::runtime_error& e) { flag(); });
-    EXPECT_NO_FLAG();
-    EXPECT_THROW(f.value(), eggs_t);
-  }
-
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; })
-      .onError([&] (std::runtime_error& e) { flag(); return makeFuture(); });
-    EXPECT_NO_FLAG();
-    EXPECT_THROW(f.value(), eggs_t);
-  }
-
-  // Returned value propagates
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; return 0; })
-      .onError([&] (eggs_t& e) { return 42; });
-    EXPECT_EQ(42, f.value());
-  }
-
-  // Returned future propagates
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; return 0; })
-      .onError([&] (eggs_t& e) { return makeFuture<int>(42); });
-    EXPECT_EQ(42, f.value());
-  }
-
-  // Throw in callback
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; return 0; })
-      .onError([&] (eggs_t& e) { throw e; return -1; });
-    EXPECT_THROW(f.value(), eggs_t);
-  }
-
-  {
-    auto f = makeFuture()
-      .then([] { throw eggs; return 0; })
-      .onError([&] (eggs_t& e) { throw e; return makeFuture<int>(-1); });
-    EXPECT_THROW(f.value(), eggs_t);
-  }
-}
-
-TEST(Future, try) {
-  class A {
-   public:
-    A(int x) : x_(x) {}
-
-    int x() const {
-      return x_;
-    }
-   private:
-    int x_;
-  };
-
-  A a(5);
-  Try<A> t_a(std::move(a));
-
-  Try<void> t_void;
-
-  EXPECT_EQ(5, t_a.value().x());
-}
-
-TEST(Future, special) {
-  EXPECT_FALSE(std::is_copy_constructible<Future<int>>::value);
-  EXPECT_FALSE(std::is_copy_assignable<Future<int>>::value);
-  EXPECT_TRUE(std::is_move_constructible<Future<int>>::value);
-  EXPECT_TRUE(std::is_move_assignable<Future<int>>::value);
-}
-
-TEST(Future, thenTry) {
-  bool flag = false;
-
-  makeFuture<int>(42).then([&](Try<int>&& t) {
-                              flag = true;
-                              EXPECT_EQ(42, t.value());
-                            });
-  EXPECT_TRUE(flag); flag = false;
-
-  makeFuture<int>(42)
-    .then([](Try<int>&& t) { return t.value(); })
-    .then([&](Try<int>&& t) { flag = true; EXPECT_EQ(42, t.value()); });
-  EXPECT_TRUE(flag); flag = false;
-
-  makeFuture().then([&](Try<void>&& t) { flag = true; t.value(); });
-  EXPECT_TRUE(flag); flag = false;
-
-  Promise<void> p;
-  auto f = p.getFuture().then([&](Try<void>&& t) { flag = true; });
-  EXPECT_FALSE(flag);
-  EXPECT_FALSE(f.isReady());
-  p.setValue();
-  EXPECT_TRUE(flag);
-  EXPECT_TRUE(f.isReady());
-}
-
-TEST(Future, thenValue) {
-  bool flag = false;
-  makeFuture<int>(42).then([&](int i){
-    EXPECT_EQ(42, i);
-    flag = true;
-  });
-  EXPECT_TRUE(flag); flag = false;
-
-  makeFuture<int>(42)
-    .then([](int i){ return i; })
-    .then([&](int i) { flag = true; EXPECT_EQ(42, i); });
-  EXPECT_TRUE(flag); flag = false;
-
-  makeFuture().then([&]{
-    flag = true;
-  });
-  EXPECT_TRUE(flag); flag = false;
-
-  auto f = makeFuture<int>(eggs).then([&](int i){});
-  EXPECT_THROW(f.value(), eggs_t);
-
-  f = makeFuture<void>(eggs).then([&]{});
-  EXPECT_THROW(f.value(), eggs_t);
-}
-
-TEST(Future, thenValueFuture) {
-  bool flag = false;
-  makeFuture<int>(42)
-    .then([](int i){ return makeFuture<int>(std::move(i)); })
-    .then([&](Try<int>&& t) { flag = true; EXPECT_EQ(42, t.value()); });
-  EXPECT_TRUE(flag); flag = false;
-
-  makeFuture()
-    .then([]{ return makeFuture(); })
-    .then([&](Try<void>&& t) { flag = true; });
-  EXPECT_TRUE(flag); flag = false;
-}
-
-static string doWorkStatic(Try<string>&& t) {
-  return t.value() + ";static";
-}
-
-TEST(Future, thenFunction) {
-  struct Worker {
-    string doWork(Try<string>&& t) {
-      return t.value() + ";class";
-    }
-    static string doWorkStatic(Try<string>&& t) {
-      return t.value() + ";class-static";
-    }
-  } w;
-
-  auto f = makeFuture<string>("start")
-    .then(doWorkStatic)
-    .then(Worker::doWorkStatic)
-    .then(&w, &Worker::doWork);
-
-  EXPECT_EQ(f.value(), "start;static;class-static;class");
-}
-
-static Future<string> doWorkStaticFuture(Try<string>&& t) {
-  return makeFuture(t.value() + ";static");
-}
-
-TEST(Future, thenFunctionFuture) {
-  struct Worker {
-    Future<string> doWorkFuture(Try<string>&& t) {
-      return makeFuture(t.value() + ";class");
-    }
-    static Future<string> doWorkStaticFuture(Try<string>&& t) {
-      return makeFuture(t.value() + ";class-static");
-    }
-  } w;
-
-  auto f = makeFuture<string>("start")
-    .then(doWorkStaticFuture)
-    .then(Worker::doWorkStaticFuture)
-    .then(&w, &Worker::doWorkFuture);
-
-  EXPECT_EQ(f.value(), "start;static;class-static;class");
-}
-
-TEST(Future, value) {
-  auto f = makeFuture(unique_ptr<int>(new int(42)));
-  auto up = std::move(f.value());
-  EXPECT_EQ(42, *up);
-
-  EXPECT_THROW(makeFuture<int>(eggs).value(), eggs_t);
-}
-
-TEST(Future, isReady) {
-  Promise<int> p;
-  auto f = p.getFuture();
-  EXPECT_FALSE(f.isReady());
-  p.setValue(42);
-  EXPECT_TRUE(f.isReady());
-  }
-
-TEST(Future, futureNotReady) {
-  Promise<int> p;
-  Future<int> f = p.getFuture();
-  EXPECT_THROW(f.value(), eggs_t);
-}
-
-TEST(Future, hasException) {
-  EXPECT_TRUE(makeFuture<int>(eggs).getTry().hasException());
-  EXPECT_FALSE(makeFuture(42).getTry().hasException());
-}
-
-TEST(Future, hasValue) {
-  EXPECT_TRUE(makeFuture(42).getTry().hasValue());
-  EXPECT_FALSE(makeFuture<int>(eggs).getTry().hasValue());
-}
-
-TEST(Future, makeFuture) {
-  EXPECT_TYPE(makeFuture(42), Future<int>);
-  EXPECT_EQ(42, makeFuture(42).value());
-
-  EXPECT_TYPE(makeFuture<float>(42), Future<float>);
-  EXPECT_EQ(42, makeFuture<float>(42).value());
-
-  auto fun = [] { return 42; };
-  EXPECT_TYPE(makeFutureTry(fun), Future<int>);
-  EXPECT_EQ(42, makeFutureTry(fun).value());
-
-  auto failfun = []() -> int { throw eggs; };
-  EXPECT_TYPE(makeFutureTry(failfun), Future<int>);
-  EXPECT_THROW(makeFutureTry(failfun).value(), eggs_t);
-
-  EXPECT_TYPE(makeFuture(), Future<void>);
-}
-
-// Promise
-
-TEST(Promise, special) {
-  EXPECT_FALSE(std::is_copy_constructible<Promise<int>>::value);
-  EXPECT_FALSE(std::is_copy_assignable<Promise<int>>::value);
-  EXPECT_TRUE(std::is_move_constructible<Promise<int>>::value);
-  EXPECT_TRUE(std::is_move_assignable<Promise<int>>::value);
-}
-
-TEST(Promise, getFuture) {
-  Promise<int> p;
-  Future<int> f = p.getFuture();
-  EXPECT_FALSE(f.isReady());
-}
-
-TEST(Promise, setValue) {
-  Promise<int> fund;
-  auto ffund = fund.getFuture();
-  fund.setValue(42);
-  EXPECT_EQ(42, ffund.value());
-
-  struct Foo {
-    string name;
-    int value;
-  };
-
-  Promise<Foo> pod;
-  auto fpod = pod.getFuture();
-  Foo f = {"the answer", 42};
-  pod.setValue(f);
-  Foo f2 = fpod.value();
-  EXPECT_EQ(f.name, f2.name);
-  EXPECT_EQ(f.value, f2.value);
-
-  pod = Promise<Foo>();
-  fpod = pod.getFuture();
-  pod.setValue(std::move(f2));
-  Foo f3 = fpod.value();
-  EXPECT_EQ(f.name, f3.name);
-  EXPECT_EQ(f.value, f3.value);
-
-  Promise<unique_ptr<int>> mov;
-  auto fmov = mov.getFuture();
-  mov.setValue(unique_ptr<int>(new int(42)));
-  unique_ptr<int> ptr = std::move(fmov.value());
-  EXPECT_EQ(42, *ptr);
-
-  Promise<void> v;
-  auto fv = v.getFuture();
-  v.setValue();
-  EXPECT_TRUE(fv.isReady());
-}
-
-TEST(Promise, setException) {
-  {
-    Promise<void> p;
-    auto f = p.getFuture();
-    p.setException(eggs);
-    EXPECT_THROW(f.value(), eggs_t);
-  }
-  {
-    Promise<void> p;
-    auto f = p.getFuture();
-    try {
-      throw eggs;
-    } catch (...) {
-      p.setException(exception_wrapper(std::current_exception()));
-    }
-    EXPECT_THROW(f.value(), eggs_t);
-  }
-}
-
-TEST(Promise, fulfil) {
-  {
-    Promise<int> p;
-    auto f = p.getFuture();
-    p.fulfil([] { return 42; });
-    EXPECT_EQ(42, f.value());
-  }
-  {
-    Promise<int> p;
-    auto f = p.getFuture();
-    p.fulfil([]() -> int { throw eggs; });
-    EXPECT_THROW(f.value(), eggs_t);
-  }
-}
-
-TEST(Future, finish) {
-  auto x = std::make_shared<int>(0);
-  {
-    Promise<int> p;
-    auto f = p.getFuture().then([x](Try<int>&& t) { *x = t.value(); });
-
-    // The callback hasn't executed
-    EXPECT_EQ(0, *x);
-
-    // The callback has a reference to x
-    EXPECT_EQ(2, x.use_count());
-
-    p.setValue(42);
-
-    // the callback has executed
-    EXPECT_EQ(42, *x);
-  }
-  // the callback has been destructed
-  // and has released its reference to x
-  EXPECT_EQ(1, x.use_count());
-}
-
-TEST(Future, unwrap) {
-  Promise<int> a;
-  Promise<int> b;
-
-  auto fa = a.getFuture();
-  auto fb = b.getFuture();
-
-  bool flag1 = false;
-  bool flag2 = false;
-
-  // do a, then do b, and get the result of a + b.
-  Future<int> f = fa.then([&](Try<int>&& ta) {
-    auto va = ta.value();
-    flag1 = true;
-    return fb.then([va, &flag2](Try<int>&& tb) {
-      flag2 = true;
-      return va + tb.value();
-    });
-  });
-
-  EXPECT_FALSE(flag1);
-  EXPECT_FALSE(flag2);
-  EXPECT_FALSE(f.isReady());
-
-  a.setValue(3);
-  EXPECT_TRUE(flag1);
-  EXPECT_FALSE(flag2);
-  EXPECT_FALSE(f.isReady());
-
-  b.setValue(4);
-  EXPECT_TRUE(flag1);
-  EXPECT_TRUE(flag2);
-  EXPECT_EQ(7, f.value());
-}
-
-TEST(Future, whenAll) {
-  // returns a vector variant
-  {
-    vector<Promise<int>> promises(10);
-    vector<Future<int>> futures;
-
-    for (auto& p : promises)
-      futures.push_back(p.getFuture());
-
-    auto allf = whenAll(futures.begin(), futures.end());
-
-    random_shuffle(promises.begin(), promises.end());
-    for (auto& p : promises) {
-      EXPECT_FALSE(allf.isReady());
-      p.setValue(42);
-    }
-
-    EXPECT_TRUE(allf.isReady());
-    auto& results = allf.value();
-    for (auto& t : results) {
-      EXPECT_EQ(42, t.value());
-    }
-  }
-
-  // check error semantics
-  {
-    vector<Promise<int>> promises(4);
-    vector<Future<int>> futures;
-
-    for (auto& p : promises)
-      futures.push_back(p.getFuture());
-
-    auto allf = whenAll(futures.begin(), futures.end());
-
-
-    promises[0].setValue(42);
-    promises[1].setException(eggs);
-
-    EXPECT_FALSE(allf.isReady());
-
-    promises[2].setValue(42);
-
-    EXPECT_FALSE(allf.isReady());
-
-    promises[3].setException(eggs);
-
-    EXPECT_TRUE(allf.isReady());
-    EXPECT_FALSE(allf.getTry().hasException());
-
-    auto& results = allf.value();
-    EXPECT_EQ(42, results[0].value());
-    EXPECT_TRUE(results[1].hasException());
-    EXPECT_EQ(42, results[2].value());
-    EXPECT_TRUE(results[3].hasException());
-  }
-
-  // check that futures are ready in then()
-  {
-    vector<Promise<void>> promises(10);
-    vector<Future<void>> futures;
-
-    for (auto& p : promises)
-      futures.push_back(p.getFuture());
-
-    auto allf = whenAll(futures.begin(), futures.end())
-      .then([](Try<vector<Try<void>>>&& ts) {
-        for (auto& f : ts.value())
-          f.value();
-      });
-
-    random_shuffle(promises.begin(), promises.end());
-    for (auto& p : promises)
-      p.setValue();
-    EXPECT_TRUE(allf.isReady());
-  }
-}
-
-
-TEST(Future, whenAny) {
-  {
-    vector<Promise<int>> promises(10);
-    vector<Future<int>> futures;
-
-    for (auto& p : promises)
-      futures.push_back(p.getFuture());
-
-    for (auto& f : futures) {
-      EXPECT_FALSE(f.isReady());
-    }
-
-    auto anyf = whenAny(futures.begin(), futures.end());
-
-    /* futures were moved in, so these are invalid now */
-    EXPECT_FALSE(anyf.isReady());
-
-    promises[7].setValue(42);
-    EXPECT_TRUE(anyf.isReady());
-    auto& idx_fut = anyf.value();
-
-    auto i = idx_fut.first;
-    EXPECT_EQ(7, i);
-
-    auto& f = idx_fut.second;
-    EXPECT_EQ(42, f.value());
-  }
-
-  // error
-  {
-    vector<Promise<void>> promises(10);
-    vector<Future<void>> futures;
-
-    for (auto& p : promises)
-      futures.push_back(p.getFuture());
-
-    for (auto& f : futures) {
-      EXPECT_FALSE(f.isReady());
-    }
-
-    auto anyf = whenAny(futures.begin(), futures.end());
-
-    EXPECT_FALSE(anyf.isReady());
-
-    promises[3].setException(eggs);
-    EXPECT_TRUE(anyf.isReady());
-    EXPECT_TRUE(anyf.value().second.hasException());
-  }
-
-  // then()
-  {
-    vector<Promise<int>> promises(10);
-    vector<Future<int>> futures;
-
-    for (auto& p : promises)
-      futures.push_back(p.getFuture());
-
-    auto anyf = whenAny(futures.begin(), futures.end())
-      .then([](Try<pair<size_t, Try<int>>>&& f) {
-        EXPECT_EQ(42, f.value().second.value());
-      });
-
-    promises[3].setValue(42);
-    EXPECT_TRUE(anyf.isReady());
-  }
-}
-
-
-TEST(when, already_completed) {
-  {
-    vector<Future<void>> fs;
-    for (int i = 0; i < 10; i++)
-      fs.push_back(makeFuture());
-
-    whenAll(fs.begin(), fs.end())
-      .then([&](Try<vector<Try<void>>>&& t) {
-        EXPECT_EQ(fs.size(), t.value().size());
-      });
-  }
-  {
-    vector<Future<int>> fs;
-    for (int i = 0; i < 10; i++)
-      fs.push_back(makeFuture(i));
-
-    whenAny(fs.begin(), fs.end())
-      .then([&](Try<pair<size_t, Try<int>>>&& t) {
-        auto& p = t.value();
-        EXPECT_EQ(p.first, p.second.value());
-      });
-  }
-}
-
-TEST(when, whenN) {
-  vector<Promise<void>> promises(10);
-  vector<Future<void>> futures;
-
-  for (auto& p : promises)
-    futures.push_back(p.getFuture());
-
-  bool flag = false;
-  size_t n = 3;
-  whenN(futures.begin(), futures.end(), n)
-    .then([&](Try<vector<pair<size_t, Try<void>>>>&& t) {
-      flag = true;
-      auto v = t.value();
-      EXPECT_EQ(n, v.size());
-      for (auto& tt : v)
-        EXPECT_TRUE(tt.second.hasValue());
-    });
-
-  promises[0].setValue();
-  EXPECT_FALSE(flag);
-  promises[1].setValue();
-  EXPECT_FALSE(flag);
-  promises[2].setValue();
-  EXPECT_TRUE(flag);
-}
-
-/* Ensure that we can compile when_{all,any} with folly::small_vector */
-TEST(when, small_vector) {
-
-  static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<void>),
-                "Futures should not be trivially copyable");
-  static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<int>),
-                "Futures should not be trivially copyable");
-
-  using folly::small_vector;
-  {
-    small_vector<Future<void>> futures;
-
-    for (int i = 0; i < 10; i++)
-      futures.push_back(makeFuture());
-
-    auto anyf = whenAny(futures.begin(), futures.end());
-  }
-
-  {
-    small_vector<Future<void>> futures;
-
-    for (int i = 0; i < 10; i++)
-      futures.push_back(makeFuture());
-
-    auto allf = whenAll(futures.begin(), futures.end());
-  }
-}
-
-TEST(Future, whenAllVariadic) {
-  Promise<bool> pb;
-  Promise<int> pi;
-  Future<bool> fb = pb.getFuture();
-  Future<int> fi = pi.getFuture();
-  bool flag = false;
-  whenAll(std::move(fb), std::move(fi))
-    .then([&](Try<std::tuple<Try<bool>, Try<int>>>&& t) {
-      flag = true;
-      EXPECT_TRUE(t.hasValue());
-      EXPECT_TRUE(std::get<0>(t.value()).hasValue());
-      EXPECT_EQ(std::get<0>(t.value()).value(), true);
-      EXPECT_TRUE(std::get<1>(t.value()).hasValue());
-      EXPECT_EQ(std::get<1>(t.value()).value(), 42);
-    });
-  pb.setValue(true);
-  EXPECT_FALSE(flag);
-  pi.setValue(42);
-  EXPECT_TRUE(flag);
-}
-
-TEST(Future, whenAllVariadicReferences) {
-  Promise<bool> pb;
-  Promise<int> pi;
-  Future<bool> fb = pb.getFuture();
-  Future<int> fi = pi.getFuture();
-  bool flag = false;
-  whenAll(fb, fi)
-    .then([&](Try<std::tuple<Try<bool>, Try<int>>>&& t) {
-      flag = true;
-      EXPECT_TRUE(t.hasValue());
-      EXPECT_TRUE(std::get<0>(t.value()).hasValue());
-      EXPECT_EQ(std::get<0>(t.value()).value(), true);
-      EXPECT_TRUE(std::get<1>(t.value()).hasValue());
-      EXPECT_EQ(std::get<1>(t.value()).value(), 42);
-    });
-  pb.setValue(true);
-  EXPECT_FALSE(flag);
-  pi.setValue(42);
-  EXPECT_TRUE(flag);
-}
-
-TEST(Future, whenAll_none) {
-  vector<Future<int>> fs;
-  auto f = whenAll(fs.begin(), fs.end());
-  EXPECT_TRUE(f.isReady());
-}
-
-TEST(Future, throwCaughtInImmediateThen) {
-  // Neither of these should throw "Promise already satisfied"
-  makeFuture().then(
-    [=](Try<void>&&) -> int { throw std::exception(); });
-  makeFuture().then(
-    [=](Try<void>&&) -> Future<int> { throw std::exception(); });
-}
-
-TEST(Future, throwIfFailed) {
-  makeFuture<void>(eggs)
-    .then([=](Try<void>&& t) {
-      EXPECT_THROW(t.throwIfFailed(), eggs_t);
-    });
-  makeFuture()
-    .then([=](Try<void>&& t) {
-      EXPECT_NO_THROW(t.throwIfFailed());
-    });
-
-  makeFuture<int>(eggs)
-    .then([=](Try<int>&& t) {
-      EXPECT_THROW(t.throwIfFailed(), eggs_t);
-    });
-  makeFuture<int>(42)
-    .then([=](Try<int>&& t) {
-      EXPECT_NO_THROW(t.throwIfFailed());
-    });
-}
-
-TEST(Future, waitWithSemaphoreImmediate) {
-  waitWithSemaphore(makeFuture());
-  auto done = waitWithSemaphore(makeFuture(42)).value();
-  EXPECT_EQ(42, done);
-
-  vector<int> v{1,2,3};
-  auto done_v = waitWithSemaphore(makeFuture(v)).value();
-  EXPECT_EQ(v.size(), done_v.size());
-  EXPECT_EQ(v, done_v);
-
-  vector<Future<void>> v_f;
-  v_f.push_back(makeFuture());
-  v_f.push_back(makeFuture());
-  auto done_v_f = waitWithSemaphore(whenAll(v_f.begin(), v_f.end())).value();
-  EXPECT_EQ(2, done_v_f.size());
-
-  vector<Future<bool>> v_fb;
-  v_fb.push_back(makeFuture(true));
-  v_fb.push_back(makeFuture(false));
-  auto fut = whenAll(v_fb.begin(), v_fb.end());
-  auto done_v_fb = std::move(waitWithSemaphore(std::move(fut)).value());
-  EXPECT_EQ(2, done_v_fb.size());
-}
-
-TEST(Future, waitWithSemaphore) {
-  Promise<int> p;
-  Future<int> f = p.getFuture();
-  std::atomic<bool> flag{false};
-  std::atomic<int> result{1};
-  std::atomic<std::thread::id> id;
-
-  std::thread t([&](Future<int>&& tf){
-      auto n = tf.then([&](Try<int> && t) {
-          id = std::this_thread::get_id();
-          return t.value();
-        });
-      flag = true;
-      result.store(waitWithSemaphore(std::move(n)).value());
-    },
-    std::move(f)
-    );
-  while(!flag){}
-  EXPECT_EQ(result.load(), 1);
-  p.setValue(42);
-  t.join();
-  // validate that the callback ended up executing in this thread, which
-  // is more to ensure that this test actually tests what it should
-  EXPECT_EQ(id, std::this_thread::get_id());
-  EXPECT_EQ(result.load(), 42);
-}
-
-TEST(Future, waitWithSemaphoreForTime) {
- {
-  Promise<int> p;
-  Future<int> f = p.getFuture();
-  auto t = waitWithSemaphore(std::move(f),
-    std::chrono::microseconds(1));
-  EXPECT_FALSE(t.isReady());
-  p.setValue(1);
-  EXPECT_TRUE(t.isReady());
- }
- {
-  Promise<int> p;
-  Future<int> f = p.getFuture();
-  p.setValue(1);
-  auto t = waitWithSemaphore(std::move(f),
-    std::chrono::milliseconds(1));
-  EXPECT_TRUE(t.isReady());
- }
- {
-  vector<Future<bool>> v_fb;
-  v_fb.push_back(makeFuture(true));
-  v_fb.push_back(makeFuture(false));
-  auto f = whenAll(v_fb.begin(), v_fb.end());
-  auto t = waitWithSemaphore(std::move(f),
-    std::chrono::milliseconds(1));
-  EXPECT_TRUE(t.isReady());
-  EXPECT_EQ(2, t.value().size());
- }
- {
-  vector<Future<bool>> v_fb;
-  Promise<bool> p1;
-  Promise<bool> p2;
-  v_fb.push_back(p1.getFuture());
-  v_fb.push_back(p2.getFuture());
-  auto f = whenAll(v_fb.begin(), v_fb.end());
-  auto t = waitWithSemaphore(std::move(f),
-    std::chrono::milliseconds(1));
-  EXPECT_FALSE(t.isReady());
-  p1.setValue(true);
-  EXPECT_FALSE(t.isReady());
-  p2.setValue(true);
-  EXPECT_TRUE(t.isReady());
- }
- {
-  auto t = waitWithSemaphore(makeFuture(),
-    std::chrono::milliseconds(1));
-  EXPECT_TRUE(t.isReady());
- }
-}
-
-TEST(Future, callbackAfterActivate) {
-  Promise<void> p;
-  auto f = p.getFuture();
-  f.deactivate();
-
-  size_t count = 0;
-  f.then([&](Try<void>&&) { count++; });
-
-  p.setValue();
-  EXPECT_EQ(0, count);
-
-  f.activate();
-  EXPECT_EQ(1, count);
-}
-
-TEST(Future, activateOnDestruct) {
-  auto f = std::make_shared<Future<void>>(makeFuture());
-  f->deactivate();
-
-  size_t count = 0;
-  f->then([&](Try<void>&&) { count++; });
-  EXPECT_EQ(0, count);
-
-  f.reset();
-  EXPECT_EQ(1, count);
-}
-
-TEST(Future, viaActsCold) {
-  ManualExecutor x;
-  size_t count = 0;
-
-  auto fv = via(&x);
-  fv.then([&](Try<void>&&) { count++; });
-
-  EXPECT_EQ(0, count);
-
-  fv.activate();
-
-  EXPECT_EQ(1, x.run());
-  EXPECT_EQ(1, count);
-}
-
-TEST(Future, viaIsCold) {
-  ManualExecutor x;
-  EXPECT_FALSE(via(&x).isActive());
-}
-
-TEST(Future, viaRaces) {
-  ManualExecutor x;
-  Promise<void> p;
-  auto tid = std::this_thread::get_id();
-  bool done = false;
-
-  std::thread t1([&] {
-    p.getFuture()
-      .via(&x)
-      .then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
-      .then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
-      .then([&](Try<void>&&) { done = true; });
-  });
-
-  std::thread t2([&] {
-    p.setValue();
-  });
-
-  while (!done) x.run();
-  t1.join();
-  t2.join();
-}
-
-// TODO(#4920689)
-TEST(Future, viaRaces_2stage) {
-  ManualExecutor x;
-  Promise<void> p;
-  auto tid = std::this_thread::get_id();
-  bool done = false;
-
-  std::thread t1([&] {
-    auto f2 = p.getFuture().via(&x);
-    f2.then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
-      .then([&](Try<void>&&) { EXPECT_EQ(tid, std::this_thread::get_id()); })
-      .then([&](Try<void>&&) { done = true; });
-
-    // the bug was in the promise being fulfilled before f2 is reactivated. we
-    // could sleep, but yielding should cause this to fail with reasonable
-    // probability
-    std::this_thread::yield();
-    f2.activate();
-  });
-
-  std::thread t2([&] {
-    p.setValue();
-  });
-
-  while (!done) x.run();
-  t1.join();
-  t2.join();
-}
-
-TEST(Future, getFuture_after_setValue) {
-  Promise<int> p;
-  p.setValue(42);
-  EXPECT_EQ(42, p.getFuture().value());
-}
-
-TEST(Future, getFuture_after_setException) {
-  Promise<void> p;
-  p.fulfil([]() -> void { throw std::logic_error("foo"); });
-  EXPECT_THROW(p.getFuture().value(), std::logic_error);
-}
-
-TEST(Future, detachRace) {
-  // Task #5438209
-  // This test is designed to detect a race that was in Core::detachOne()
-  // where detached_ was incremented and then tested, and that
-  // allowed a race where both Promise and Future would think they were the
-  // second and both try to delete. This showed up at scale but was very
-  // difficult to reliably repro in a test. As it is, this only fails about
-  // once in every 1,000 executions. Doing this 1,000 times is going to make a
-  // slow test so I won't do that but if it ever fails, take it seriously, and
-  // run the test binary with "--gtest_repeat=10000 --gtest_filter=*detachRace"
-  // (Don't forget to enable ASAN)
-  auto p = folly::make_unique<Promise<bool>>();
-  auto f = folly::make_unique<Future<bool>>(p->getFuture());
-  folly::Baton<> baton;
-  std::thread t1([&]{
-    baton.post();
-    p.reset();
-  });
-  baton.wait();
-  f.reset();
-  t1.join();
-}
-
-class TestData : public RequestData {
- public:
-  explicit TestData(int data) : data_(data) {}
-  virtual ~TestData() {}
-  int data_;
-};
-
-TEST(Future, context) {
-
-  // Start a new context
-  RequestContext::create();
-
-  EXPECT_EQ(nullptr, RequestContext::get()->getContextData("test"));
-
-  // Set some test data
-  RequestContext::get()->setContextData(
-    "test",
-    std::unique_ptr<TestData>(new TestData(10)));
-
-  // Start a future
-  Promise<void> p;
-  auto future = p.getFuture().then([&]{
-    // Check that the context followed the future
-    EXPECT_TRUE(RequestContext::get() != nullptr);
-    auto a = dynamic_cast<TestData*>(
-      RequestContext::get()->getContextData("test"));
-    auto data = a->data_;
-    EXPECT_EQ(10, data);
-  });
-
-  // Clear the context
-  RequestContext::setContext(nullptr);
-
-  EXPECT_EQ(nullptr, RequestContext::get()->getContextData("test"));
-
-  // Fulfil the promise
-  p.setValue();
-}
-
-
-// This only fails about 1 in 1k times when the bug is present :(
-TEST(Future, t5506504) {
-  ThreadExecutor x;
-
-  auto fn = [&x]{
-    auto promises = std::make_shared<vector<Promise<void>>>(4);
-    vector<Future<void>> futures;
-
-    for (auto& p : *promises) {
-      futures.emplace_back(
-        p.getFuture()
-        .via(&x)
-        .then([](Try<void>&&){}));
-    }
-
-    x.waitForStartup();
-    x.add([promises]{
-      for (auto& p : *promises) p.setValue();
-    });
-
-    return whenAll(futures.begin(), futures.end());
-  };
-
-  waitWithSemaphore(fn());
-}
-
-// Test of handling of a circular dependency. It's never recommended
-// to have one because of possible memory leaks. Here we test that
-// we can handle freeing of the Future while it is running.
-TEST(Future, CircularDependencySharedPtrSelfReset) {
-  Promise<int64_t> promise;
-  auto ptr = std::make_shared<Future<int64_t>>(promise.getFuture());
-
-  ptr->then(
-    [ptr] (folly::wangle::Try<int64_t>&& uid) mutable {
-      EXPECT_EQ(1, ptr.use_count());
-
-      // Leaving no references to ourselves.
-      ptr.reset();
-      EXPECT_EQ(0, ptr.use_count());
-    }
-  );
-
-  EXPECT_EQ(2, ptr.use_count());
-
-  ptr.reset();
-
-  promise.fulfil([]{return 1l;});
-}
diff --git a/folly/wangle/futures/test/Interrupts.cpp b/folly/wangle/futures/test/Interrupts.cpp
deleted file mode 100644 (file)
index 9204efa..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include <folly/wangle/futures/Future.h>
-#include <folly/wangle/futures/Promise.h>
-
-using namespace folly::wangle;
-using folly::exception_wrapper;
-
-TEST(Interrupts, raise) {
-  std::runtime_error eggs("eggs");
-  Promise<void> p;
-  p.setInterruptHandler([&](const exception_wrapper& e) {
-    EXPECT_THROW(e.throwException(), decltype(eggs));
-  });
-  p.getFuture().raise(eggs);
-}
-
-TEST(Interrupts, cancel) {
-  Promise<void> p;
-  p.setInterruptHandler([&](const exception_wrapper& e) {
-    EXPECT_THROW(e.throwException(), FutureCancellation);
-  });
-  p.getFuture().cancel();
-}
-
-TEST(Interrupts, handleThenInterrupt) {
-  Promise<int> p;
-  bool flag = false;
-  p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
-  p.getFuture().cancel();
-  EXPECT_TRUE(flag);
-}
-
-TEST(Interrupts, interruptThenHandle) {
-  Promise<int> p;
-  bool flag = false;
-  p.getFuture().cancel();
-  p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
-  EXPECT_TRUE(flag);
-}
-
-TEST(Interrupts, interruptAfterFulfilNoop) {
-  Promise<void> p;
-  bool flag = false;
-  p.setInterruptHandler([&](const exception_wrapper& e) { flag = true; });
-  p.setValue();
-  p.getFuture().cancel();
-  EXPECT_FALSE(flag);
-}
-
-TEST(Interrupts, secondInterruptNoop) {
-  Promise<void> p;
-  int count = 0;
-  p.setInterruptHandler([&](const exception_wrapper& e) { count++; });
-  auto f = p.getFuture();
-  f.cancel();
-  f.cancel();
-  EXPECT_EQ(1, count);
-}
diff --git a/folly/wangle/futures/test/Thens.cpp b/folly/wangle/futures/test/Thens.cpp
deleted file mode 100644 (file)
index 2ebbf48..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// This file is @generated by thens.rb. Do not edit directly.
-
-// TODO: fails to compile with clang:dev.  See task #4412111
-#ifndef __clang__
-
-#include <folly/wangle/futures/test/Thens.h>
-
-TEST(Future, thenVariants) {
-  SomeClass anObject;
-  folly::Executor* anExecutor;
-
-  {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>&&>);}
-  {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&&>);}
-  {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, Try<A>&&>);}
-  {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&&>());}
-  {Future<B> f = someFuture<A>().then([&](Try<A>&&){return someFuture<B>();});}
-  {Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&&>);}
-  {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&&>);}
-  {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, A&&>);}
-  {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A&&>());}
-  {Future<B> f = someFuture<A>().then([&](A&&){return someFuture<B>();});}
-  {Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&&>);}
-  {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&&>);}
-  {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, Try<A>&&>);}
-  {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&&>());}
-  {Future<B> f = someFuture<A>().then([&](Try<A>&&){return B();});}
-  {Future<B> f = someFuture<A>().then(&aFunction<B, A&&>);}
-  {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&&>);}
-  {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, A&&>);}
-  {Future<B> f = someFuture<A>().then(aStdFunction<B, A&&>());}
-  {Future<B> f = someFuture<A>().then([&](A&&){return B();});}
-}
-
-#endif
diff --git a/folly/wangle/futures/test/Thens.h b/folly/wangle/futures/test/Thens.h
deleted file mode 100644 (file)
index d039848..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-#include <gtest/gtest.h>
-#include <memory>
-#include <folly/wangle/futures/Future.h>
-#include <folly/Executor.h>
-
-using namespace folly::wangle;
-using namespace std;
-using namespace testing;
-
-typedef unique_ptr<int> A;
-struct B {};
-
-template <class T>
-using EnableIfFuture = typename std::enable_if<isFuture<T>::value>::type;
-
-template <class T>
-using EnableUnlessFuture = typename std::enable_if<!isFuture<T>::value>::type;
-
-template <class T>
-Future<T> someFuture() {
-  return makeFuture(T());
-}
-
-template <class Ret, class... Params, typename = void>
-Ret aFunction(Params...);
-
-template <class Ret, class... Params>
-typename std::enable_if<isFuture<Ret>::value, Ret>::type
-aFunction(Params...) {
-  typedef typename Ret::value_type T;
-  return makeFuture(T());
-}
-
-template <class Ret, class... Params>
-typename std::enable_if<!isFuture<Ret>::value, Ret>::type
-aFunction(Params...) {
-  return Ret();
-}
-
-template <class Ret, class... Params>
-std::function<Ret(Params...)>
-aStdFunction(
-    typename std::enable_if<!isFuture<Ret>::value, bool>::type = false) {
-  return [](Params...) -> Ret { return Ret(); };
-}
-
-template <class Ret, class... Params>
-std::function<Ret(Params...)>
-aStdFunction(typename std::enable_if<isFuture<Ret>::value, bool>::type = true) {
-  typedef typename Ret::value_type T;
-  return [](Params...) -> Future<T> { return makeFuture(T()); };
-}
-
-class SomeClass {
-  B b;
-public:
-  template <class Ret, class... Params>
-  static Ret aStaticMethod(Params...);
-
-  template <class Ret, class... Params>
-  static
-  typename std::enable_if<!isFuture<Ret>::value, Ret>::type
-  aStaticMethod(Params...) {
-    return Ret();
-  }
-
-  template <class Ret, class... Params>
-  static
-  typename std::enable_if<isFuture<Ret>::value, Ret>::type
-  aStaticMethod(Params...) {
-    typedef typename Ret::value_type T;
-    return makeFuture(T());
-  }
-
-  template <class Ret, class... Params>
-  Ret aMethod(Params...);
-
-  template <class Ret, class... Params>
-  typename std::enable_if<!isFuture<Ret>::value, Ret>::type
-  aMethod(Params...) {
-    return Ret();
-  }
-
-  template <class Ret, class... Params>
-  typename std::enable_if<isFuture<Ret>::value, Ret>::type
-  aMethod(Params...) {
-    typedef typename Ret::value_type T;
-    return makeFuture(T());
-  }
-};
diff --git a/folly/wangle/futures/test/TimekeeperTest.cpp b/folly/wangle/futures/test/TimekeeperTest.cpp
deleted file mode 100644 (file)
index 49f8b0c..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <gtest/gtest.h>
-
-#include <folly/wangle/futures/Timekeeper.h>
-#include <unistd.h>
-
-using namespace folly::wangle;
-using namespace std::chrono;
-using folly::wangle::Timekeeper;
-using Duration = folly::wangle::Duration;
-
-std::chrono::milliseconds const one_ms(1);
-std::chrono::milliseconds const awhile(10);
-
-std::chrono::steady_clock::time_point now() {
-  return std::chrono::steady_clock::now();
-}
-
-struct TimekeeperFixture : public testing::Test {
-  TimekeeperFixture() :
-    timeLord_(folly::wangle::detail::getTimekeeperSingleton())
-  {}
-
-  Timekeeper* timeLord_;
-};
-
-TEST_F(TimekeeperFixture, after) {
-  Duration waited(0);
-
-  auto t1 = now();
-  auto f = timeLord_->after(awhile);
-  EXPECT_FALSE(f.isReady());
-  f.get();
-  auto t2 = now();
-
-  EXPECT_GE(t2 - t1, awhile);
-}
-
-TEST(Timekeeper, futureGet) {
-  Promise<int> p;
-  std::thread([&]{ p.setValue(42); }).detach();
-  EXPECT_EQ(42, p.getFuture().get());
-}
-
-TEST(Timekeeper, futureGetBeforeTimeout) {
-  Promise<int> p;
-  auto t = std::thread([&]{ p.setValue(42); });
-  // Technically this is a race and if the test server is REALLY overloaded
-  // and it takes more than a second to do that thread it could be flaky. But
-  // I want a low timeout (in human terms) so if this regresses and someone
-  // runs it by hand they're not sitting there forever wondering why it's
-  // blocked, and get a useful error message instead. If it does get flaky,
-  // empirically increase the timeout to the point where it's very improbable.
-  EXPECT_EQ(42, p.getFuture().get(seconds(2)));
-  t.join();
-}
-
-TEST(Timekeeper, futureGetTimeout) {
-  Promise<int> p;
-  EXPECT_THROW(p.getFuture().get(Duration(1)), folly::wangle::TimedOut);
-}
-
-TEST(Timekeeper, futureSleep) {
-  auto t1 = now();
-  futures::sleep(one_ms).get();
-  EXPECT_GE(now() - t1, one_ms);
-}
-
-TEST(Timekeeper, futureDelayed) {
-  auto t1 = now();
-  auto dur = makeFuture()
-    .delayed(one_ms)
-    .then([=]{ return now() - t1; })
-    .get();
-
-  EXPECT_GE(dur, one_ms);
-}
-
-TEST(Timekeeper, futureWithinThrows) {
-  Promise<int> p;
-  auto f = p.getFuture()
-    .within(one_ms)
-    .onError([](TimedOut&) { return -1; });
-
-  EXPECT_EQ(-1, f.get());
-}
-
-TEST(Timekeeper, futureWithinAlreadyComplete) {
-  auto f = makeFuture(42)
-    .within(one_ms)
-    .onError([&](TimedOut&){ return -1; });
-
-  EXPECT_EQ(42, f.get());
-}
-
-TEST(Timekeeper, futureWithinFinishesInTime) {
-  Promise<int> p;
-  auto f = p.getFuture()
-    .within(std::chrono::minutes(1))
-    .onError([&](TimedOut&){ return -1; });
-  p.setValue(42);
-
-  EXPECT_EQ(42, f.get());
-}
-
-TEST(Timekeeper, futureWithinVoidSpecialization) {
-  makeFuture().within(one_ms);
-}
-
-TEST(Timekeeper, futureWithinException) {
-  Promise<void> p;
-  auto f = p.getFuture().within(awhile, std::runtime_error("expected"));
-  EXPECT_THROW(f.get(), std::runtime_error);
-}
diff --git a/folly/wangle/futures/test/Try.cpp b/folly/wangle/futures/test/Try.cpp
deleted file mode 100644 (file)
index 9b2f4f7..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include <folly/Memory.h>
-#include <folly/wangle/futures/Try.h>
-
-using namespace folly::wangle;
-
-TEST(Try, makeTryFunction) {
-  auto func = []() {
-    return folly::make_unique<int>(1);
-  };
-
-  auto result = makeTryFunction(func);
-  EXPECT_TRUE(result.hasValue());
-  EXPECT_EQ(*result.value(), 1);
-}
-
-TEST(Try, makeTryFunctionThrow) {
-  auto func = []() {
-    throw std::runtime_error("Runtime");
-    return folly::make_unique<int>(1);
-  };
-
-  auto result = makeTryFunction(func);
-  EXPECT_TRUE(result.hasException<std::runtime_error>());
-}
-
-TEST(Try, makeTryFunctionVoid) {
-  auto func = []() {
-    return;
-  };
-
-  auto result = makeTryFunction(func);
-  EXPECT_TRUE(result.hasValue());
-}
-
-TEST(Try, makeTryFunctionVoidThrow) {
-  auto func = []() {
-    throw std::runtime_error("Runtime");
-    return;
-  };
-
-  auto result = makeTryFunction(func);
-  EXPECT_TRUE(result.hasException<std::runtime_error>());
-}
diff --git a/folly/wangle/futures/test/ViaTest.cpp b/folly/wangle/futures/test/ViaTest.cpp
deleted file mode 100644 (file)
index 80765ff..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-#include <thread>
-
-#include <folly/wangle/futures/Future.h>
-#include <folly/wangle/futures/InlineExecutor.h>
-#include <folly/wangle/futures/ManualExecutor.h>
-
-using namespace folly::wangle;
-
-struct ManualWaiter {
-  explicit ManualWaiter(std::shared_ptr<ManualExecutor> ex) : ex(ex) {}
-
-  void makeProgress() {
-    ex->wait();
-    ex->run();
-  }
-
-  std::shared_ptr<ManualExecutor> ex;
-};
-
-struct ViaFixture : public testing::Test {
-  ViaFixture() :
-    westExecutor(new ManualExecutor),
-    eastExecutor(new ManualExecutor),
-    waiter(new ManualWaiter(westExecutor)),
-    done(false)
-  {
-    t = std::thread([=] {
-      ManualWaiter eastWaiter(eastExecutor);
-      while (!done)
-        eastWaiter.makeProgress();
-      });
-  }
-
-  ~ViaFixture() {
-    done = true;
-    eastExecutor->add([=]() { });
-    t.join();
-  }
-
-  void addAsync(int a, int b, std::function<void(int&&)>&& cob) {
-    eastExecutor->add([=]() {
-      cob(a + b);
-    });
-  }
-
-  std::shared_ptr<ManualExecutor> westExecutor;
-  std::shared_ptr<ManualExecutor> eastExecutor;
-  std::shared_ptr<ManualWaiter> waiter;
-  InlineExecutor inlineExecutor;
-  bool done;
-  std::thread t;
-};
-
-TEST(Via, exception_on_launch) {
-  auto future = makeFuture<int>(std::runtime_error("E"));
-  EXPECT_THROW(future.value(), std::runtime_error);
-}
-
-TEST(Via, then_value) {
-  auto future = makeFuture(std::move(1))
-    .then([](Try<int>&& t) {
-      return t.value() == 1;
-    })
-    ;
-
-  EXPECT_TRUE(future.value());
-}
-
-TEST(Via, then_future) {
-  auto future = makeFuture(1)
-    .then([](Try<int>&& t) {
-      return makeFuture(t.value() == 1);
-    })
-    ;
-  EXPECT_TRUE(future.value());
-}
-
-static Future<std::string> doWorkStatic(Try<std::string>&& t) {
-  return makeFuture(t.value() + ";static");
-}
-
-TEST(Via, then_function) {
-  struct Worker {
-    Future<std::string> doWork(Try<std::string>&& t) {
-      return makeFuture(t.value() + ";class");
-    }
-    static Future<std::string> doWorkStatic(Try<std::string>&& t) {
-      return makeFuture(t.value() + ";class-static");
-    }
-  } w;
-
-  auto f = makeFuture(std::string("start"))
-    .then(doWorkStatic)
-    .then(Worker::doWorkStatic)
-    .then(&w, &Worker::doWork)
-    ;
-
-  EXPECT_EQ(f.value(), "start;static;class-static;class");
-}
-
-TEST_F(ViaFixture, deactivateChain) {
-  bool flag = false;
-  auto f = makeFuture().deactivate();
-  EXPECT_FALSE(f.isActive());
-  auto f2 = f.then([&](Try<void>){ flag = true; });
-  EXPECT_FALSE(flag);
-}
-
-TEST_F(ViaFixture, deactivateActivateChain) {
-  bool flag = false;
-  // you can do this all day long with temporaries.
-  auto f1 = makeFuture().deactivate().activate().deactivate();
-  // Chaining on activate/deactivate requires an rvalue, so you have to move
-  // one of these two ways (if you're not using a temporary).
-  auto f2 = std::move(f1).activate();
-  f2.deactivate();
-  auto f3 = std::move(f2.activate());
-  f3.then([&](Try<void>){ flag = true; });
-  EXPECT_TRUE(flag);
-}
-
-TEST_F(ViaFixture, thread_hops) {
-  auto westThreadId = std::this_thread::get_id();
-  auto f = via(eastExecutor.get()).then([=](Try<void>&& t) {
-    EXPECT_NE(std::this_thread::get_id(), westThreadId);
-    return makeFuture<int>(1);
-  }).via(westExecutor.get()
-  ).then([=](Try<int>&& t) {
-    EXPECT_EQ(std::this_thread::get_id(), westThreadId);
-    return t.value();
-  });
-  while (!f.isReady()) {
-    waiter->makeProgress();
-  }
-  EXPECT_EQ(f.value(), 1);
-}
-
-TEST_F(ViaFixture, chain_vias) {
-  auto westThreadId = std::this_thread::get_id();
-  auto f = via(eastExecutor.get()).then([=](Try<void>&& t) {
-    EXPECT_NE(std::this_thread::get_id(), westThreadId);
-    return makeFuture<int>(1);
-  }).then([=](Try<int>&& t) {
-    int val = t.value();
-    return makeFuture(std::move(val)).via(westExecutor.get())
-      .then([=](Try<int>&& t) mutable {
-        EXPECT_EQ(std::this_thread::get_id(), westThreadId);
-        return t.value();
-      });
-  }).then([=](Try<int>&& t) {
-    EXPECT_EQ(std::this_thread::get_id(), westThreadId);
-    return t.value();
-  });
-
-  while (!f.isReady()) {
-    waiter->makeProgress();
-  }
-  EXPECT_EQ(f.value(), 1);
-}
-
-TEST_F(ViaFixture, bareViaAssignment) {
-  auto f = via(eastExecutor.get());
-}
-TEST_F(ViaFixture, viaAssignment) {
-  // via()&&
-  auto f = makeFuture().via(eastExecutor.get());
-  // via()&
-  auto f2 = f.via(eastExecutor.get());
-}
diff --git a/folly/wangle/futures/test/main.cpp b/folly/wangle/futures/test/main.cpp
deleted file mode 100644 (file)
index 7dbf27d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2014 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/folly/wangle/futures/test/thens.rb b/folly/wangle/futures/test/thens.rb
deleted file mode 100755 (executable)
index 4aaa846..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env ruby
-
-# ruby thens.rb > Thens.cpp
-
-# An exercise in combinatorics.
-# (ordinary/static function, member function, std::function, lambda)
-# X
-# returns (Future<R>, R)
-# X
-# accepts (Try<T>&&, Try<T> const&, Try<T>, T&&, T const&, T, nothing)
-
-def test(*args)
-  args = args.join(", ")
-  [
-  "{Future<B> f = someFuture<A>().then(#{args});}",
-  #"{Future<B> f = makeFuture(A()).then(#{args}, anExecutor);}",
-  ]
-end
-
-def retval(ret)
-  {
-    "Future<B>" => "someFuture<B>()",
-    "Try<B>" => "Try<B>(B())",
-    "B" => "B()"
-  }[ret]
-end
-
-return_types = [
-  "Future<B>",
-  "B",
-  #"Try<B>",
-]
-param_types = [
-    "Try<A>&&",
-    #"Try<A> const&",
-    #"Try<A>",
-    #"Try<A>&",
-    "A&&",
-    #"A const&",
-    #"A",
-    #"A&",
-    #"",
-  ]
-
-tests = (
-  return_types.map { |ret|
-    param_types.map { |param|
-      both = "#{ret}, #{param}"
-      [
-        ["&aFunction<#{both}>"],
-        ["&SomeClass::aStaticMethod<#{both}>"],
-        # TODO switch these around (std::bind-style)
-        ["&anObject", "&SomeClass::aMethod<#{both}>"],
-        ["aStdFunction<#{both}>()"],
-        ["[&](#{param}){return #{retval(ret)};}"],
-      ]
-    }
-  }.flatten(2) + [
-    #[""],
-  ]
-).map {|a| test(a)}.flatten
-
-print <<EOF
-// This file is #{"@"}generated by thens.rb. Do not edit directly.
-
-// TODO: fails to compile with clang:dev.  See task #4412111
-#ifndef __clang__
-
-#include <folly/wangle/futures/test/Thens.h>
-
-TEST(Future, thenVariants) {
-  SomeClass anObject;
-  folly::Executor* anExecutor;
-
-  #{tests.join("\n  ")}
-}
-
-#endif
-EOF