/* * Copyright 2012-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. */ #include #include #include #include #include #include #include using namespace folly; using namespace std; namespace { FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(has_member_type_x, x); } // namespace TEST(Traits, has_member_type) { struct membership_no {}; struct membership_yes { using x = void; }; EXPECT_TRUE((is_same>::value)); EXPECT_TRUE((is_same>::value)); } // Note: FOLLY_CREATE_HAS_MEMBER_FN_TRAITS tests are in // folly/test/HasMemberFnTraitsTest.cpp. struct T1 {}; // old-style IsRelocatable, below struct T2 {}; // old-style IsRelocatable, below struct T3 { typedef std::true_type IsRelocatable; }; struct T5 : T3 {}; struct F1 {}; struct F2 { typedef int IsRelocatable; }; struct F3 : T3 { typedef std::false_type IsRelocatable; }; struct F4 : T1 {}; namespace folly { template <> struct IsRelocatable : std::true_type {}; template <> FOLLY_ASSUME_RELOCATABLE(T2); } // namespace folly TEST(Traits, scalars) { EXPECT_TRUE(IsRelocatable::value); EXPECT_TRUE(IsRelocatable::value); EXPECT_TRUE(IsRelocatable::value); EXPECT_TRUE(IsRelocatable::value); } TEST(Traits, containers) { EXPECT_TRUE(IsRelocatable>::value); EXPECT_TRUE((IsRelocatable>::value)); EXPECT_TRUE((IsRelocatable>::value)); } TEST(Traits, original) { EXPECT_TRUE(IsRelocatable::value); EXPECT_TRUE(IsRelocatable::value); } TEST(Traits, typedefd) { EXPECT_TRUE(IsRelocatable::value); EXPECT_TRUE(IsRelocatable::value); EXPECT_FALSE(IsRelocatable::value); EXPECT_FALSE(IsRelocatable::value); } TEST(Traits, unset) { EXPECT_TRUE(IsRelocatable::value); EXPECT_TRUE(IsRelocatable::value); } TEST(Traits, bitAndInit) { EXPECT_TRUE(IsZeroInitializable::value); EXPECT_FALSE(IsZeroInitializable>::value); } TEST(Trait, logicOperators) { static_assert(Conjunction::value, ""); static_assert(!Conjunction::value, ""); static_assert(is_same::type, true_type>::value, ""); static_assert(is_same::type, false_type>::value, ""); static_assert(Conjunction::value, ""); static_assert(!Conjunction::value, ""); static_assert(Disjunction::value, ""); static_assert(!Disjunction::value, ""); static_assert(is_same::type, true_type>::value, ""); static_assert(is_same::type, false_type>::value, ""); static_assert(Disjunction::value, ""); static_assert(Disjunction::value, ""); static_assert(!Negation::value, ""); static_assert(Negation::value, ""); } TEST(Traits, is_negative) { EXPECT_TRUE(folly::is_negative(-1)); EXPECT_FALSE(folly::is_negative(0)); EXPECT_FALSE(folly::is_negative(1)); EXPECT_FALSE(folly::is_negative(0u)); EXPECT_FALSE(folly::is_negative(1u)); EXPECT_TRUE(folly::is_non_positive(-1)); EXPECT_TRUE(folly::is_non_positive(0)); EXPECT_FALSE(folly::is_non_positive(1)); EXPECT_TRUE(folly::is_non_positive(0u)); EXPECT_FALSE(folly::is_non_positive(1u)); } TEST(Traits, relational) { // We test, especially, the edge cases to make sure we don't // trip -Wtautological-comparisons EXPECT_FALSE((folly::less_than(0u))); EXPECT_FALSE((folly::less_than(254u))); EXPECT_FALSE((folly::less_than(255u))); EXPECT_TRUE((folly::less_than(254u))); EXPECT_FALSE((folly::greater_than(0u))); EXPECT_TRUE((folly::greater_than(254u))); EXPECT_FALSE((folly::greater_than(255u))); EXPECT_FALSE((folly::greater_than(254u))); } #if FOLLY_HAVE_INT128_T TEST(Traits, int128) { EXPECT_TRUE( (::std::is_same<::std::make_unsigned<__int128_t>::type, __uint128_t>:: value)); EXPECT_TRUE(( ::std::is_same<::std::make_signed<__int128_t>::type, __int128_t>::value)); EXPECT_TRUE( (::std::is_same<::std::make_unsigned<__uint128_t>::type, __uint128_t>:: value)); EXPECT_TRUE( (::std::is_same<::std::make_signed<__uint128_t>::type, __int128_t>:: value)); EXPECT_TRUE((::std::is_arithmetic<__int128_t>::value)); EXPECT_TRUE((::std::is_arithmetic<__uint128_t>::value)); EXPECT_TRUE((::std::is_integral<__int128_t>::value)); EXPECT_TRUE((::std::is_integral<__uint128_t>::value)); EXPECT_FALSE((::std::is_unsigned<__int128_t>::value)); EXPECT_TRUE((::std::is_signed<__int128_t>::value)); EXPECT_TRUE((::std::is_unsigned<__uint128_t>::value)); EXPECT_FALSE((::std::is_signed<__uint128_t>::value)); EXPECT_TRUE((::std::is_fundamental<__int128_t>::value)); EXPECT_TRUE((::std::is_fundamental<__uint128_t>::value)); EXPECT_TRUE((::std::is_scalar<__int128_t>::value)); EXPECT_TRUE((::std::is_scalar<__uint128_t>::value)); } #endif // FOLLY_HAVE_INT128_T template void testIsRelocatable(Args&&... args) { if (!IsRelocatable::value) { return; } // We use placement new on zeroed memory to avoid garbage subsections char vsrc[sizeof(T)] = {0}; char vdst[sizeof(T)] = {0}; char vcpy[sizeof(T)]; T* src = new (vsrc) T(std::forward(args)...); SCOPE_EXIT { src->~T(); }; std::memcpy(vcpy, vsrc, sizeof(T)); T deep(*src); T* dst = new (vdst) T(std::move(*src)); SCOPE_EXIT { dst->~T(); }; EXPECT_EQ(deep, *dst); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-aliasing" EXPECT_EQ(deep, *reinterpret_cast(vcpy)); #pragma GCC diagnostic pop // This test could technically fail; however, this is what relocation // almost always means, so it's a good test to have EXPECT_EQ(std::memcmp(vcpy, vdst, sizeof(T)), 0); } TEST(Traits, actuallyRelocatable) { // Ensure that we test stack and heap allocation for strings with in-situ // capacity testIsRelocatable("1"); testIsRelocatable(sizeof(std::string) + 1, 'x'); testIsRelocatable>(5, 'g'); } namespace { // has_value_type::value is true if T has a nested type `value_type` template struct has_value_type : std::false_type {}; template struct has_value_type> : std::true_type {}; struct some_tag {}; template struct container { template container( folly::type_t()...))>, Args&&...) {} }; } // namespace TEST(Traits, void_t) { EXPECT_TRUE((::std::is_same, void>::value)); EXPECT_TRUE((::std::is_same, void>::value)); EXPECT_TRUE((::std::is_same, void>::value)); EXPECT_TRUE( (::std::is_same, void>::value)); EXPECT_TRUE((::has_value_type::value)); EXPECT_FALSE((::has_value_type::value)); } TEST(Traits, type_t) { EXPECT_TRUE((::std::is_same, float>::value)); EXPECT_TRUE((::std::is_same, float>::value)); EXPECT_TRUE((::std::is_same, float>::value)); EXPECT_TRUE( (::std::is_same, float>:: value)); EXPECT_TRUE(( ::std::is_constructible<::container, some_tag, std::string>:: value)); EXPECT_FALSE( (::std::is_constructible<::container, some_tag, float>:: value)); } TEST(Traits, remove_cvref) { using folly::remove_cvref; using folly::remove_cvref_t; // test all possible c-ref qualifiers without volatile EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE((std::is_same::type, int>::value)); EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE((std::is_same::type, int>::value)); EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE((std::is_same::type, int>::value)); EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE((std::is_same::type, int>::value)); EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE((std::is_same::type, int>::value)); EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE((std::is_same::type, int>::value)); // test all possible c-ref qualifiers with volatile EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE((std::is_same::type, int>::value)); EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE((std::is_same::type, int>::value)); EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE((std::is_same::type, int>::value)); EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE( (std::is_same::type, int>::value)); EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE( (std::is_same::type, int>::value)); EXPECT_TRUE((std::is_same, int>::value)); EXPECT_TRUE( (std::is_same::type, int>::value)); } TEST(Traits, like) { EXPECT_TRUE((std::is_same, char>::value)); EXPECT_TRUE((std::is_same, char const>::value)); EXPECT_TRUE((std::is_same, char volatile>::value)); EXPECT_TRUE( (std::is_same, char const volatile>:: value)); EXPECT_TRUE((std::is_same, char&>::value)); EXPECT_TRUE((std::is_same, char const&>::value)); EXPECT_TRUE( (std::is_same, char volatile&>::value)); EXPECT_TRUE( (std::is_same, char const volatile&>:: value)); EXPECT_TRUE((std::is_same, char&&>::value)); EXPECT_TRUE((std::is_same, char const&&>::value)); EXPECT_TRUE( (std::is_same, char volatile&&>::value)); EXPECT_TRUE( (std::is_same, char const volatile&&>:: value)); }