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

Cut FOLLY_IS_TRIVIALLY_COPYABLE macro

Summary:
[Folly] Cut `FOLLY_IS_TRIVIALLY_COPYABLE` macro, replacing all uses with `folly::is_trivially_copyable`.

And cut `folly::IsTriviallyCopyable` with member-type-detection support, and move `folly::traits_detail::is_trivially_copyable` to `folly::is_trivially_copyable`.

`FOLLY_IS_TRIVIALLY_COPYABLE` and `folly::IsTriviallyCopyable` were there to support gcc < 5.

Reviewed By: Orvid

Differential Revision: D8246972

fbshipit-source-id: 8af9bbdbfac8671a61ebaa200dbfd2426a40d2eb
parent 101c87e4
......@@ -248,7 +248,7 @@ struct DoNotOptimizeAwayNeedsIndirect {
// First two constraints ensure it can be an "r" operand.
// std::is_pointer check is because callers seem to expect that
// doNotOptimizeAway(&x) is equivalent to doNotOptimizeAway(x).
constexpr static bool value = !folly::IsTriviallyCopyable<Decayed>::value ||
constexpr static bool value = !folly::is_trivially_copyable<Decayed>::value ||
sizeof(Decayed) > sizeof(long) || std::is_pointer<Decayed>::value;
};
} // namespace detail
......
......@@ -168,7 +168,7 @@ enum class StorageType { ePODStruct, ePODUnion, eUnion };
template <class Value, class Error>
constexpr StorageType getStorageType() {
return StrictAllOf<IsTriviallyCopyable, Value, Error>::value
return StrictAllOf<is_trivially_copyable, Value, Error>::value
? (sizeof(std::pair<Value, Error>) <= sizeof(void * [2]) &&
StrictAllOf<std::is_trivial, Value, Error>::value
? StorageType::ePODStruct
......@@ -903,8 +903,6 @@ class Expected final : expected_detail::ExpectedStorage<Value, Error> {
public:
using value_type = Value;
using error_type = Error;
using IsTriviallyCopyable = typename expected_detail::
StrictAllOf<IsTriviallyCopyable, Value, Error>::type;
template <class U>
using rebind = Expected<U, Error>;
......
......@@ -208,10 +208,12 @@ class fbvector {
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
private:
typedef std::integral_constant<bool,
IsTriviallyCopyable<T>::value &&
sizeof(T) <= 16 // don't force large structures to be passed by value
> should_pass_by_value;
typedef std::integral_constant<
bool,
is_trivially_copyable<T>::value &&
sizeof(T) <= 16 // don't force large structures to be passed by value
>
should_pass_by_value;
typedef typename std::conditional<
should_pass_by_value::value, T, const T&>::type VT;
typedef typename std::conditional<
......@@ -485,7 +487,7 @@ class fbvector {
template <typename It>
void D_uninitialized_copy_a(T* dest, It first, It last) {
if (usingStdAllocator::value) {
if (folly::IsTriviallyCopyable<T>::value) {
if (folly::is_trivially_copyable<T>::value) {
S_uninitialized_copy_bits(dest, first, last);
} else {
S_uninitialized_copy(dest, first, last);
......@@ -570,7 +572,7 @@ class fbvector {
}
static const T* S_copy_n(T* dest, const T* first, size_type n) {
if (folly::IsTriviallyCopyable<T>::value) {
if (is_trivially_copyable<T>::value) {
std::memcpy((void*)dest, (void*)first, n * sizeof(T));
return first + n;
} else {
......@@ -580,7 +582,7 @@ class fbvector {
static std::move_iterator<T*>
S_copy_n(T* dest, std::move_iterator<T*> mIt, size_type n) {
if (folly::IsTriviallyCopyable<T>::value) {
if (is_trivially_copyable<T>::value) {
T* first = mIt.base();
std::memcpy((void*)dest, (void*)first, n * sizeof(T));
return std::make_move_iterator(first + n);
......
......@@ -417,7 +417,6 @@ nobase_follyinclude_HEADERS = \
portability/SysTypes.h \
portability/SysUio.h \
portability/Time.h \
portability/TypeTraits.h \
portability/Unistd.h \
portability/Windows.h \
Preprocessor.h \
......
......@@ -286,6 +286,19 @@ using type_t = typename traits_detail::type_t_<T, Ts...>::type;
template <class... Ts>
using void_t = type_t<void, Ts...>;
// Older versions of libstdc++ do not provide std::is_trivially_copyable
#if defined(__clang__) && !defined(_LIBCPP_VERSION)
template <class T>
struct is_trivially_copyable
: std::integral_constant<bool, __is_trivially_copyable(T)> {};
#elif defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5
template <class T>
struct is_trivially_copyable : std::is_trivial<T> {};
#else
template <class T>
using is_trivially_copyable = std::is_trivially_copyable<T>;
#endif
/**
* IsRelocatable<T>::value describes the ability of moving around
* memory a value of type T by using memcpy (as opposed to the
......@@ -323,11 +336,6 @@ using void_t = type_t<void, Ts...>;
*
* It may be unset in a base class by overriding the typedef to false_type.
*/
/*
* IsTriviallyCopyable describes the value semantics property. C++11 contains
* the type trait is_trivially_copyable; however, it is not yet implemented
* in gcc (as of 4.7.1), and the user may wish to specify otherwise.
*/
/*
* IsZeroInitializable describes the property that default construction is the
* same as memset(dst, 0, sizeof(T)).
......@@ -347,22 +355,9 @@ namespace traits_detail {
FOLLY_HAS_TRUE_XXX(IsRelocatable);
FOLLY_HAS_TRUE_XXX(IsZeroInitializable);
FOLLY_HAS_TRUE_XXX(IsTriviallyCopyable);
#undef FOLLY_HAS_TRUE_XXX
// Older versions of libstdc++ do not provide std::is_trivially_copyable
#if defined(__clang__) && !defined(_LIBCPP_VERSION)
template <class T>
struct is_trivially_copyable
: std::integral_constant<bool, __is_trivially_copyable(T)> {};
#elif defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5
template <class T>
struct is_trivially_copyable : std::is_trivial<T> {};
#else
template <class T>
using is_trivially_copyable = std::is_trivially_copyable<T>;
#endif
} // namespace traits_detail
struct Ignore {
......@@ -431,21 +426,14 @@ struct IsNothrowSwappable
/* using override */ using traits_detail_IsNothrowSwappable::IsNothrowSwappable;
template <class T> struct IsTriviallyCopyable
: std::conditional<
traits_detail::has_IsTriviallyCopyable<T>::value,
traits_detail::has_true_IsTriviallyCopyable<T>,
traits_detail::is_trivially_copyable<T>
>::type {};
template <class T> struct IsRelocatable
: std::conditional<
traits_detail::has_IsRelocatable<T>::value,
traits_detail::has_true_IsRelocatable<T>,
// TODO add this line (and some tests for it) when we upgrade to gcc 4.7
//std::is_trivially_move_constructible<T>::value ||
IsTriviallyCopyable<T>
>::type {};
template <class T>
struct IsRelocatable : std::conditional<
traits_detail::has_IsRelocatable<T>::value,
traits_detail::has_true_IsRelocatable<T>,
// TODO add this line (and some tests for it) when we
// upgrade to gcc 4.7
// std::is_trivially_move_constructible<T>::value ||
is_trivially_copyable<T>>::type {};
template <class T> struct IsZeroInitializable
: std::conditional<
......
......@@ -921,7 +921,7 @@ class VectorContainerPolicy : public BasePolicy<
return folly::AllocatorHasDefaultObjectConstruct<Alloc, Value, Value>::
value &&
folly::AllocatorHasDefaultObjectDestroy<Alloc, Value>::value &&
FOLLY_IS_TRIVIALLY_COPYABLE(Value);
folly::is_trivially_copyable<Value>::value;
}
public:
......
......@@ -42,7 +42,6 @@
#include <folly/lang/Launder.h>
#include <folly/lang/SafeAssert.h>
#include <folly/portability/Builtins.h>
#include <folly/portability/TypeTraits.h>
#include <folly/container/detail/F14Defaults.h>
#include <folly/container/detail/F14IntrinsicsAvailability.h>
......@@ -1379,8 +1378,8 @@ class F14Table : public Policy {
// partial failure should not occur. Sorry for the subtle invariants
// in the Policy API.
if (FOLLY_IS_TRIVIALLY_COPYABLE(Item) && !this->destroyItemOnClear() &&
bucket_count() == src.bucket_count()) {
if (folly::is_trivially_copyable<Item>::value &&
!this->destroyItemOnClear() && bucket_count() == src.bucket_count()) {
// most happy path
auto n = allocSize(chunkMask_ + 1, bucket_count());
std::memcpy(&chunks_[0], &src.chunks_[0], n);
......
......@@ -25,8 +25,8 @@
#include <boost/noncopyable.hpp>
#include <folly/Portability.h>
#include <folly/Traits.h>
#include <folly/detail/TurnSequencer.h>
#include <folly/portability/TypeTraits.h>
#include <folly/portability/Unistd.h>
namespace folly {
......@@ -62,7 +62,7 @@ class LockFreeRingBuffer: boost::noncopyable {
"Element type must be nothrow default constructible");
static_assert(
FOLLY_IS_TRIVIALLY_COPYABLE(T),
folly::is_trivially_copyable<T>::value,
"Element type must be trivially copyable");
public:
......
......@@ -633,10 +633,12 @@ TEST(Collect, collectNParallel) {
/// Ensure that we can compile collectAll/Any with folly::small_vector
TEST(Collect, smallVector) {
static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<Unit>),
"Futures should not be trivially copyable");
static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(Future<int>),
"Futures should not be trivially copyable");
static_assert(
!folly::is_trivially_copyable<Future<Unit>>::value,
"Futures should not be trivially copyable");
static_assert(
!folly::is_trivially_copyable<Future<int>>::value,
"Futures should not be trivially copyable");
{
folly::small_vector<Future<Unit>> futures;
......
/*
* Copyright 2016-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
// Unfortunately, boost::has_trivial_copy<T> is broken in libc++ due to its
// usage of __has_trivial_copy(), so we can't use it as a
// least-common-denominator for C++11 implementations that don't support
// std::is_trivially_copyable<T>.
//
// http://stackoverflow.com/questions/12754886/has-trivial-copy-behaves-differently-in-clang-and-gcc-whos-right
//
// As a result, use std::is_trivially_copyable() where it exists, and fall back
// to Boost otherwise.
#if FOLLY_HAVE_STD__IS_TRIVIALLY_COPYABLE
#include <type_traits>
#define FOLLY_IS_TRIVIALLY_COPYABLE(T) (std::is_trivially_copyable<T>::value)
#else
#include <boost/type_traits.hpp>
#define FOLLY_IS_TRIVIALLY_COPYABLE(T) \
(boost::has_trivial_copy<T>::value && boost::has_trivial_destructor<T>::value)
#endif
......@@ -52,7 +52,6 @@
#include <folly/lang/Exception.h>
#include <folly/memory/Malloc.h>
#include <folly/portability/Malloc.h>
#include <folly/portability/TypeTraits.h>
#if (FOLLY_X64 || FOLLY_PPC64)
#define FOLLY_SV_PACK_ATTR FOLLY_PACK_ATTR
......@@ -102,7 +101,7 @@ namespace detail {
* memory is initialized to type T already.
*/
template <class T>
typename std::enable_if<!FOLLY_IS_TRIVIALLY_COPYABLE(T)>::type
typename std::enable_if<!folly::is_trivially_copyable<T>::value>::type
moveObjectsRight(T* first, T* lastConstructed, T* realLast) {
if (lastConstructed == realLast) {
return;
......@@ -139,7 +138,7 @@ moveObjectsRight(T* first, T* lastConstructed, T* realLast) {
// std::move_backward here will just turn into a memmove. (TODO:
// change to std::is_trivially_copyable when that works.)
template <class T>
typename std::enable_if<FOLLY_IS_TRIVIALLY_COPYABLE(T)>::type
typename std::enable_if<folly::is_trivially_copyable<T>::value>::type
moveObjectsRight(T* first, T* lastConstructed, T* realLast) {
std::move_backward(first, lastConstructed, realLast);
}
......@@ -222,7 +221,7 @@ struct IntegralSizePolicy<SizeType, true>
* ranges don't overlap.
*/
template <class T>
typename std::enable_if<!FOLLY_IS_TRIVIALLY_COPYABLE(T)>::type
typename std::enable_if<!folly::is_trivially_copyable<T>::value>::type
moveToUninitialized(T* first, T* last, T* out) {
std::size_t idx = 0;
try {
......@@ -244,7 +243,7 @@ struct IntegralSizePolicy<SizeType, true>
// Specialization for trivially copyable types.
template <class T>
typename std::enable_if<FOLLY_IS_TRIVIALLY_COPYABLE(T)>::type
typename std::enable_if<folly::is_trivially_copyable<T>::value>::type
moveToUninitialized(T* first, T* last, T* out) {
std::memmove(out, first, (last - first) * sizeof *first);
}
......
......@@ -59,7 +59,7 @@ class AtomicStruct {
static_assert(alignof(T) <= alignof(Raw), "underlying type is under-aligned");
static_assert(sizeof(T) <= sizeof(Raw), "underlying type is under-sized");
static_assert(
std::is_trivial<T>::value || folly::IsTriviallyCopyable<T>::value,
std::is_trivial<T>::value || is_trivially_copyable<T>::value,
"target type must be trivially copyable");
Atom<Raw> data;
......
......@@ -50,7 +50,7 @@ class Tearable {
// We memcpy the object representation, and the destructor would not know how
// to deal with an object state it doesn't understand.
static_assert(
IsTriviallyCopyable<T>::value,
is_trivially_copyable<T>::value,
"Tearable types must be trivially copyable.");
Tearable() = default;
......
......@@ -26,8 +26,6 @@ using namespace folly;
namespace {
struct Data {
using IsTriviallyCopyable = std::true_type;
Data(unsigned char value) {
setValue(value);
}
......@@ -54,6 +52,7 @@ struct Data {
// sanitizers.
unsigned char contents[99];
};
static_assert(is_trivially_copyable<Data>::value, "not trivially-copyable");
TEST(TearableTest, BasicOperations) {
Tearable<Data> tearable;
......
......@@ -615,26 +615,26 @@ struct WithConstructor {
TEST(Expected, TriviallyCopyable) {
// These could all be static_asserts but EXPECT_* give much nicer output on
// failure.
EXPECT_TRUE((IsTriviallyCopyable<Expected<int, E>>::value));
EXPECT_TRUE((IsTriviallyCopyable<Expected<char*, E>>::value));
EXPECT_TRUE((is_trivially_copyable<Expected<int, E>>::value));
EXPECT_TRUE((is_trivially_copyable<Expected<char*, E>>::value));
EXPECT_TRUE(
(IsTriviallyCopyable<Expected<NoDestructor, E>>::value));
(is_trivially_copyable<Expected<NoDestructor, E>>::value));
EXPECT_FALSE(
(IsTriviallyCopyable<Expected<WithDestructor, E>>::value));
(is_trivially_copyable<Expected<WithDestructor, E>>::value));
EXPECT_TRUE(
(IsTriviallyCopyable<Expected<NoConstructor, E>>::value));
(is_trivially_copyable<Expected<NoConstructor, E>>::value));
EXPECT_FALSE(
(IsTriviallyCopyable<Expected<std::string, E>>::value));
(is_trivially_copyable<Expected<std::string, E>>::value));
EXPECT_FALSE(
(IsTriviallyCopyable<Expected<int, std::string>>::value));
(is_trivially_copyable<Expected<int, std::string>>::value));
// libstdc++ with GCC 4.x doesn't have std::is_trivially_copyable
#if (defined(__clang__) && !defined(_LIBCPP_VERSION)) || \
!(defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5)
EXPECT_TRUE(
(IsTriviallyCopyable<Expected<WithConstructor, E>>::value));
(is_trivially_copyable<Expected<WithConstructor, E>>::value));
#endif
EXPECT_TRUE(
(IsTriviallyCopyable<Expected<Expected<int, E>, E>>::value));
(is_trivially_copyable<Expected<Expected<int, E>, E>>::value));
}
TEST(Expected, Then) {
......
......@@ -48,7 +48,6 @@ TEST(Traits, has_member_type) {
struct T1 {}; // old-style IsRelocatable, below
struct T2 {}; // old-style IsRelocatable, below
struct T3 { typedef std::true_type IsRelocatable; };
struct T4 { typedef std::true_type IsTriviallyCopyable; };
struct T5 : T3 {};
struct F1 {};
......@@ -93,14 +92,7 @@ TEST(Traits, unset) {
EXPECT_TRUE(IsRelocatable<F4>::value);
}
TEST(Traits, bitprop) {
EXPECT_TRUE(IsTriviallyCopyable<T4>::value);
EXPECT_TRUE(IsRelocatable<T4>::value);
}
TEST(Traits, bitAndInit) {
EXPECT_TRUE (IsTriviallyCopyable<int>::value);
EXPECT_FALSE(IsTriviallyCopyable<vector<int>>::value);
EXPECT_TRUE (IsZeroInitializable<int>::value);
EXPECT_FALSE(IsZeroInitializable<vector<int>>::value);
}
......
......@@ -28,8 +28,8 @@
#include <boost/algorithm/string.hpp>
#include <folly/Conv.h>
#include <folly/Traits.h>
#include <folly/portability/GTest.h>
#include <folly/portability/TypeTraits.h>
using folly::small_vector;
using namespace folly::small_vector_policy;
......@@ -70,8 +70,9 @@ static_assert(sizeof(small_vector<int16_t,4,uint16_t>) == 10,
#endif
static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(std::unique_ptr<int>),
"std::unique_ptr<> is trivially copyable");
static_assert(
!folly::is_trivially_copyable<std::unique_ptr<int>>::value,
"std::unique_ptr<> is trivially copyable");
static_assert(
alignof(small_vector<std::aligned_storage<32, 32>::type, 4>) == 32,
......@@ -133,8 +134,9 @@ struct NontrivialType {
int32_t a;
};
static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(NontrivialType),
"NontrivialType is trivially copyable");
static_assert(
!folly::is_trivially_copyable<NontrivialType>::value,
"NontrivialType is trivially copyable");
int NontrivialType::ctored = 0;
......@@ -197,8 +199,9 @@ struct NoncopyableCounter {
};
int NoncopyableCounter::alive = 0;
static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(NoncopyableCounter),
"NoncopyableCounter is trivially copyable");
static_assert(
!folly::is_trivially_copyable<NoncopyableCounter>::value,
"NoncopyableCounter is trivially copyable");
// Check that throws don't break the basic guarantee for some cases.
// Uses the method for testing exception safety described at
......
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