1
0
Fork 0

remove backports

This commit is contained in:
Jan Christoph Uhde 2019-11-21 18:57:22 +01:00
parent 36bde0dfad
commit c6aef7194b
6 changed files with 101 additions and 190 deletions

View File

@ -32,7 +32,6 @@
#include "Futures/Promise.h"
#include "Futures/SharedState.h"
#include "Futures/Unit.h"
#include "Futures/backports.h"
namespace arangodb {
namespace futures {
@ -102,7 +101,7 @@ struct valueCallableResult {
template <class F, typename R = typename std::result_of<F()>::type>
typename std::enable_if<!std::is_same<R, void>::value, Try<R>>::type makeTryWith(F&& func) noexcept {
try {
return Try<R>(in_place, func());
return Try<R>(std::in_place, func());
} catch (...) {
return Try<R>(std::current_exception());
}
@ -140,10 +139,10 @@ void waitImpl(Future<T>& f) {
if (f.isReady()) {
return; // short-circuit
}
std::mutex m;
std::condition_variable cv;
Promise<T> p;
Future<T> ret = p.getFuture();
f.thenFinal([p(std::move(p)), &cv, &m](Try<T>&& t) mutable {
@ -162,14 +161,14 @@ void waitImpl(Future<T>& f, std::chrono::time_point<Clock, Duration> const& tp)
if (f.isReady()) {
return; // short-circuit
}
std::mutex m;
std::condition_variable cv;
Promise<T> p;
Future<T> ret = p.getFuture();
f.thenFinal([p(std::move(p)), &cv, &m](Try<T>&& t) mutable {
std::lock_guard<std::mutex> guard(m);
std::lock_guard<std::mutex> guard(m);
p.setTry(std::move(t));
cv.notify_one();
});
@ -193,7 +192,7 @@ class Future {
public:
/// @brief value type of the future
typedef T value_type;
/// @brief Constructs a Future with no shared state.
static Future<T> makeEmpty() { return Future<T>(detail::EmptyConstructor{}); }
@ -211,8 +210,8 @@ class Future {
// Construct a Future from a `T` constructed from `args`
template <class... Args, typename std::enable_if<std::is_constructible<T, Args&&...>::value, int>::type = 0>
explicit Future(in_place_t, Args&&... args)
: _state(detail::SharedState<T>::make(in_place, std::forward<Args>(args)...)) {}
explicit Future(std::in_place_t, Args&&... args)
: _state(detail::SharedState<T>::make(std::in_place, std::forward<Args>(args)...)) {}
Future(Future const& o) = delete;
Future(Future<T>&& o) noexcept : _state(std::move(o._state)) {
@ -354,7 +353,7 @@ class Future {
pr.setException(std::move(t).exception());
} else {
pr.setTry(detail::makeTryWith([&fn, &t] {
return futures::invoke(std::forward<DF>(fn), std::move(t).get());
return std::invoke(std::forward<DF>(fn), std::move(t).get());
}));
}
});
@ -370,7 +369,7 @@ class Future {
using DF = detail::decay_t<F>;
static_assert(!isFuture<B>::value, "");
static_assert(is_invocable_r<Future<B>, F, T>::value,
static_assert(std::is_invocable_r<Future<B>, F, T>::value,
"Function must be invocable with T");
Promise<B> promise;
@ -381,7 +380,7 @@ class Future {
pr.setException(std::move(t).exception());
} else {
try {
auto f = futures::invoke(std::forward<DF>(fn), std::move(t).get());
auto f = std::invoke(std::forward<DF>(fn), std::move(t).get());
std::move(f).then([pr = std::move(pr)](Try<B>&& t) mutable {
pr.setTry(std::move(t));
});
@ -409,7 +408,7 @@ class Future {
getState().setCallback([fn = std::forward<DF>(func),
pr = std::move(promise)](Try<T>&& t) mutable {
pr.setTry(detail::makeTryWith([&fn, &t] {
return futures::invoke(std::forward<DF>(fn), std::move(t));
return std::invoke(std::forward<DF>(fn), std::move(t));
}));
});
return future;
@ -428,7 +427,7 @@ class Future {
getState().setCallback([fn = std::forward<F>(func),
pr = std::move(promise)](Try<T>&& t) mutable {
try {
auto f = futures::invoke(std::forward<F>(fn), std::move(t));
auto f = std::invoke(std::forward<F>(fn), std::move(t));
std::move(f).then([pr = std::move(pr)](Try<B>&& t) mutable {
pr.setTry(std::move(t));
});
@ -465,7 +464,7 @@ class Future {
std::rethrow_exception(std::move(t).exception());
} catch (ET& e) {
pr.setTry(detail::makeTryWith([&fn, &e]() mutable {
return futures::invoke(std::forward<DF>(fn), e);
return std::invoke(std::forward<DF>(fn), e);
}));
} catch (...) {
pr.setException(std::current_exception());
@ -494,7 +493,7 @@ class Future {
std::rethrow_exception(std::move(t).exception());
} catch (ET& e) {
try {
auto f = futures::invoke(std::forward<DF>(fn), e);
auto f = std::invoke(std::forward<DF>(fn), e);
std::move(f).then([pr = std::move(pr)](Try<B>&& t) mutable {
pr.setTry(std::move(t));
});

View File

@ -86,8 +86,8 @@ class SharedState {
/// State will be OnlyResult
/// Result held will be the `T` constructed from forwarded `args`
template <typename... Args>
static SharedState<T>* make(in_place_t, Args&&... args) {
return new SharedState<T>(in_place, std::forward<Args>(args)...);
static SharedState<T>* make(std::in_place_t, Args&&... args) {
return new SharedState<T>(std::in_place, std::forward<Args>(args)...);
}
// not copyable
@ -233,9 +233,9 @@ class SharedState {
/// use to construct a ready future
template <typename... Args>
explicit SharedState(in_place_t,
explicit SharedState(std::in_place_t,
Args&&... args) noexcept(std::is_nothrow_constructible<T, Args&&...>::value)
: _result(in_place, std::forward<Args>(args)...),
: _result(std::in_place, std::forward<Args>(args)...),
_state(State::OnlyResult),
_attached(1) {}
@ -258,7 +258,7 @@ class SharedState {
void doCallback() {
TRI_ASSERT(_state == State::Done);
TRI_ASSERT(_callback);
_attached.fetch_add(1);
// SharedStateScope makes this exception safe
SharedStateScope scope(this); // will call detachOne()

View File

@ -26,7 +26,6 @@
#include "Basics/Common.h"
#include "Basics/debugging.h"
#include "Basics/system-compiler.h"
#include "Futures/backports.h"
#include <exception>
#include <type_traits>
@ -63,7 +62,7 @@ class Try {
: _value(std::move(v)), _content(Content::Value) {}
template <typename... Args>
explicit Try(in_place_t,
explicit Try(std::in_place_t,
Args&&... args) noexcept(std::is_nothrow_constructible<T, Args&&...>::value)
: _value(static_cast<Args&&>(args)...), _content(Content::Value) {}
@ -395,7 +394,7 @@ class Try<void> {
template <class F, typename R = typename std::result_of<F()>::type>
typename std::enable_if<!std::is_same<R, void>::value, Try<R>>::type makeTryWith(F&& func) noexcept {
try {
return Try<R>(in_place, func());
return Try<R>(std::in_place, func());
} catch (...) {
return Try<R>(std::current_exception());
}

View File

@ -1,87 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Simon Grätzer
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_FUTURES_BACKPORTS_H
#define ARANGOD_FUTURES_BACKPORTS_H 1
#if __cplusplus >= 201703L
#include <type_traits>
#include <utility>
#endif
#include <functional>
namespace arangodb {
namespace futures {
/// Backports from C++17 of:
/// std::in_place_t
/// std::in_place
/// std::is_invocable
/// std::is_invocable_r
/// std::invoke
#if __cplusplus < 201703L
struct in_place_tag {};
using in_place_t = in_place_tag (&)(in_place_tag);
inline in_place_tag in_place(in_place_tag = {}) { return {}; }
template <typename F, typename... Args>
struct is_invocable
: std::is_constructible<std::function<void(Args...)>,
std::reference_wrapper<typename std::remove_reference<F>::type>> {
};
template <typename R, typename F, typename... Args>
struct is_invocable_r
: std::is_constructible<std::function<R(Args...)>, std::reference_wrapper<typename std::remove_reference<F>::type>> {
};
// mimic: std::invoke, C++17
template <typename F, typename... Args>
constexpr auto invoke(F&& f, Args&&... args) noexcept(
noexcept(static_cast<F&&>(f)(static_cast<Args&&>(args)...)))
-> decltype(static_cast<F&&>(f)(static_cast<Args&&>(args)...)) {
return static_cast<F&&>(f)(static_cast<Args&&>(args)...);
}
template <typename M, typename C, typename... Args>
constexpr auto invoke(M(C::*d), Args&&... args)
-> decltype(std::mem_fn(d)(static_cast<Args&&>(args)...)) {
return std::mem_fn(d)(static_cast<Args&&>(args)...);
}
#else
using std::invoke;
using in_place_t = std::in_place_t;
inline constexpr in_place_t in_place{};
template <class R, class FN, class... ArgTypes>
using is_invocable_r = std::is_invocable_r<R, FN, ArgTypes...>;
template <class FN, class... ArgTypes>
using is_invocable = std::is_invocable<FN, ArgTypes...>;
#endif
} // namespace futures
} // namespace arangodb
#endif

View File

@ -45,27 +45,27 @@ namespace {
EXPECT_FALSE(invalid.valid());
return invalid;
}
template <typename T>
constexpr typename std::decay<T>::type copy(T&& value) noexcept(noexcept(typename std::decay<T>::type(std::forward<T>(value)))) {
return std::forward<T>(value);
}
int onThenHelperAddOne(int i) {
return i + 1;
}
int onThenHelperAddFive(int i) {
return i + 5;
}
Future<int> onThenHelperAddFutureFive(int i) {
return makeFuture(i + 5);
}
typedef std::domain_error eggs_t;
static eggs_t eggs("eggs");
Future<int> onErrorHelperEggs(const eggs_t&) {
return makeFuture(10);
}
@ -84,11 +84,11 @@ TEST(FutureTest, basic) {
auto f = Future<int>::makeEmpty();
EXPECT_ANY_THROW(f.isReady());
}
TEST(FutureTest, default_ctor) {
Future<Unit> abc{};
}
TEST(FutureTest, requires_only_move_ctor) {
struct MoveCtorOnly {
explicit MoveCtorOnly(int id) : id_(id) {}
@ -98,7 +98,7 @@ TEST(FutureTest, requires_only_move_ctor) {
void operator=(MoveCtorOnly&&) = delete;
int id_;
};
{
auto f = makeFuture<MoveCtorOnly>(MoveCtorOnly(42));
ASSERT_TRUE(f.valid());
@ -128,11 +128,11 @@ TEST(FutureTest, requires_only_move_ctor) {
ASSERT_TRUE(v.id_ == 42);
}
}
TEST(FutureTest, ctor_post_condition) {
auto const except = std::logic_error("foo");
auto const ewrap = std::make_exception_ptr(std::logic_error("foo"));
#define DOIT(CREATION_EXPR) \
do { \
auto f1 = (CREATION_EXPR); \
@ -141,7 +141,7 @@ auto f2 = std::move(f1); \
ASSERT_FALSE(f1.valid()); \
ASSERT_TRUE(f2.valid()); \
} while (false)
DOIT(makeValid());
DOIT(Future<int>(42));
DOIT(Future<int>{42});
@ -160,7 +160,7 @@ ASSERT_TRUE(f2.valid()); \
DOIT(makeFuture<int>(Try<int>(ewrap)));
#undef DOIT
}
TEST(FutureTest, ctor_post_condition_invalid) {
#define DOIT(CREATION_EXPR) \
do { \
@ -170,17 +170,17 @@ auto f2 = std::move(f1); \
ASSERT_FALSE(f1.valid()); \
ASSERT_FALSE(f2.valid()); \
} while (false)
DOIT(makeInvalid());
DOIT(Future<int>::makeEmpty());
#undef DOIT
}
TEST(FutureTest, lacksPreconditionValid) {
// Ops that don't throw FutureInvalid if !valid() --
// without precondition: valid()
#define DOIT(STMT) \
do { \
auto f = makeValid(); \
@ -188,15 +188,15 @@ auto f = makeValid(); \
::copy(std::move(f)); \
STMT; \
} while (false)
// .valid() itself
DOIT(f.valid());
// move-ctor - move-copy to local, copy(), pass-by-move-value
DOIT(auto other = std::move(f));
DOIT(copy(std::move(f)));
DOIT(([](auto) {})(std::move(f)));
// move-assignment into either {valid | invalid}
DOIT({
auto other = makeValid();
@ -206,14 +206,14 @@ STMT; \
auto other = makeInvalid();
other = std::move(f);
});
#undef DOIT
}
TEST(FutureTest, hasPreconditionValid) {
// Ops that require validity; precondition: valid();
// throw FutureInvalid if !valid()
#define DOIT(STMT) \
do { \
auto f = makeValid(); \
@ -221,7 +221,7 @@ STMT; \
::copy(std::move(f)); \
EXPECT_ANY_THROW(STMT); \
} while (false)
DOIT(f.isReady());
DOIT(f.result());
DOIT(std::move(f).get());
@ -233,22 +233,22 @@ EXPECT_ANY_THROW(STMT); \
//DOIT(std::move(f).then());
DOIT(std::move(f).thenValue([](int&&) noexcept -> void {}));
DOIT(std::move(f).thenValue([](auto&&) noexcept -> void {}));
#undef DOIT
}
TEST(FutureTest, hasPostconditionValid) {
// Ops that preserve validity -- postcondition: valid()
#define DOIT(STMT) \
do { \
auto f = makeValid(); \
EXPECT_NO_THROW(STMT); \
ASSERT_TRUE(f.valid()); \
} while (false)
auto const swallow = [](auto) {};
DOIT(swallow(f.valid())); // f.valid() itself preserves validity
DOIT(swallow(f.isReady()));
DOIT(swallow(f.hasValue()));
@ -261,24 +261,24 @@ ASSERT_TRUE(f.valid()); \
DOIT(swallow(f.getTry()));
DOIT(f.wait());
//DOIT(std::move(f.wait()));
#undef DOIT
}
TEST(FutureTest, lacksPostconditionValid) {
// Ops that consume *this -- postcondition: !valid()
#define DOIT(CTOR, STMT) \
do { \
auto f = (CTOR); \
STMT; \
ASSERT_FALSE(f.valid()); \
} while (false)
// move-ctor of {valid|invalid}
DOIT(makeValid(), { auto other{std::move(f)}; });
DOIT(makeInvalid(), { auto other{std::move(f)}; });
// move-assignment of {valid|invalid} into {valid|invalid}
DOIT(makeValid(), {
auto other = makeValid();
@ -296,7 +296,7 @@ ASSERT_FALSE(f.valid()); \
auto other = makeInvalid();
other = std::move(f);
});
// pass-by-value of {valid|invalid}
DOIT(makeValid(), {
auto const byval = [](auto) {};
@ -306,7 +306,7 @@ ASSERT_FALSE(f.valid()); \
auto const byval = [](auto) {};
byval(std::move(f));
});
// other consuming ops
auto const swallow = [](auto) {};
//DOIT(makeValid(), swallow(std::move(f).wait()));
@ -314,10 +314,10 @@ ASSERT_FALSE(f.valid()); \
DOIT(makeValid(), swallow(std::move(f).get()));
DOIT(makeValid(), swallow(std::move(f).get(std::chrono::milliseconds(10))));
//DOIT(makeValid(), swallow(std::move(f).semi()));
#undef DOIT
}
TEST(FutureTest, thenError) {
bool theFlag = false;
auto flag = [&] { theFlag = true; };
@ -327,13 +327,13 @@ f.wait(); \
ASSERT_TRUE(theFlag); \
theFlag = false; \
} while (0);
#define EXPECT_NO_FLAG() \
do { \
ASSERT_FALSE(theFlag); \
theFlag = false; \
} while (0);
// By reference
{
auto f = makeFuture()
@ -342,7 +342,7 @@ theFlag = false; \
EXPECT_FLAG();
EXPECT_NO_THROW(f.get());
}
// By auto reference
{
auto f = makeFuture()
@ -534,7 +534,7 @@ theFlag = false; \
.thenError<eggs_t&>([&](eggs_t& e) -> Future<int> { throw e; });
EXPECT_THROW(f.get(), eggs_t);
}
// // exception_wrapper, return Future<T>
// {
// auto f = makeFuture()
@ -597,7 +597,7 @@ theFlag = false; \
#undef EXPECT_FLAG
#undef EXPECT_NO_FLAG
}
TEST(FutureTest, special) {
ASSERT_FALSE(std::is_copy_constructible<Future<int>>::value);
ASSERT_FALSE(std::is_copy_assignable<Future<int>>::value);
@ -628,23 +628,23 @@ TEST(FutureTest, then) {
std::string value = f.get();
ASSERT_TRUE(value == "1;2;3;4;5;6;7;8;9;10;11");
}
TEST(FutureTest, then_static_functions) {
auto f = makeFuture<int>(10).thenValue(onThenHelperAddFive);
ASSERT_TRUE(f.get() == 15);
auto f2 = makeFuture<int>(15).thenValue(onThenHelperAddFutureFive);
ASSERT_TRUE(f2.get() == 20);
}
TEST(FutureTest, get) {
auto f = makeFuture(std::make_unique<int>(42));
auto up = std::move(f).get();
ASSERT_TRUE(42 == *up);
EXPECT_THROW(makeFuture<int>(eggs).get(), eggs_t);
}
TEST(FutureTest, isReady) {
Promise<int> p;
auto f = p.getFuture();
@ -652,76 +652,76 @@ TEST(FutureTest, isReady) {
p.setValue(42);
ASSERT_TRUE(f.isReady());
}
TEST(FutureTest, futureNotReady) {
Promise<int> p;
Future<int> f = p.getFuture();
EXPECT_THROW(f.result().get(), FutureException);
}
TEST(FutureTest, makeFuture) {
ASSERT_TRUE(makeFuture<int>(eggs).getTry().hasException());
ASSERT_FALSE(makeFuture(42).getTry().hasException());
}
TEST(FutureTest, hasValue) {
ASSERT_TRUE(makeFuture(42).getTry().hasValue());
ASSERT_FALSE(makeFuture<int>(eggs).getTry().hasValue());
}
TEST(FutureTest, makeFuture2) {
//EXPECT_TYPE(makeFuture(42), Future<int>);
ASSERT_TRUE(42 == makeFuture(42).get());
//EXPECT_TYPE(makeFuture<float>(42), Future<float>);
ASSERT_TRUE(42 == makeFuture<float>(42).get());
auto fun = [] { return 42; };
//EXPECT_TYPE(makeFutureWith(fun), Future<int>);
ASSERT_TRUE(42 == makeFutureWith(fun).get());
auto funf = [] { return makeFuture<int>(43); };
//EXPECT_TYPE(makeFutureWith(funf), Future<int>);
ASSERT_TRUE(43 == makeFutureWith(funf).get());
auto failfun = []() -> int { throw eggs; };
//EXPECT_TYPE(makeFutureWith(failfun), Future<int>);
EXPECT_NO_THROW(makeFutureWith(failfun));
EXPECT_THROW(makeFutureWith(failfun).get(), eggs_t);
auto failfunf = []() -> Future<int> { throw eggs; };
//EXPECT_TYPE(makeFutureWith(failfunf), Future<int>);
EXPECT_NO_THROW(makeFutureWith(failfunf));
EXPECT_THROW(makeFutureWith(failfunf).get(), eggs_t);
//EXPECT_TYPE(makeFuture(), Future<Unit>);
}
TEST(FutureTest, finish) {
auto x = std::make_shared<int>(0);
Promise<int> p;
auto f = p.getFuture().then([x](Try<int>&& t) { *x = t.get(); });
// The callback hasn't executed
ASSERT_TRUE(0 == *x);
// The callback has a reference to x
ASSERT_TRUE(2 == x.use_count());
p.setValue(42);
f.wait();
// the callback has executed
ASSERT_EQ(42, *x);
std::this_thread::yield();
// the callback has been destructed
// and has released its reference to x
ASSERT_EQ(1, x.use_count());
}
TEST(FutureTest, detachRace) {
// This test is designed to detect a race that was in Core::detachOne()
// where detached_ was incremented and then tested, and that
@ -737,7 +737,7 @@ TEST(FutureTest, detachRace) {
//folly::Baton<> baton;
std::mutex m;
std::condition_variable condition;
std::unique_lock<std::mutex> guard(m);
std::thread t1([&]{
std::unique_lock<std::mutex> lock(m);
@ -788,7 +788,7 @@ TEST(FutureTest, ImplicitConstructor) {
}
TEST(FutureTest, InPlaceConstructor) {
auto f = Future<std::pair<int, double>>(in_place, 5, 3.2);
auto f = Future<std::pair<int, double>>(std::in_place, 5, 3.2);
ASSERT_TRUE(5 == f.get().first);
}
@ -843,7 +843,7 @@ TEST(FutureTest, invokeCallbackReturningFutureAsRvalue) {
ASSERT_TRUE(202 == makeFuture<int>(200).thenValue(cfoo).get());
ASSERT_TRUE(303 == makeFuture<int>(300).thenValue(Foo()).get());
}
TEST(FutureTest, basic_example) {
Promise<int> p;
Future<int> f = p.getFuture();
@ -851,7 +851,7 @@ TEST(FutureTest, basic_example) {
p.setValue(42);
ASSERT_TRUE(f2.get() == 43);
}
TEST(FutureTest, basic_example_fpointer) {
Promise<int> p;
Future<int> f = p.getFuture();

View File

@ -92,13 +92,13 @@ TEST(FuturesTryTest, Basic) {
}
TEST(FuturesTryTest, in_place) {
Try<A> t_a(in_place, 5);
Try<A> t_a(std::in_place, 5);
ASSERT_TRUE(5 == t_a.get().x());
}
TEST(FuturesTryTest, in_place_nested) {
Try<Try<A>> t_t_a(in_place, in_place, 5);
Try<Try<A>> t_t_a(std::in_place, std::in_place, 5);
ASSERT_TRUE(5 == t_t_a.get().get().x());
}
@ -124,8 +124,8 @@ TEST(FuturesTryTest, assignment_with_throwing_ctor) {
int counter = 0;
{
Try<ThrowingCopyConstructor> t1{in_place, counter};
Try<ThrowingCopyConstructor> t2{in_place, counter};
Try<ThrowingCopyConstructor> t1{std::in_place, counter};
Try<ThrowingCopyConstructor> t2{std::in_place, counter};
ASSERT_TRUE(2 == counter);
EXPECT_ANY_THROW(t2 = t1);
EXPECT_ANY_THROW(t2 = t1);
@ -135,7 +135,7 @@ TEST(FuturesTryTest, assignment_with_throwing_ctor) {
}
ASSERT_TRUE(0 == counter);
{
Try<ThrowingCopyConstructor> t1{in_place, counter};
Try<ThrowingCopyConstructor> t1{std::in_place, counter};
Try<ThrowingCopyConstructor> t2;
ASSERT_TRUE(1 == counter);
EXPECT_ANY_THROW(t2 = t1);
@ -173,12 +173,12 @@ TEST(FuturesTryTest, MoveConstRvalue) {
// where for example MutableContainer has a mutable member that is move only
// and you want to fetch the value from the Try and move it into a member
{
const Try<MutableContainer> t{in_place};
const Try<MutableContainer> t{std::in_place};
auto val = MoveConstructOnly(std::move(t).get().val);
static_cast<void>(val);
}
{
const Try<MutableContainer> t{in_place};
const Try<MutableContainer> t{std::in_place};
auto val = (*(std::move(t))).val;
static_cast<void>(val);
}