Commit ec5f59cf authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

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
parent 1c3b25b2
......@@ -376,6 +376,7 @@ nobase_follyinclude_HEADERS = \
Unit.h \
Uri.h \
Uri-inl.h \
Utility.h \
Varint.h \
VersionCheck.h
......
/*
* 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);
}
}
......@@ -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)
/*
* 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
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment