#include <stdexcept>
#include <vector>
-#include <folly/Optional.h>
+#include <folly/Executor.h>
+#include <folly/Function.h>
#include <folly/MicroSpinLock.h>
-
-#include <folly/futures/Try.h>
-#include <folly/futures/Promise.h>
+#include <folly/Optional.h>
#include <folly/futures/Future.h>
-#include <folly/Executor.h>
+#include <folly/futures/Promise.h>
+#include <folly/futures/Try.h>
#include <folly/futures/detail/FSM.h>
#include <folly/io/async/Request.h>
}
}
- template <typename F>
- class LambdaBufHelper {
- public:
- template <typename FF>
- explicit LambdaBufHelper(FF&& func) : func_(std::forward<FF>(func)) {}
- void operator()(Try<T>&& t) {
- SCOPE_EXIT { this->~LambdaBufHelper(); };
- func_(std::move(t));
- }
- private:
- F func_;
- };
-
/// Call only from Future thread.
template <typename F>
void setCallback(F func) {
bool transitionToArmed = false;
auto setCallback_ = [&]{
context_ = RequestContext::saveContext();
-
- // Move the lambda into the Core if it fits
- if (sizeof(LambdaBufHelper<F>) <= lambdaBufSize) {
- auto funcLoc = reinterpret_cast<LambdaBufHelper<F>*>(&lambdaBuf_);
- new (funcLoc) LambdaBufHelper<F>(std::forward<F>(func));
- callback_ = std::ref(*funcLoc);
- } else {
- callback_ = std::move(func);
- }
+ callback_ = std::move(func);
};
FSM_START(fsm_)
// sizeof(Core<T>) == size(Core<U>).
// See Core::convert for details.
- // lambdaBuf occupies exactly one cache line
- static constexpr size_t lambdaBufSize = 8 * sizeof(void*);
- typename std::aligned_storage<lambdaBufSize>::type lambdaBuf_;
+ folly::Function<
+ void(Try<T>&&),
+ folly::FunctionMoveCtor::MAY_THROW,
+ 8 * sizeof(void*)>
+ callback_;
// place result_ next to increase the likelihood that the value will be
// contained entirely in one cache line
folly::Optional<Try<T>> result_;
- std::function<void(Try<T>&&)> callback_ {nullptr};
FSM<State> fsm_;
std::atomic<unsigned char> attached_;
std::atomic<bool> active_ {true};
--- /dev/null
+/*
+ * Copyright 2016 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>
+
+using namespace folly;
+
+TEST(NonCopyableLambda, basic) {
+ Promise<int> promise;
+ Future<int> future = promise.getFuture();
+
+ Future<Unit>().then(std::bind(
+ [](Promise<int>& promise) mutable { promise.setValue(123); },
+ std::move(promise)));
+
+ // The previous statement can be simplified in C++14:
+ // Future<Unit>().then([promise = std::move(promise)]() mutable {
+ // promise.setValue(123);
+ // });
+
+ EXPECT_TRUE(future.isReady());
+ EXPECT_EQ(future.get(), 123);
+}
+
+TEST(NonCopyableLambda, unique_ptr) {
+ Promise<Unit> promise;
+ auto int_ptr = folly::make_unique<int>(1);
+
+ EXPECT_EQ(*int_ptr, 1);
+
+ auto future = promise.getFuture().then(std::bind(
+ [](std::unique_ptr<int>& int_ptr) mutable {
+ ++*int_ptr;
+ return std::move(int_ptr);
+ },
+ std::move(int_ptr)));
+
+ // The previous statement can be simplified in C++14:
+ // auto future =
+ // promise.getFuture().then([int_ptr = std::move(int_ptr)]() mutable {
+ // ++*int_ptr;
+ // return std::move(int_ptr);
+ // });
+
+ EXPECT_FALSE(future.isReady());
+ promise.setValue();
+ EXPECT_TRUE(future.isReady());
+ EXPECT_EQ(*future.get(), 2);
+}
+
+TEST(NonCopyableLambda, Function) {
+ Promise<int> promise;
+
+ Function<int(int)> callback = [](int x) { return x + 1; };
+
+ auto future = promise.getFuture().then(std::move(callback));
+ EXPECT_THROW(callback(0), std::bad_function_call);
+
+ EXPECT_FALSE(future.isReady());
+ promise.setValue(100);
+ EXPECT_TRUE(future.isReady());
+ EXPECT_EQ(future.get(), 101);
+}
+
+TEST(NonCopyableLambda, FunctionConst) {
+ Promise<int> promise;
+
+ Function<int(int) const> callback = [](int x) { return x + 1; };
+
+ auto future = promise.getFuture().then(std::move(callback));
+ EXPECT_THROW(callback(0), std::bad_function_call);
+
+ EXPECT_FALSE(future.isReady());
+ promise.setValue(100);
+ EXPECT_TRUE(future.isReady());
+ EXPECT_EQ(future.get(), 101);
+}