From: Yedidya Feldblum Date: Sun, 5 Nov 2017 04:34:13 +0000 (-0700) Subject: Move folly/Functional.h X-Git-Tag: v2017.11.06.00^0 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=05a56e4c1e3313f38f4f891a0b8db684004555e1;p=folly.git Move folly/Functional.h Summary: [Folly] Move `folly/Functional.h` to `folly/lang/RValueReferenceWrapper.h`. Reviewed By: Orvid Differential Revision: D6242160 fbshipit-source-id: a8ec42106cfe0ea617c87d382694d5eb2f0f61a0 --- diff --git a/folly/Functional.h b/folly/Functional.h deleted file mode 100644 index e239e1ac..00000000 --- a/folly/Functional.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2017-present 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 - -namespace folly { - -/** - * Class template that wraps a reference to an rvalue. Similar to - * std::reference_wrapper but with three important differences: - * - * 1) folly::rvalue_reference_wrappers can only be moved, not copied; - * 2) the get() function and the conversion-to-T operator are destructive and - * not const, they invalidate the wrapper; - * 3) the constructor-from-T is explicit. - * - * These restrictions are designed to make it harder to accidentally create a - * a dangling rvalue reference, or to use an rvalue reference multiple times. - * (Using an rvalue reference typically implies invalidation of the target - * object, such as move-assignment to another object.) - * - * @seealso folly::rref - */ -template -class rvalue_reference_wrapper { - public: - using type = T; - - /** - * Default constructor. Creates an invalid reference. Must be move-assigned - * to in order to be come valid. - */ - rvalue_reference_wrapper() noexcept : ptr_(nullptr) {} - - /** - * Explicit constructor to make it harder to accidentally create a dangling - * reference to a temporary. - */ - explicit rvalue_reference_wrapper(T&& ref) noexcept - : ptr_(std::addressof(ref)) {} - - /** - * No construction from lvalue reference. Use std::move. - */ - explicit rvalue_reference_wrapper(T&) noexcept = delete; - - /** - * Destructive move construction. - */ - rvalue_reference_wrapper(rvalue_reference_wrapper&& other) noexcept - : ptr_(other.ptr_) { - other.ptr_ = nullptr; - } - - /** - * Destructive move assignment. - */ - rvalue_reference_wrapper& operator=( - rvalue_reference_wrapper&& other) noexcept { - ptr_ = other.ptr_; - other.ptr_ = nullptr; - return *this; - } - - /** - * Implicit conversion to raw reference. Destructive. - */ - /* implicit */ operator T &&() && noexcept { - return static_cast(*this).get(); - } - - /** - * Explicit unwrap. Destructive. - */ - T&& get() && noexcept { - assert(valid()); - T& ref = *ptr_; - ptr_ = nullptr; - return static_cast(ref); - } - - /** - * Calls the callable object to whom reference is stored. Only available if - * the wrapped reference points to a callable object. Destructive. - */ - template - decltype(auto) operator()(Args&&... args) && - noexcept(noexcept(std::declval()(std::forward(args)...))) { - return static_cast(*this).get()( - std::forward(args)...); - } - - /** - * Check whether wrapped reference is valid. - */ - bool valid() const noexcept { - return ptr_ != nullptr; - } - - private: - // Disallow copy construction and copy assignment, to make it harder to - // accidentally use an rvalue reference multiple times. - rvalue_reference_wrapper(const rvalue_reference_wrapper&) = delete; - rvalue_reference_wrapper& operator=(const rvalue_reference_wrapper&) = delete; - - T* ptr_; -}; - -/** - * Create a folly::rvalue_reference_wrapper. Analogous to std::ref(). - * - * Warning: folly::rvalue_reference_wrappers are potentially dangerous, because - * they can easily be used to capture references to temporary values. Users must - * ensure that the target object outlives the reference wrapper. - * - * @example - * class Object {}; - * void f(Object&&); - * // BAD - * void g() { - * auto ref = folly::rref(Object{}); // create reference to temporary - * f(std::move(ref)); // pass dangling reference - * } - * // GOOD - * void h() { - * Object o; - * auto ref = folly::rref(std::move(o)); - * f(std::move(ref)); - * } - */ -template -rvalue_reference_wrapper rref(T&& value) noexcept { - return rvalue_reference_wrapper(std::move(value)); -} -template -rvalue_reference_wrapper rref(T&) noexcept = delete; -} // namespace folly diff --git a/folly/Makefile.am b/folly/Makefile.am index e1c0e464..37f95d1c 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -314,6 +314,7 @@ nobase_follyinclude_HEADERS = \ json.h \ lang/Assume.h \ lang/Launder.h \ + lang/RValueReferenceWrapper.h \ lang/SafeAssert.h \ Lazy.h \ LifoSem.h \ @@ -453,7 +454,6 @@ nobase_follyinclude_HEADERS = \ Try.h \ Unicode.h \ Function.h \ - Functional.h \ UncaughtExceptions.h \ Unit.h \ Uri.h \ diff --git a/folly/container/Iterator.h b/folly/container/Iterator.h index 1c316950..7db1136e 100644 --- a/folly/container/Iterator.h +++ b/folly/container/Iterator.h @@ -23,7 +23,7 @@ #include #include -#include +#include namespace folly { diff --git a/folly/lang/RValueReferenceWrapper.h b/folly/lang/RValueReferenceWrapper.h new file mode 100644 index 00000000..e239e1ac --- /dev/null +++ b/folly/lang/RValueReferenceWrapper.h @@ -0,0 +1,154 @@ +/* + * Copyright 2017-present 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 + +namespace folly { + +/** + * Class template that wraps a reference to an rvalue. Similar to + * std::reference_wrapper but with three important differences: + * + * 1) folly::rvalue_reference_wrappers can only be moved, not copied; + * 2) the get() function and the conversion-to-T operator are destructive and + * not const, they invalidate the wrapper; + * 3) the constructor-from-T is explicit. + * + * These restrictions are designed to make it harder to accidentally create a + * a dangling rvalue reference, or to use an rvalue reference multiple times. + * (Using an rvalue reference typically implies invalidation of the target + * object, such as move-assignment to another object.) + * + * @seealso folly::rref + */ +template +class rvalue_reference_wrapper { + public: + using type = T; + + /** + * Default constructor. Creates an invalid reference. Must be move-assigned + * to in order to be come valid. + */ + rvalue_reference_wrapper() noexcept : ptr_(nullptr) {} + + /** + * Explicit constructor to make it harder to accidentally create a dangling + * reference to a temporary. + */ + explicit rvalue_reference_wrapper(T&& ref) noexcept + : ptr_(std::addressof(ref)) {} + + /** + * No construction from lvalue reference. Use std::move. + */ + explicit rvalue_reference_wrapper(T&) noexcept = delete; + + /** + * Destructive move construction. + */ + rvalue_reference_wrapper(rvalue_reference_wrapper&& other) noexcept + : ptr_(other.ptr_) { + other.ptr_ = nullptr; + } + + /** + * Destructive move assignment. + */ + rvalue_reference_wrapper& operator=( + rvalue_reference_wrapper&& other) noexcept { + ptr_ = other.ptr_; + other.ptr_ = nullptr; + return *this; + } + + /** + * Implicit conversion to raw reference. Destructive. + */ + /* implicit */ operator T &&() && noexcept { + return static_cast(*this).get(); + } + + /** + * Explicit unwrap. Destructive. + */ + T&& get() && noexcept { + assert(valid()); + T& ref = *ptr_; + ptr_ = nullptr; + return static_cast(ref); + } + + /** + * Calls the callable object to whom reference is stored. Only available if + * the wrapped reference points to a callable object. Destructive. + */ + template + decltype(auto) operator()(Args&&... args) && + noexcept(noexcept(std::declval()(std::forward(args)...))) { + return static_cast(*this).get()( + std::forward(args)...); + } + + /** + * Check whether wrapped reference is valid. + */ + bool valid() const noexcept { + return ptr_ != nullptr; + } + + private: + // Disallow copy construction and copy assignment, to make it harder to + // accidentally use an rvalue reference multiple times. + rvalue_reference_wrapper(const rvalue_reference_wrapper&) = delete; + rvalue_reference_wrapper& operator=(const rvalue_reference_wrapper&) = delete; + + T* ptr_; +}; + +/** + * Create a folly::rvalue_reference_wrapper. Analogous to std::ref(). + * + * Warning: folly::rvalue_reference_wrappers are potentially dangerous, because + * they can easily be used to capture references to temporary values. Users must + * ensure that the target object outlives the reference wrapper. + * + * @example + * class Object {}; + * void f(Object&&); + * // BAD + * void g() { + * auto ref = folly::rref(Object{}); // create reference to temporary + * f(std::move(ref)); // pass dangling reference + * } + * // GOOD + * void h() { + * Object o; + * auto ref = folly::rref(std::move(o)); + * f(std::move(ref)); + * } + */ +template +rvalue_reference_wrapper rref(T&& value) noexcept { + return rvalue_reference_wrapper(std::move(value)); +} +template +rvalue_reference_wrapper rref(T&) noexcept = delete; +} // namespace folly diff --git a/folly/lang/test/RValueReferenceWrapperTest.cpp b/folly/lang/test/RValueReferenceWrapperTest.cpp new file mode 100644 index 00000000..7f44aa77 --- /dev/null +++ b/folly/lang/test/RValueReferenceWrapperTest.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2017 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 + +TEST(RvalueReferenceWrapper, MoveAndConvert) { + using folly::rvalue_reference_wrapper; + + // Destructive moves. + int i1 = 0; + rvalue_reference_wrapper rref1(std::move(i1)); + ASSERT_TRUE(rref1.valid()); + rvalue_reference_wrapper rref0(std::move(rref1)); + ASSERT_TRUE(rref0.valid()); + ASSERT_FALSE(rref1.valid()); + rref1 = std::move(rref0); + ASSERT_FALSE(rref0.valid()); + ASSERT_TRUE(rref1.valid()); + const int& r1 = std::move(rref1); + ASSERT_FALSE(rref1.valid()); + ASSERT_EQ(&r1, &i1); + + // Destructive unwrap to T&&. + int i2 = 0; + rvalue_reference_wrapper rref2(std::move(i2)); + int&& r2 = std::move(rref2); + ASSERT_EQ(&r2, &i2); + + // Destructive unwrap to const T&. + const int i3 = 0; + rvalue_reference_wrapper rref3(std::move(i3)); + const int& r3 = std::move(rref3); + ASSERT_EQ(&r3, &i3); + + // Destructive unwrap to const T&&. + const int i4 = 0; + rvalue_reference_wrapper rref4(std::move(i4)); + const int&& r4 = std::move(rref4); + ASSERT_EQ(&r4, &i4); + + /* + * Things that intentionally do not compile. Copy construction, copy + * assignment, unwrap of lvalue reference to wrapper, const violations. + * + int i5; + const int i6 = 0; + rvalue_reference_wrapper rref5(i5); + rvalue_reference_wrapper rref6(i6); + rref1 = rref5; + int& r5 = rref5; + const int& r6 = rref6; + int i7; + const rvalue_reference_wrapper rref7(std::move(i7)); + int& r7 = std::move(rref7); + */ +} + +TEST(RvalueReferenceWrapper, Call) { + int a = 4711, b, c; + auto callMe = [&](int x, const int& y, int&& z) -> int { + EXPECT_EQ(a, x); + EXPECT_EQ(&b, &y); + EXPECT_EQ(&c, &z); + return a; + }; + int result = folly::rref(std::move(callMe))(a, b, std::move(c)); + EXPECT_EQ(a, result); +} diff --git a/folly/test/FunctionalTest.cpp b/folly/test/FunctionalTest.cpp deleted file mode 100644 index f8a81f1b..00000000 --- a/folly/test/FunctionalTest.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2017 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 - -TEST(RvalueReferenceWrapper, MoveAndConvert) { - using folly::rvalue_reference_wrapper; - - // Destructive moves. - int i1 = 0; - rvalue_reference_wrapper rref1(std::move(i1)); - ASSERT_TRUE(rref1.valid()); - rvalue_reference_wrapper rref0(std::move(rref1)); - ASSERT_TRUE(rref0.valid()); - ASSERT_FALSE(rref1.valid()); - rref1 = std::move(rref0); - ASSERT_FALSE(rref0.valid()); - ASSERT_TRUE(rref1.valid()); - const int& r1 = std::move(rref1); - ASSERT_FALSE(rref1.valid()); - ASSERT_EQ(&r1, &i1); - - // Destructive unwrap to T&&. - int i2 = 0; - rvalue_reference_wrapper rref2(std::move(i2)); - int&& r2 = std::move(rref2); - ASSERT_EQ(&r2, &i2); - - // Destructive unwrap to const T&. - const int i3 = 0; - rvalue_reference_wrapper rref3(std::move(i3)); - const int& r3 = std::move(rref3); - ASSERT_EQ(&r3, &i3); - - // Destructive unwrap to const T&&. - const int i4 = 0; - rvalue_reference_wrapper rref4(std::move(i4)); - const int&& r4 = std::move(rref4); - ASSERT_EQ(&r4, &i4); - - /* - * Things that intentionally do not compile. Copy construction, copy - * assignment, unwrap of lvalue reference to wrapper, const violations. - * - int i5; - const int i6 = 0; - rvalue_reference_wrapper rref5(i5); - rvalue_reference_wrapper rref6(i6); - rref1 = rref5; - int& r5 = rref5; - const int& r6 = rref6; - int i7; - const rvalue_reference_wrapper rref7(std::move(i7)); - int& r7 = std::move(rref7); - */ -} - -TEST(RvalueReferenceWrapper, Call) { - int a = 4711, b, c; - auto callMe = [&](int x, const int& y, int&& z) -> int { - EXPECT_EQ(a, x); - EXPECT_EQ(&b, &y); - EXPECT_EQ(&c, &z); - return a; - }; - int result = folly::rref(std::move(callMe))(a, b, std::move(c)); - EXPECT_EQ(a, result); -} diff --git a/folly/test/Makefile.am b/folly/test/Makefile.am index e5da5010..4bf6b29d 100644 --- a/folly/test/Makefile.am +++ b/folly/test/Makefile.am @@ -328,10 +328,10 @@ function_test_SOURCES = \ function_test_LDADD = libfollytestmain.la TESTS += function_test -functional_test_SOURCES = \ - FunctionalTest.cpp -functional_test_LDADD = libfollytestmain.la -TESTS += functional_test +rvalue_reference_wrapper_test_SOURCES = \ + ../lang/RValueReferenceWrapperTest.cpp +rvalue_reference_wrapper_test_LDADD = libfollytestmain.la +TESTS += rvalue_reference_wrapper_test ssl_test_SOURCES = \ ../ssl/test/OpenSSLHashTest.cpp