Commit ca71b787 authored by Hannes Roth's avatar Hannes Roth Committed by woo

(Wangle) Then Magic

Summary: All is good now.

Test Plan: Run all the tests.

Reviewed By: hans@fb.com

Subscribers: jsedgwick, trunkagent, fugalh, folly-diffs@

FB internal diff: D1758272

Signature: t1:1758272:1421889405:a015d30783715e106a1e6667e971f7cf47c8392d
parent d6c0e8e7
......@@ -31,16 +31,6 @@ 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);
......@@ -78,14 +68,14 @@ void Future<T>::setCallback_(F&& func) {
core_->setCallback(std::move(func));
}
// Variant: f.then([](Try<T>&& t){ return t.value(); });
// Variant: returns a value
// e.g. 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;
template <typename F, typename R, bool isTry, typename... Args>
typename std::enable_if<!R::ReturnsFuture::value, typename R::Return>::type
Future<T>::thenImplementation(F func, detail::argResult<isTry, F, Args...>) {
static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
typedef typename R::ReturnsFuture::Inner B;
throwIfInvalid();
......@@ -130,39 +120,11 @@ Future<T>::then(F&& func) {
*/
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()) {
if (!isTry && t.hasException()) {
p->setException(std::move(t.exception()));
} else {
p->fulfil([&]() {
return (*funcm)(std::move(t.value()));
return (*funcm)(t.template get<isTry, Args>()...);
});
}
});
......@@ -170,44 +132,14 @@ Future<T>::then(F&& func) {
return f;
}
// Variant: f.then([](){ return; });
// Variant: returns a Future
// e.g. 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()>::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;
template <typename F, typename R, bool isTry, typename... Args>
typename std::enable_if<R::ReturnsFuture::value, typename R::Return>::type
Future<T>::thenImplementation(F func, detail::argResult<isTry, F, Args...>) {
static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
typedef typename R::ReturnsFuture::Inner B;
throwIfInvalid();
......@@ -220,53 +152,16 @@ Future<T>::then(F&& func) {
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()) {
if (!isTry && t.hasException()) {
p->setException(std::move(t.exception()));
} else {
try {
auto f2 = (*funcm)(std::move(t.value()));
auto f2 = (*funcm)(t.template get<isTry, Args>()...);
// 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()));
}
}
......@@ -275,42 +170,16 @@ Future<T>::then(F&& func) {
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 <typename T>
template <typename Caller, typename R, typename... Args>
Future<typename isFuture<R>::Inner>
Future<T>::then(Caller *instance, R(Caller::*func)(Args...)) {
typedef typename std::remove_cv<
typename std::remove_reference<
typename detail::ArgType<Args...>::FirstArg>::type>::type FirstArg;
return then([instance, func](Try<T>&& t){
return (instance->*func)(t.template get<isTry<FirstArg>::value, Args>()...);
});
}
template <class T>
......
This diff is collapsed.
......@@ -198,6 +198,16 @@ class Try {
return e_->with_exception<Ex>(std::move(func));
}
template <bool isTry, typename R>
typename std::enable_if<isTry, R>::type get() {
return std::forward<R>(*this);
}
template <bool isTry, typename R>
typename std::enable_if<!isTry, R>::type get() {
return std::forward<R>(value());
}
private:
Contains contains_;
union {
......@@ -300,6 +310,11 @@ class Try<void> {
return e_->with_exception<Ex>(std::move(func));
}
template <bool, typename R>
R get() {
return std::forward<R>(*this);
}
private:
bool hasValue_;
std::unique_ptr<exception_wrapper> e_{nullptr};
......
......@@ -276,6 +276,25 @@ TEST(Future, special) {
EXPECT_TRUE(std::is_move_assignable<Future<int>>::value);
}
TEST(Future, then) {
auto f = makeFuture<string>("0")
.then([](){ return makeFuture<string>("1"); })
.then([](Try<string>&& t) { return makeFuture(t.value() + ";2"); })
.then([](const Try<string>&& t) { return makeFuture(t.value() + ";3"); })
.then([](Try<string>& t) { return makeFuture(t.value() + ";4"); })
.then([](const Try<string>& t) { return makeFuture(t.value() + ";5"); })
.then([](Try<string> t) { return makeFuture(t.value() + ";6"); })
.then([](const Try<string> t) { return makeFuture(t.value() + ";7"); })
.then([](string&& s) { return makeFuture(s + ";8"); })
.then([](const string&& s) { return makeFuture(s + ";9"); })
.then([](string& s) { return makeFuture(s + ";10"); })
.then([](const string& s) { return makeFuture(s + ";11"); })
.then([](string s) { return makeFuture(s + ";12"); })
.then([](const string s) { return makeFuture(s + ";13"); })
;
EXPECT_EQ(f.value(), "1;2;3;4;5;6;7;8;9;10;11;12;13");
}
TEST(Future, thenTry) {
bool flag = false;
......@@ -384,6 +403,25 @@ TEST(Future, thenFunctionFuture) {
EXPECT_EQ(f.value(), "start;static;class-static;class");
}
TEST(Future, thenBind) {
auto l = []() {
return makeFuture("bind");
};
auto b = std::bind(l);
auto f = makeFuture().then(std::move(b));
EXPECT_EQ(f.value(), "bind");
}
TEST(Future, thenBindTry) {
auto l = [](Try<string>&& t) {
return makeFuture(t.value() + ";bind");
};
auto b = std::bind(l, std::placeholders::_1);
auto f = makeFuture<string>("start").then(std::move(b));
EXPECT_EQ(f.value(), "start;bind");
}
TEST(Future, value) {
auto f = makeFuture(unique_ptr<int>(new int(42)));
auto up = std::move(f.value());
......
/*
* Copyright 2015 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>
using namespace folly;
struct Widget {
int v_, copied_, moved_;
/* implicit */ Widget(int v) : v_(v), copied_(0), moved_(0) {}
Widget(const Widget& other)
: v_(other.v_), copied_(other.copied_ + 1), moved_(other.moved_) {}
Widget(Widget&& other) noexcept
: v_(other.v_), copied_(other.copied_), moved_(other.moved_ + 1) {}
Widget& operator=(const Widget& other)
{ throw std::logic_error("unexpected copy assignment"); }
Widget& operator=(Widget&& other)
{ throw std::logic_error("unexpected move assignment"); }
};
TEST(Then, tryConstructor) {
auto t = Try<Widget>(23);
EXPECT_EQ(t.value().v_, 23);
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(t.value().moved_, 1);
}
TEST(Then, makeFuture) {
auto future = makeFuture<Widget>(23);
EXPECT_EQ(future.value().v_, 23);
EXPECT_EQ(future.value().copied_, 0);
EXPECT_EQ(future.value().moved_, 2);
}
TEST(Then, TryConstRValueReference) {
auto future = makeFuture<Widget>(23).then(
[](const Try<Widget>&& t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(t.value().moved_, 2);
return t.value().v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, TryRValueReference) {
auto future = makeFuture<Widget>(23).then(
[](Try<Widget>&& t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(t.value().moved_, 2);
return t.value().v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, TryLValueReference) {
auto future = makeFuture<Widget>(23).then(
[](Try<Widget>& t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(t.value().moved_, 2);
return t.value().v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, TryConstLValueReference) {
auto future = makeFuture<Widget>(23).then(
[](const Try<Widget>& t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(t.value().moved_, 2);
return t.value().v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, TryValue) {
auto future = makeFuture<Widget>(23).then(
[](Try<Widget> t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(t.value().moved_, 3);
return t.value().v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, TryConstValue) {
auto future = makeFuture<Widget>(23).then(
[](const Try<Widget> t) {
EXPECT_EQ(t.value().copied_, 0);
EXPECT_EQ(t.value().moved_, 3);
return t.value().v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, ConstRValueReference) {
auto future = makeFuture<Widget>(23).then(
[](const Widget&& w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(w.moved_, 2);
return w.v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, RValueReference) {
auto future = makeFuture<Widget>(23).then(
[](Widget&& w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(w.moved_, 2);
return w.v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, LValueReference) {
auto future = makeFuture<Widget>(23).then(
[](Widget& w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(w.moved_, 2);
return w.v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, ConstLValueReference) {
auto future = makeFuture<Widget>(23).then(
[](const Widget& w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(w.moved_, 2);
return w.v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, Value) {
auto future = makeFuture<Widget>(23).then(
[](Widget w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(w.moved_, 3);
return w.v_;
});
EXPECT_EQ(future.value(), 23);
}
TEST(Then, ConstValue) {
auto future = makeFuture<Widget>(23).then(
[](const Widget w) {
EXPECT_EQ(w.copied_, 0);
EXPECT_EQ(w.moved_, 3);
return w.v_;
});
EXPECT_EQ(future.value(), 23);
}
// 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) {
......@@ -14,21 +11,82 @@ TEST(Future, thenVariants) {
{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>, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A> const&>());}
{Future<B> f = someFuture<A>().then([&](Try<A> const&){return someFuture<B>();});}
{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>, 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<Future<B>, A const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A const&>);}
{Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, A const&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A const&>());}
{Future<B> f = someFuture<A>().then([&](A const&){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<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([&](){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, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A> const&>());}
{Future<B> f = someFuture<A>().then([&](Try<A> const&){return 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, 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();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, A const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A const&>);}
{Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, A const&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, A const&>());}
{Future<B> f = someFuture<A>().then([&](A const&){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();});}
{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();});}
{Future<B> f = someFuture<A>().then([&](){return B();});}
}
#endif
......@@ -38,9 +38,6 @@ 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...) {
......@@ -69,11 +66,7 @@ aStdFunction(typename std::enable_if<isFuture<Ret>::value, bool>::type = true) {
}
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
......@@ -89,9 +82,6 @@ public:
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...) {
......
#!/usr/bin/env ruby
# ruby thens.rb > Thens.cpp
# ruby folly/futures/test/thens.rb > folly/futures/test/Thens.cpp
# An exercise in combinatorics.
# (ordinary/static function, member function, std::function, lambda)
......@@ -32,40 +32,39 @@ return_types = [
]
param_types = [
"Try<A>&&",
#"Try<A> const&",
#"Try<A>",
#"Try<A>&",
"Try<A> const&",
"Try<A>",
"Try<A>&",
"A&&",
#"A const&",
#"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)};}"],
]
if param != "" then
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)};}"],
]
else
[["[&](){return #{retval(ret)};}"]]
end
}
}.flatten(2) + [
#[""],
]
}.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) {
......@@ -75,5 +74,4 @@ TEST(Future, thenVariants) {
#{tests.join("\n ")}
}
#endif
EOF
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment