--- /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.
+ */
+
+#pragma once
+
+#include <type_traits>
+#include <utility>
+
+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 <class T> decay_t<T> decay_copy(T&& v)
+ * > { return std::forward<T>(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 <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);
+}
+}
--- /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 <folly/Utility.h>
+
+#include <gtest/gtest.h>
+
+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
+}