tree: 114222293427318f49cd8afa5569297e6cb65884 [path history] [tgz]
  1. detail/
  2. exercises/
  3. test/
  4. Barrier.cpp
  5. Barrier.h
  6. DrivableExecutor.h
  7. Future-inl.h
  8. Future-pre.h
  9. Future.cpp
  10. Future.h
  11. FutureException.h
  12. helpers.h
  13. InlineExecutor.cpp
  14. InlineExecutor.h
  15. ManualExecutor.cpp
  16. ManualExecutor.h
  17. OpaqueCallbackShunt.h
  18. Promise-inl.h
  19. Promise.h
  20. QueuedImmediateExecutor.cpp
  21. QueuedImmediateExecutor.h
  22. README.md
  23. ScheduledExecutor.cpp
  24. ScheduledExecutor.h
  25. SharedPromise-inl.h
  26. SharedPromise.h
  27. ThreadedExecutor.cpp
  28. ThreadedExecutor.h
  29. Timekeeper.h
  30. Try-inl.h
  31. Try.h
  32. Unit.h
faux-folly/folly/futures/README.md

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(foo); cout << "Future chain made" << endl;

// ... now perhaps in another event callback

cout << "fulfilling Promise" << endl; p.setValue(42); cout << "Promise fulfilled" << endl;

<span class="n">Result</span> <span class="n">result</span><span class="p">;</span>
<span class="c1">// The value when result is FOUND,</span>
<span class="c1">// The error message when result is SERVER_ERROR or CLIENT_ERROR</span>
<span class="c1">// undefined otherwise</span>
<span class="n">string</span> <span class="n">value</span><span class="p">;</span>

};

GetReply get(string key); };

vector<Future<GetReply>> futs; for (auto& key : keys) { futs.push_back(mc.get(key)); } auto any = collectAny(futs.begin(), futs.end());

Future<string> fut2 = fut1.then( [](GetReply reply) { if (reply.result == MemcacheClient::GetReply::Result::FOUND) return reply.value; throw SomeException("No value"); });

Future<Unit> fut3 = fut2 .then([](string str) { cout << str << endl; }) .onError([](std::exception const& e) { cerr << e.what() << endl; });

// Thread B f.then(x).then(y).then(z);

// Thread A p.setValue();

f.isReady() == false

p.setValue(42);

f.isReady() == true f.value() == 42

f.isReady() == false

p.setException(std::runtime_error("Fail"));

f.isReady() == true f.value() // throws the exception

f.then([](int i){ cout << i; });

p.setValue(42);

f2.then([](string s){ /* ... */ });

f2.then([](Try<string> const& s){ ... });

struct Foo { void memberMethod(Try<int> const& t); static void staticMemberMethod(Try<int> const& t); }; Foo foo;

// bind global function makeFuture<int>(1).then(globalFunction); // bind member method makeFuture<int>(2).then(&Foo::memberMethod, &foo); // bind static member method makeFuture<int>(3).then(&Foo::staticMemberMethod);

Future<int> foo(int arg) { auto promise = std::make_shared<Promise<int>>();

fooOldFashioned(arg, [promise](int result) { promise->setValue(result); });

return promise->getFuture(); }

Promise<int> p1, p2, p3; p1.setException(std::runtime_error("oh no!")); p2.setException(folly::make_exception_wrapper<std::runtime_error>("oh no!")); p3.setException(std::current_exception());

// Try is also integrated with exception_wrapper makeFuture<int>(std::runtime_error("ugh")).then([](Try<int> t){ if (t.hasException<std::exception>()) { // this is enough if we only care whether the given exception is present } });

makeFuture<int>(std::runtime_error("ugh")).then([](Try<int> t){ // we can also extract and handle the exception object // TODO(jsedgwick) infer exception type from the type of the function bool caught = t.withException<std::exception>([](const std::exception& e){ // do something with e }); });

// f now contains the result of the then() callback, unless the ensure() // callback threw, in which case f will contain that exception

std::vector<Future<T>> fs; for (int i = 0; i < 10; i++) { fs.push_back(someRPC(i)); }

collectAll(fs).then([](const std::vector<Try<T>>& tries){ for (const auto& t : tries) { // handle each response } });

// Or using a Try: collect(fs).then([](const Try<std::vector<T>>& t) { // ... });

// Thread B f.then(x).then(y);

// Thread A p.setValue();

// f will complete with a TimedOut exception if the Future returned by foo() // does not complete within 500 ms f = foo().within(milliseconds(500));

// Same deal, but a timeout will trigger the provided exception instead f2 = foo().within(milliseconds(500), std::runtime_error("you took too long!"));

// If the Future doesn't complete within one second, f will remain // incomplete. That is, if a timeout occurs, it's as if wait() was // never called. Future<int> f = foo().wait(milliseconds(1000));

// Or maybe we want the Future to complete with some special value p.setValue(42);

// Or maybe we don't want to do anything at all! Including not setting // this handler in the first place. });

auto f = p.getFuture(); // The Future holder can now send an interrupt whenever it wants via raise(). // If the interrupt beats out the fulfillment of the Promise and there is // an interrupt handler set on the Promise, that handler will be called with // the provided exception f.raise(std::runtime_error("Something went awry! Abort!"));

// cancel() is syntactic sugar for raise(FutureCancellation()) f.cancel();

// The mock implementation class MockAsyncClient : public AsyncClient { public: // Declare a mock method foo_ that takes an int and returns an int MOCK_METHOD1(foo_, int(int));

// Plug the mock into an override of the interface Future<int> foo(int i) override { // Lift the result back into a Future before returning return makeFuture<int>(foo_(i)); } };

// Let's say that we're testing a class MyProxy that simply forwards foo() // calls to AsyncClient and returns the result class MyProxy { public: Future<int> foo(int i) { return client->foo(i); } void setClient(AsyncClient client); private: AsyncClient client; };

// Now, in our testing code MyProxy proxy; MockAsyncClient mockClient; // Inject the mock proxy.setClient(&mockClient) // Set an expectation on the mock to be called with 42 and return 84 EXPECT_CALL(mockClient, foo_(42)).WillOnce(Return(84)); // Trigger the call auto f = MyProxy.foo(42); // If everything has been mocked out synchronously, we can just check the // value of the future directly EXPECT_EQ(84, f.value());PitfallsEventBase, EventBaseManager, Executor #

-- "bind" is a function that takes a monad, and a function that takes a value -- and returns another monad. Haskellers call this ">>=" because they are -- vying to unseat perl from the throne of illegibility. bind :: m a -> (a -> m b) -> m b

// "then" is "bind" template <class B> Future<B> then(std::function<Future<B>(A));

... };

// "makeFuture" is also "unit", and we will need it because constructors can't // really be converted to std::function (AFAIK) template <class A> Future<A> makeFuture(A);

// Right Identity Future<A> m; m.then(makeFuture<A>) == m

// Associativity Future<A> m; std::function<Future<B>(A)> f; std::function<Future<C>(B)> g; m.then(f).then(g) == m.then([](A x) { return f(x).then(g); })

-- Left Identity unit >=> g ≡ g -- Right Identity f >=> unit ≡ f -- Associativity (f >=> g) >=> h ≡ f >=> (g >=> h)