X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FTraits.h;h=ece58c30b60c0e0b9de212479cf4702796f5451e;hb=74b5413059e7be72dbc52ba815160bd6fe825835;hp=caeb852c3b6f3d85949398331b3a00be9a5bb9e2;hpb=50b33d29c25c9cb33ff61988a6fc16ec1a25e6d0;p=folly.git diff --git a/folly/Traits.h b/folly/Traits.h index caeb852c..ece58c30 100644 --- a/folly/Traits.h +++ b/folly/Traits.h @@ -1,5 +1,5 @@ /* - * Copyright 2015 Facebook, Inc. + * 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. @@ -16,8 +16,7 @@ // @author: Andrei Alexandrescu -#ifndef FOLLY_BASE_TRAITS_H_ -#define FOLLY_BASE_TRAITS_H_ +#pragma once #include #include @@ -38,9 +37,7 @@ #endif #include -#include #include -#include namespace folly { @@ -93,45 +90,148 @@ namespace folly { namespace traits_detail { -#define FOLLY_HAS_TRUE_XXX(name) \ - BOOST_MPL_HAS_XXX_TRAIT_DEF(name); \ - template struct name ## _is_true \ - : std::is_same {}; \ - template struct has_true_ ## name \ - : std::conditional< \ - has_ ## name ::value, \ - name ## _is_true, \ - std::false_type \ - >:: type {}; +#define FOLLY_HAS_TRUE_XXX(name) \ + BOOST_MPL_HAS_XXX_TRAIT_DEF(name) \ + template \ + struct name##_is_true : std::is_same {}; \ + template \ + struct has_true_##name : std::conditional< \ + has_##name::value, \ + name##_is_true, \ + std::false_type>::type {}; 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 +struct is_trivially_copyable + : std::integral_constant {}; +#elif defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 +template +struct is_trivially_copyable : std::is_trivial {}; +#else +template +using is_trivially_copyable = std::is_trivially_copyable; +#endif } +struct Ignore { + template + /* implicit */ Ignore(const T&) {} + template + const Ignore& operator=(T const&) const { return *this; } +}; + +template +using Ignored = Ignore; + +namespace traits_detail_IsEqualityComparable { +Ignore operator==(Ignore, Ignore); + +template +struct IsEqualityComparable + : std::is_convertible< + decltype(std::declval() == std::declval()), + bool + > {}; +} + +/* using override */ using traits_detail_IsEqualityComparable:: + IsEqualityComparable; + +namespace traits_detail_IsLessThanComparable { +Ignore operator<(Ignore, Ignore); + +template +struct IsLessThanComparable + : std::is_convertible< + decltype(std::declval() < std::declval()), + bool + > {}; +} + +/* using override */ using traits_detail_IsLessThanComparable:: + IsLessThanComparable; + +namespace traits_detail_IsNothrowSwappable { +#if defined(_MSC_VER) || defined(__cpp_lib_is_swappable) +// MSVC already implements the C++17 P0185R1 proposal which +// adds std::is_nothrow_swappable, so use it instead. +template +using IsNothrowSwappable = std::is_nothrow_swappable; +#else +/* using override */ using std::swap; + +template +struct IsNothrowSwappable + : std::integral_constant::value && + noexcept(swap(std::declval(), std::declval())) + > {}; +#endif +} + +/* using override */ using traits_detail_IsNothrowSwappable::IsNothrowSwappable; + template struct IsTriviallyCopyable - : std::integral_constant::value || - // TODO: add alternate clause is_trivially_copyable, when available - traits_detail::has_true_IsTriviallyCopyable::value - > {}; + : std::conditional< + traits_detail::has_IsTriviallyCopyable::value, + traits_detail::has_true_IsTriviallyCopyable, + traits_detail::is_trivially_copyable + >::type {}; template struct IsRelocatable - : std::integral_constant::value || + : std::conditional< + traits_detail::has_IsRelocatable::value, + traits_detail::has_true_IsRelocatable, // TODO add this line (and some tests for it) when we upgrade to gcc 4.7 //std::is_trivially_move_constructible::value || - IsTriviallyCopyable::value || - traits_detail::has_true_IsRelocatable::value - > {}; + IsTriviallyCopyable + >::type {}; template struct IsZeroInitializable - : std::integral_constant::value || - traits_detail::has_true_IsZeroInitializable::value - > {}; + : std::conditional< + traits_detail::has_IsZeroInitializable::value, + traits_detail::has_true_IsZeroInitializable, + std::integral_constant::value> + >::type {}; + +template +struct Conjunction : std::true_type {}; +template +struct Conjunction : T {}; +template +struct Conjunction + : std::conditional, T>::type {}; + +template +struct Disjunction : std::false_type {}; +template +struct Disjunction : T {}; +template +struct Disjunction + : std::conditional>::type {}; + +template +struct Negation : std::integral_constant {}; + +template +struct Bools { + using valid_type = bool; + static constexpr std::size_t size() { + return sizeof...(Bs); + } +}; + +// Lighter-weight than Conjunction, but evaluates all sub-conditions eagerly. +template +using StrictConjunction = + std::is_same, Bools>; } // namespace folly @@ -271,8 +371,9 @@ template class shared_ptr; template struct has_nothrow_constructor< std::pair > - : ::boost::mpl::and_< has_nothrow_constructor, - has_nothrow_constructor > {}; + : std::integral_constant::value && + has_nothrow_constructor::value> {}; } // namespace boost @@ -280,8 +381,10 @@ namespace folly { // STL commonly-used types template -struct IsRelocatable< std::pair > - : ::boost::mpl::and_< IsRelocatable, IsRelocatable > {}; +struct IsRelocatable< std::pair > + : std::integral_constant::value && + IsRelocatable::value> {}; // Is T one of T1, T2, ..., Tn? template @@ -318,10 +421,13 @@ struct is_negative_impl { // folly::to integral specializations can end up generating code // inside what are really static ifs (not executed because of the templated -// types) that violate -Wsign-compare so suppress them in order to not prevent -// all calling code from using it. +// types) that violate -Wsign-compare and/or -Wbool-compare so suppress them +// in order to not prevent all calling code from using it. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" +#if __GNUC_PREREQ(5, 0) +#pragma GCC diagnostic ignored "-Wbool-compare" +#endif template bool less_than_impl(LHS const lhs) { @@ -331,8 +437,6 @@ bool less_than_impl(LHS const lhs) { lhs < rhs; } -#pragma GCC diagnostic pop - template bool greater_than_impl(LHS const lhs) { return @@ -341,6 +445,8 @@ bool greater_than_impl(LHS const lhs) { lhs > rhs; } +#pragma GCC diagnostic pop + } // namespace detail { // same as `x < 0` @@ -377,18 +483,114 @@ bool greater_than(LHS const lhs) { >(lhs); } +namespace traits_detail { +struct InPlaceTag {}; +template +struct InPlaceTypeTag {}; +template +struct InPlaceIndexTag {}; +} + +/** + * Like std::piecewise_construct, a tag type & instance used for in-place + * construction of non-movable contained types, e.g. by Synchronized. + * Follows the naming and design of std::in_place suggested in + * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0032r2.pdf + */ +using in_place_t = traits_detail::InPlaceTag (&)(traits_detail::InPlaceTag); + +template +using in_place_type_t = + traits_detail::InPlaceTypeTag (&)(traits_detail::InPlaceTypeTag); + +template +using in_place_index_t = + traits_detail::InPlaceIndexTag (&)(traits_detail::InPlaceIndexTag); + +inline traits_detail::InPlaceTag in_place(traits_detail::InPlaceTag = {}) { + return {}; +} + +template +inline traits_detail::InPlaceTypeTag in_place( + traits_detail::InPlaceTypeTag = {}) { + return {}; +} + +template +inline traits_detail::InPlaceIndexTag in_place( + traits_detail::InPlaceIndexTag = {}) { + return {}; +} + +// For backwards compatibility: +using construct_in_place_t = in_place_t; + +inline traits_detail::InPlaceTag construct_in_place( + traits_detail::InPlaceTag = {}) { + return {}; +} + +/** + * Initializer lists are a powerful compile time syntax introduced in C++11 + * but due to their often conflicting syntax they are not used by APIs for + * construction. + * + * Further standard conforming compilers *strongly* favor an + * std::initalizer_list overload for construction if one exists. The + * following is a simple tag used to disambiguate construction with + * initializer lists and regular uniform initialization. + * + * For example consider the following case + * + * class Something { + * public: + * explicit Something(int); + * Something(std::intiializer_list); + * + * operator int(); + * }; + * + * ... + * Something something{1}; // SURPRISE!! + * + * The last call to instantiate the Something object will go to the + * initializer_list overload. Which may be surprising to users. + * + * If however this tag was used to disambiguate such construction it would be + * easy for users to see which construction overload their code was referring + * to. For example + * + * class Something { + * public: + * explicit Something(int); + * Something(folly::initlist_construct_t, std::initializer_list); + * + * operator int(); + * }; + * + * ... + * Something something_one{1}; // not the initializer_list overload + * Something something_two{folly::initlist_construct, {1}}; // correct + */ +struct initlist_construct_t {}; +constexpr initlist_construct_t initlist_construct{}; + } // namespace folly -FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(std::basic_string); -FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::vector); -FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::list); -FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::deque); -FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::unique_ptr); -FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::shared_ptr); -FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::function); +// gcc-5.0 changed string's implementation in libgcc to be non-relocatable +#if __GNUC__ < 5 +FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(std::basic_string) +#endif +FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::vector) +FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::list) +FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::deque) +FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::unique_ptr) +FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::shared_ptr) +FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::function) // Boost -FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(boost::shared_ptr); +FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(boost::shared_ptr) #define FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(classname, type_name) \ template \ @@ -472,4 +674,44 @@ FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(boost::shared_ptr); FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL( \ classname, func_name, /* nolint */ volatile const) -#endif //FOLLY_BASE_TRAITS_H_ +/* Some combinations of compilers and C++ libraries make __int128 and + * unsigned __int128 available but do not correctly define their standard type + * traits. + * + * If FOLLY_SUPPLY_MISSING_INT128_TRAITS is defined, we define these traits + * here. + * + * @author: Phil Willoughby + */ +#if FOLLY_SUPPLY_MISSING_INT128_TRAITS +FOLLY_NAMESPACE_STD_BEGIN +template <> +struct is_arithmetic<__int128> : ::std::true_type {}; +template <> +struct is_arithmetic : ::std::true_type {}; +template <> +struct is_integral<__int128> : ::std::true_type {}; +template <> +struct is_integral : ::std::true_type {}; +template <> +struct make_unsigned<__int128> { + typedef unsigned __int128 type; +}; +template <> +struct make_signed<__int128> { + typedef __int128 type; +}; +template <> +struct make_unsigned { + typedef unsigned __int128 type; +}; +template <> +struct make_signed { + typedef __int128 type; +}; +template <> +struct is_signed<__int128> : ::std::true_type {}; +template <> +struct is_unsigned : ::std::true_type {}; +FOLLY_NAMESPACE_STD_END +#endif // FOLLY_SUPPLY_MISSING_INT128_TRAITS