From: James Sedgwick Date: Fri, 9 Jan 2015 16:27:02 +0000 (-0800) Subject: move wangle/futures to futures X-Git-Tag: v0.22.0~8 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=bc374dcbb0e552826e4bcbed1d8cbd479ce062c0;p=folly.git move wangle/futures to futures 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 --- diff --git a/folly/Makefile.am b/folly/Makefile.am index 50ec57d2..d717d5fd 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -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 index 00000000..75937b15 --- /dev/null +++ b/folly/futures/Deprecated.h @@ -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 index 00000000..c19f08a0 --- /dev/null +++ b/folly/futures/Future-inl.h @@ -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 +#include + +#include +#include +#include + +namespace folly { namespace wangle { + +class Timekeeper; + +namespace detail { + Timekeeper* getTimekeeperSingleton(); +} + +template +struct isFuture { + static const bool value = false; +}; + +template +struct isFuture > { + static const bool value = true; +}; + +template +Future::Future(Future&& other) noexcept : core_(nullptr) { + *this = std::move(other); +} + +template +Future& Future::operator=(Future&& other) { + std::swap(core_, other.core_); + return *this; +} + +template +Future::~Future() { + detach(); +} + +template +void Future::detach() { + if (core_) { + core_->detachFuture(); + core_ = nullptr; + } +} + +template +void Future::throwIfInvalid() const { + if (!core_) + throw NoState(); +} + +template +template +void Future::setCallback_(F&& func) { + throwIfInvalid(); + core_->setCallback(std::move(func)); +} + +// Variant: f.then([](Try&& t){ return t.value(); }); +template +template +typename std::enable_if< + !isFuture&&)>::type>::value, + Future&&)>::type> >::type +Future::then(F&& func) { + typedef typename std::result_of&&)>::type B; + + throwIfInvalid(); + + // wrap these so we can move them into the lambda + folly::MoveWrapper> p; + folly::MoveWrapper funcm(std::forward(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) mutable { + p->fulfil([&]() { + return (*funcm)(std::move(t)); + }); + }); + + return f; +} + +// Variant: f.then([](T&& t){ return t; }); +template +template +typename std::enable_if< + !std::is_same::value && + !isFuture::type&&)>::type>::value, + Future::type&&)>::type> >::type +Future::then(F&& func) { + typedef typename std::result_of::type B; + + throwIfInvalid(); + + folly::MoveWrapper> p; + folly::MoveWrapper funcm(std::forward(func)); + auto f = p->getFuture(); + + setCallback_( + [p, funcm](Try&& 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 +template +typename std::enable_if< + std::is_same::value && + !isFuture::type>::value, + Future::type> >::type +Future::then(F&& func) { + typedef typename std::result_of::type B; + + throwIfInvalid(); + + folly::MoveWrapper> p; + folly::MoveWrapper funcm(std::forward(func)); + auto f = p->getFuture(); + + setCallback_( + [p, funcm](Try&& t) mutable { + if (t.hasException()) { + p->setException(std::move(t.exception())); + } else { + p->fulfil([&]() { + return (*funcm)(); + }); + } + }); + + return f; +} + +// Variant: f.then([](Try&& t){ return makeFuture(t.value()); }); +template +template +typename std::enable_if< + isFuture&&)>::type>::value, + Future&&)>::type::value_type> >::type +Future::then(F&& func) { + typedef typename std::result_of&&)>::type::value_type B; + + throwIfInvalid(); + + // wrap these so we can move them into the lambda + folly::MoveWrapper> p; + folly::MoveWrapper funcm(std::forward(func)); + + // grab the Future now before we lose our handle on the Promise + auto f = p->getFuture(); + + setCallback_( + [p, funcm](Try&& t) mutable { + try { + auto f2 = (*funcm)(std::move(t)); + // that didn't throw, now we can steal p + f2.setCallback_([p](Try&& 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); }); +template +template +typename std::enable_if< + !std::is_same::value && + isFuture::type&&)>::type>::value, + Future::type&&)>::type::value_type> >::type +Future::then(F&& func) { + typedef typename std::result_of::type::value_type B; + + throwIfInvalid(); + + folly::MoveWrapper> p; + folly::MoveWrapper funcm(std::forward(func)); + auto f = p->getFuture(); + + setCallback_( + [p, funcm](Try&& 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) 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 +template +typename std::enable_if< + std::is_same::value && + isFuture::type>::value, + Future::type::value_type> >::type +Future::then(F&& func) { + typedef typename std::result_of::type::value_type B; + + throwIfInvalid(); + + folly::MoveWrapper> p; + folly::MoveWrapper funcm(std::forward(func)); + + auto f = p->getFuture(); + + setCallback_( + [p, funcm](Try&& t) mutable { + if (t.hasException()) { + p->setException(t.exception()); + } else { + try { + auto f2 = (*funcm)(); + f2.setCallback_([p](Try&& 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 +Future Future::then() { + return then([] (Try&& t) {}); +} + +// onError where the callback returns T +template +template +typename std::enable_if< + !detail::Extract::ReturnsFuture::value, + Future>::type +Future::onError(F&& func) { + typedef typename detail::Extract::FirstArg Exn; + static_assert( + std::is_same::RawReturn, T>::value, + "Return type of onError callback must be T or Future"); + + Promise p; + auto f = p.getFuture(); + auto pm = folly::makeMoveWrapper(std::move(p)); + auto funcm = folly::makeMoveWrapper(std::move(func)); + setCallback_([pm, funcm](Try&& t) mutable { + if (!t.template withException([&] (Exn& e) { + pm->fulfil([&]{ + return (*funcm)(e); + }); + })) { + pm->fulfilTry(std::move(t)); + } + }); + + return f; +} + +// onError where the callback returns Future +template +template +typename std::enable_if< + detail::Extract::ReturnsFuture::value, + Future>::type +Future::onError(F&& func) { + static_assert( + std::is_same::Return, Future>::value, + "Return type of onError callback must be T or Future"); + typedef typename detail::Extract::FirstArg Exn; + + Promise p; + auto f = p.getFuture(); + auto pm = folly::makeMoveWrapper(std::move(p)); + auto funcm = folly::makeMoveWrapper(std::move(func)); + setCallback_([pm, funcm](Try&& t) mutable { + if (!t.template withException([&] (Exn& e) { + try { + auto f2 = (*funcm)(e); + f2.setCallback_([pm](Try&& 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 +typename std::add_lvalue_reference::type Future::value() { + throwIfInvalid(); + + return core_->getTry().value(); +} + +template +typename std::add_lvalue_reference::type Future::value() const { + throwIfInvalid(); + + return core_->getTry().value(); +} + +template +Try& Future::getTry() { + throwIfInvalid(); + + return core_->getTry(); +} + +template +template +inline Future Future::via(Executor* executor) && { + throwIfInvalid(); + + this->deactivate(); + core_->setExecutor(executor); + + return std::move(*this); +} + +template +template +inline Future Future::via(Executor* executor) & { + throwIfInvalid(); + + MoveWrapper> p; + auto f = p->getFuture(); + then([p](Try&& t) mutable { p->fulfilTry(std::move(t)); }); + return std::move(f).via(executor); +} + +template +bool Future::isReady() const { + throwIfInvalid(); + return core_->ready(); +} + +template +void Future::raise(exception_wrapper exception) { + core_->raise(std::move(exception)); +} + +// makeFuture + +template +Future::type> makeFuture(T&& t) { + Promise::type> p; + p.setValue(std::forward(t)); + return p.getFuture(); +} + +inline // for multiple translation units +Future makeFuture() { + Promise p; + p.setValue(); + return p.getFuture(); +} + +template +auto makeFutureTry( + F&& func, + typename std::enable_if::value, bool>::type sdf) + -> Future { + Promise p; + p.fulfil( + [&func]() { + return (func)(); + }); + return p.getFuture(); +} + +template +auto makeFutureTry(F const& func) -> Future { + F copy = func; + return makeFutureTry(std::move(copy)); +} + +template +Future makeFuture(std::exception_ptr const& e) { + Promise p; + p.setException(e); + return p.getFuture(); +} + +template +Future makeFuture(exception_wrapper ew) { + Promise p; + p.setException(std::move(ew)); + return p.getFuture(); +} + +template +typename std::enable_if::value, + Future>::type +makeFuture(E const& e) { + Promise p; + p.setException(make_exception_wrapper(e)); + return p.getFuture(); +} + +template +Future makeFuture(Try&& t) { + if (t.hasException()) { + return makeFuture(std::move(t.exception())); + } else { + return makeFuture(std::move(t.value())); + } +} + +template <> +inline Future makeFuture(Try&& t) { + if (t.hasException()) { + return makeFuture(std::move(t.exception())); + } else { + return makeFuture(); + } +} + +// via +template +Future via(Executor* executor) { + return makeFuture().via(executor); +} + +// when (variadic) + +template +typename detail::VariadicContext< + typename std::decay::type::value_type...>::type +whenAll(Fs&&... fs) +{ + auto ctx = + new detail::VariadicContext::type::value_type...>(); + ctx->total = sizeof...(fs); + auto f_saved = ctx->p.getFuture(); + detail::whenAllVariadicHelper(ctx, + std::forward::type>(fs)...); + return f_saved; +} + +// when (iterator) + +template +Future< + std::vector< + Try::value_type::value_type>>> +whenAll(InputIterator first, InputIterator last) +{ + typedef + typename std::iterator_traits::value_type::value_type T; + + if (first >= last) { + return makeFuture(std::vector>()); + } + size_t n = std::distance(first, last); + + auto ctx = new detail::WhenAllContext(); + + 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) { + ctx->results[i] = std::move(t); + if (++ctx->count == n) { + ctx->p.setValue(std::move(ctx->results)); + delete ctx; + } + }); + } + + return f_saved; +} + +template +Future< + std::pair::value_type::value_type> > > +whenAny(InputIterator first, InputIterator last) { + typedef + typename std::iterator_traits::value_type::value_type T; + + auto ctx = new detail::WhenAnyContext(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) { + if (!ctx->done.exchange(true)) { + ctx->p.setValue(std::make_pair(i, std::move(t))); + } + ctx->decref(); + }); + } + + return f_saved; +} + +template +Future::value_type::value_type>>>> +whenN(InputIterator first, InputIterator last, size_t n) { + typedef typename + std::iterator_traits::value_type::value_type T; + typedef std::vector>> V; + + struct ctx_t { + V v; + size_t completed; + Promise p; + }; + auto ctx = std::make_shared(); + 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) { + 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(std::move(v))); + } + } + }); + + it++; + i++; + } + + if (i < n) { + ctx->p.setException(std::runtime_error("Not enough futures")); + } + + return ctx->p.getFuture(); +} + +template +Future +waitWithSemaphore(Future&& f) { + Baton<> baton; + auto done = f.then([&](Try &&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 waitWithSemaphore(Future&& f) { + Baton<> baton; + auto done = f.then([&](Try &&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 +Future +waitWithSemaphore(Future&& f, Dur timeout) { + auto baton = std::make_shared>(); + auto done = f.then([baton](Try &&t) { + baton->post(); + return std::move(t.value()); + }); + baton->timed_wait(std::chrono::system_clock::now() + timeout); + return done; +} + +template +Future +waitWithSemaphore(Future&& f, Dur timeout) { + auto baton = std::make_shared>(); + auto done = f.then([baton](Try &&t) { + baton->post(); + t.value(); + }); + baton->timed_wait(std::chrono::system_clock::now() + timeout); + return done; +} + +namespace { + template + void getWaitHelper(Future* f) { + // If we already have a value do the cheap thing + if (f->isReady()) { + return; + } + + folly::Baton<> baton; + f->then([&](Try const&) { + baton.post(); + }); + baton.wait(); + } + + template + Future getWaitTimeoutHelper(Future* f, Duration dur) { + // TODO make and use variadic whenAny #5877971 + Promise p; + auto token = std::make_shared>(); + folly::Baton<> baton; + + folly::wangle::detail::getTimekeeperSingleton()->after(dur) + .then([&,token](Try 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) { + if (token->exchange(true) == false) { + p.fulfilTry(std::move(t)); + baton.post(); + } + }); + + baton.wait(); + return p.getFuture(); + } +} + +template +T Future::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::get() { + getWaitHelper(this); + value(); +} + +template +T Future::get(Duration dur) { + return std::move(getWaitTimeoutHelper(this, dur).value()); +} + +template <> +inline void Future::get(Duration dur) { + getWaitTimeoutHelper(this, dur).value(); +} + +template +Future Future::within(Duration dur, Timekeeper* tk) { + return within(dur, TimedOut(), tk); +} + +template +template +Future Future::within(Duration dur, E e, Timekeeper* tk) { + + struct Context { + Context(E ex) : exception(std::move(ex)), promise(), token(false) {} + E exception; + Promise promise; + std::atomic token; + }; + auto ctx = std::make_shared(std::move(e)); + + if (!tk) { + tk = folly::wangle::detail::getTimekeeperSingleton(); + } + + tk->after(dur) + .then([ctx](Try 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) { + if (ctx->token.exchange(true) == false) { + ctx->promise.fulfilTry(std::move(t)); + } + }); + + return ctx->promise.getFuture(); +} + +template +Future Future::delayed(Duration dur, Timekeeper* tk) { + return whenAll(*this, futures::sleep(dur, tk)) + .then([](Try, Try>>&& tup) { + Try& t = std::get<0>(tup.value()); + return makeFuture(std::move(t)); + }); +} + +}} + +// I haven't included a Future specialization because I don't forsee us +// using it, however it is not difficult to add when needed. Refer to +// Future 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 index 00000000..fc7ff9b4 --- /dev/null +++ b/folly/futures/Future.cpp @@ -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 +#include +#include + +namespace folly { namespace wangle { namespace futures { + +Future 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 index 00000000..e61c530c --- /dev/null +++ b/folly/futures/Future.h @@ -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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace folly { namespace wangle { + +template struct Promise; + +namespace detail { + +template struct Core; +template struct VariadicContext; + +template +struct AliasIfVoid { + typedef typename std::conditional< + std::is_same::value, + int, + T>::type type; +}; + + +template +struct IsFuture : std::integral_constant { + typedef T Inner; +}; + +template