From ec5f59cf16844e37c3915f9df69099bba63062b1 Mon Sep 17 00:00:00 2001 From: Yedidya Feldblum Date: Wed, 28 Dec 2016 18:03:39 -0800 Subject: [PATCH] folly::copy Summary: [Folly] `folly::copy`. Usable when you have a function with two overloads: class MyData; void something(MyData&&); void something(const MyData&); Where the purpose is to make copies and moves explicit without having to spell out the full type names - in this case, for copies, to invoke copy constructors. When the caller wants to pass a copy of an lvalue, the caller may: void foo() { MyData data; something(folly::copy(data)); // explicit copy something(std::move(data)); // explicit move something(data); // const& - neither move nor copy } Reviewed By: markisaa, ericniebler Differential Revision: D3462023 fbshipit-source-id: 6c777be288f2a7012c1b4b46dc988890b8662595 --- folly/Makefile.am | 1 + folly/Utility.h | 71 ++++++++++++++++++++++++++++++++++++++ folly/test/Makefile.am | 4 +++ folly/test/UtilityTest.cpp | 61 ++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 folly/Utility.h create mode 100644 folly/test/UtilityTest.cpp diff --git a/folly/Makefile.am b/folly/Makefile.am index 085418ce..6c6d4baf 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -376,6 +376,7 @@ nobase_follyinclude_HEADERS = \ Unit.h \ Uri.h \ Uri-inl.h \ + Utility.h \ Varint.h \ VersionCheck.h diff --git a/folly/Utility.h b/folly/Utility.h new file mode 100644 index 00000000..ce5b1536 --- /dev/null +++ b/folly/Utility.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +namespace folly { + +/** + * copy + * + * Usable when you have a function with two overloads: + * + * class MyData; + * void something(MyData&&); + * void something(const MyData&); + * + * Where the purpose is to make copies and moves explicit without having to + * spell out the full type names - in this case, for copies, to invoke copy + * constructors. + * + * When the caller wants to pass a copy of an lvalue, the caller may: + * + * void foo() { + * MyData data; + * something(folly::copy(data)); // explicit copy + * something(std::move(data)); // explicit move + * something(data); // const& - neither move nor copy + * } + * + * Note: If passed an rvalue, invokes the move-ctor, not the copy-ctor. This + * can be used to to force a move, where just using std::move would not: + * + * std::copy(std::move(data)); // force-move, not just a cast to && + * + * Note: The following text appears in the standard: + * + * > In several places in this Clause the operation //DECAY_COPY(x)// is used. + * > All such uses mean call the function `decay_copy(x)` and use the result, + * > where `decay_copy` is defined as follows: + * > + * > template decay_t decay_copy(T&& v) + * > { return std::forward(v); } + * > + * > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf + * > 30.2.6 `decay_copy` [thread.decaycopy]. + * + * We mimic it, with a `noexcept` specifier for good measure. + */ + +template +constexpr typename std::decay::type copy(T&& value) noexcept( + noexcept(typename std::decay::type(std::forward(value)))) { + return std::forward(value); +} +} diff --git a/folly/test/Makefile.am b/folly/test/Makefile.am index f2785b38..77a3ae84 100644 --- a/folly/test/Makefile.am +++ b/folly/test/Makefile.am @@ -319,4 +319,8 @@ singleton_thread_local_test_SOURCES = SingletonThreadLocalTest.cpp singleton_thread_local_test_LDADD = libfollytestmain.la TESTS += singleton_thread_local_test +utility_test_SOURCES = UtilityTest.cpp +utility_test_LDADD = libfollytestmain.la +TESTS += utility_test + check_PROGRAMS += $(TESTS) diff --git a/folly/test/UtilityTest.cpp b/folly/test/UtilityTest.cpp new file mode 100644 index 00000000..9bd58da4 --- /dev/null +++ b/folly/test/UtilityTest.cpp @@ -0,0 +1,61 @@ +/* + * 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 + +#include + +namespace { + +class UtilityTest : public testing::Test {}; +} + +TEST_F(UtilityTest, copy) { + struct MyData {}; + struct Worker { + size_t rrefs = 0, crefs = 0; + void something(MyData&&) { + ++rrefs; + } + void something(const MyData&) { + ++crefs; + } + }; + + MyData data; + Worker worker; + worker.something(folly::copy(data)); + worker.something(std::move(data)); + worker.something(data); + EXPECT_EQ(2, worker.rrefs); + EXPECT_EQ(1, worker.crefs); +} + +TEST_F(UtilityTest, copy_noexcept_spec) { + struct MyNoexceptCopyable {}; + MyNoexceptCopyable noe; + EXPECT_TRUE(noexcept(folly::copy(noe))); + EXPECT_TRUE(noexcept(folly::copy(std::move(noe)))); + + struct MyThrowingCopyable { + MyThrowingCopyable() {} + MyThrowingCopyable(const MyThrowingCopyable&) noexcept(false) {} + MyThrowingCopyable(MyThrowingCopyable&&) = default; + }; + MyThrowingCopyable thr; + EXPECT_FALSE(noexcept(folly::copy(thr))); + EXPECT_TRUE(noexcept(folly::copy(std::move(thr)))); // note: does not copy +} -- 2.34.1