From: Peter Griess Date: Thu, 10 Oct 2013 17:12:00 +0000 (-0700) Subject: Detect and use std::is_trivially_copyable where possible. X-Git-Tag: v0.22.0~821 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=baab37435b9b210d9f2068e8a85e7a23d6a518f5;hp=60f2c87ddcc00799c9b0a4d42c8d56a259298e54;p=folly.git Detect and use std::is_trivially_copyable where possible. Summary: - Sadly, boost::has_trivial_copy is not a suitable replacement for std::is_trivially_copyable on libc++. Fortunately, the latter is actually supported (and works), so use it directly. Test Plan: - fbconfig -r folly && fbmake runtests - ./configure && make check on Ubuntu/FC/Mac Reviewed By: delong.j@fb.com FB internal diff: D1008921 --- diff --git a/folly/Portability.h b/folly/Portability.h index d017400e..47d33be4 100644 --- a/folly/Portability.h +++ b/folly/Portability.h @@ -137,4 +137,21 @@ struct MaxAlign { char c; } __attribute__((aligned)); #include "folly/detail/Clock.h" #endif +// Unfortunately, boost::has_trivial_copy 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. +// +// 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 +#define FOLLY_IS_TRIVIALLY_COPYABLE(T) (std::is_trivially_copyable::value) +#else +#include +#define FOLLY_IS_TRIVIALLY_COPYABLE(T) (boost::has_trivial_copy::value) +#endif + #endif // FOLLY_PORTABILITY_H_ diff --git a/folly/configure.ac b/folly/configure.ac index 4a364763..2c0dc950 100644 --- a/folly/configure.ac +++ b/folly/configure.ac @@ -118,6 +118,15 @@ AC_COMPILE_IFELSE( ], [AC_DEFINE([USE_LIBCPP], [1], [Define to 1 if we're using libc++.])]) +AC_COMPILE_IFELSE( + [AC_LANG_SOURCE[ + #include + const bool val = std::is_trivially_copyable::value;] + ], + [AC_DEFINE([HAVE_STD__IS_TRIVIALLY_COPYABLE], [1], + [Define to 1 if we have a usable std::is_trivially_copyable + implementation.])]) + # Check for clock_gettime(2). This is not in an AC_CHECK_FUNCS() because we # want to link with librt if necessary. AC_SEARCH_LIBS([clock_gettime], [rt], diff --git a/folly/small_vector.h b/folly/small_vector.h index 373b8393..88c7bb59 100644 --- a/folly/small_vector.h +++ b/folly/small_vector.h @@ -116,7 +116,7 @@ namespace detail { */ template typename std::enable_if< - !boost::has_trivial_copy::value + !FOLLY_IS_TRIVIALLY_COPYABLE(T) >::type moveToUninitialized(T* first, T* last, T* out) { auto const count = last - first; @@ -138,11 +138,10 @@ namespace detail { } } - // Specialization for trivially copyable types. (TODO: change to - // std::is_trivially_copyable when that works.) + // Specialization for trivially copyable types. template typename std::enable_if< - boost::has_trivial_copy::value + FOLLY_IS_TRIVIALLY_COPYABLE(T) >::type moveToUninitialized(T* first, T* last, T* out) { std::memmove(out, first, (last - first) * sizeof *first); @@ -156,7 +155,7 @@ namespace detail { */ template typename std::enable_if< - !boost::has_trivial_copy::value + !FOLLY_IS_TRIVIALLY_COPYABLE(T) >::type moveObjectsRight(T* first, T* lastConstructed, T* realLast) { if (lastConstructed == realLast) { @@ -195,7 +194,7 @@ namespace detail { // change to std::is_trivially_copyable when that works.) template typename std::enable_if< - boost::has_trivial_copy::value + FOLLY_IS_TRIVIALLY_COPYABLE(T) >::type moveObjectsRight(T* first, T* lastConstructed, T* realLast) { std::move_backward(first, lastConstructed, realLast); diff --git a/folly/test/small_vector_test.cpp b/folly/test/small_vector_test.cpp index ad70e628..3df4fb97 100644 --- a/folly/test/small_vector_test.cpp +++ b/folly/test/small_vector_test.cpp @@ -84,8 +84,8 @@ struct NontrivialType { int32_t a; }; -static_assert(!boost::has_trivial_copy::value, - "NontrivialType isn't trivially copyable"); +static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(NontrivialType), + "NontrivialType is trivially copyable"); int NontrivialType::ctored = 0; @@ -148,6 +148,9 @@ struct NoncopyableCounter { }; int NoncopyableCounter::alive = 0; +static_assert(!FOLLY_IS_TRIVIALLY_COPYABLE(NoncopyableCounter), + "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 // http://www.boost.org/community/exception_safety.html, to force all @@ -472,9 +475,10 @@ TEST(small_vector, Iteration) { } TEST(small_vector, NonCopyableType) { - folly::small_vector,2> vec; + folly::small_vector vec; + for (int i = 0; i < 10; ++i) { - vec.emplace(vec.begin(), new std::string("asd")); + vec.emplace(vec.begin(), 13); } EXPECT_EQ(vec.size(), 10); auto vec2 = std::move(vec); diff --git a/folly/test/stl_tests/OFBVector.h b/folly/test/stl_tests/OFBVector.h index 88e18273..f5f11c5e 100644 --- a/folly/test/stl_tests/OFBVector.h +++ b/folly/test/stl_tests/OFBVector.h @@ -179,7 +179,7 @@ void uninitializedFillDefaultOrFree(T * b, size_t n) { template void uninitializedFillOrFree(T * b, size_t n, const T& value) { auto const e = b + n; - if (boost::has_trivial_copy::value) { + if (FOLLY_IS_TRIVIALLY_COPYABLE(T)) { auto i = b; auto const e1 = b + (n & ~size_t(7)); for (; i != e1; i += 8) { @@ -764,7 +764,7 @@ public: memmove(const_cast(position) + n, position, sizeof(T) * (e_ - position)); - if (boost::has_trivial_copy::value) { + if (FOLLY_IS_TRIVIALLY_COPYABLE(T)) { std::uninitialized_fill(const_cast(position), const_cast(position) + n, x);