X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FTraits.h;h=ece58c30b60c0e0b9de212479cf4702796f5451e;hb=74b5413059e7be72dbc52ba815160bd6fe825835;hp=f5fe5816cf0e2f456aa665788a2795ec289345a1;hpb=f5cac66e7afed78ae6ad79d1648a779ec31542e7;p=folly.git diff --git a/folly/Traits.h b/folly/Traits.h index f5fe5816..ece58c30 100644 --- a/folly/Traits.h +++ b/folly/Traits.h @@ -1,5 +1,5 @@ /* - * Copyright 2013 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,21 +16,28 @@ // @author: Andrei Alexandrescu -#ifndef FOLLY_BASE_TRAITS_H_ -#define FOLLY_BASE_TRAITS_H_ +#pragma once #include #include #include - -#include "folly/Portability.h" - +#include + +#include + +// libc++ doesn't provide this header, nor does msvc +#ifdef FOLLY_HAVE_BITS_CXXCONFIG_H +// This file appears in two locations: inside fbcode and in the +// libstdc++ source code (when embedding fbstring as std::string). +// To aid in this schizophrenic use, two macros are defined in +// c++config.h: +// _LIBSTDCXX_FBSTRING - Set inside libstdc++. This is useful to +// gate use inside fbcode v. libstdc++ #include +#endif #include -#include #include -#include namespace folly { @@ -83,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 @@ -230,8 +340,10 @@ FOLLY_NAMESPACE_STD_BEGIN template struct pair; #ifndef _GLIBCXX_USE_FB +FOLLY_GLIBCXX_NAMESPACE_CXX11_BEGIN template class basic_string; +FOLLY_GLIBCXX_NAMESPACE_CXX11_END #else template class basic_string; @@ -240,8 +352,10 @@ template class vector; template class deque; +FOLLY_GLIBCXX_NAMESPACE_CXX11_BEGIN template class list; +FOLLY_GLIBCXX_NAMESPACE_CXX11_END template class set; template @@ -257,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 @@ -266,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 @@ -280,34 +397,6 @@ struct IsOneOf { enum { value = std::is_same::value || IsOneOf::value }; }; -/** - * A traits class to check for incomplete types. - * - * Example: - * - * struct FullyDeclared {}; // complete type - * struct ForwardDeclared; // incomplete type - * - * is_complete::value // evaluates to true - * is_complete::value // evaluates to true - * is_complete::value // evaluates to false - * - * struct ForwardDeclared {}; // declared, at last - * - * is_complete::value // now it evaluates to true - * - * @author: Marcelo Juchem - */ -template -class is_complete { - template struct sfinae {}; - template - constexpr static bool test(sfinae*) { return true; } - template constexpr static bool test(...) { return false; } -public: - constexpr static bool value = test(nullptr); -}; - /* * Complementary type traits for integral comparisons. * @@ -327,70 +416,36 @@ struct is_negative_impl { template struct is_negative_impl { - constexpr static bool check(T x) { return false; } + constexpr static bool check(T) { return false; } }; -template -bool less_than_impl( - typename std::enable_if< - (rhs <= std::numeric_limits::max() - && rhs > std::numeric_limits::min()), - LHS - >::type const lhs -) { - return lhs < rhs; -} - -template -bool less_than_impl( - typename std::enable_if< - (rhs > std::numeric_limits::max()), - LHS - >::type const -) { - return true; -} - -template -bool less_than_impl( - typename std::enable_if< - (rhs <= std::numeric_limits::min()), - LHS - >::type const -) { - return false; -} +// 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 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 greater_than_impl( - typename std::enable_if< - (rhs <= std::numeric_limits::max() - && rhs >= std::numeric_limits::min()), - LHS - >::type const lhs -) { - return lhs > rhs; +bool less_than_impl(LHS const lhs) { + return + rhs > std::numeric_limits::max() ? true : + rhs <= std::numeric_limits::min() ? false : + lhs < rhs; } template -bool greater_than_impl( - typename std::enable_if< - (rhs > std::numeric_limits::max()), - LHS - >::type const -) { - return false; +bool greater_than_impl(LHS const lhs) { + return + rhs > std::numeric_limits::max() ? false : + rhs < std::numeric_limits::min() ? true : + lhs > rhs; } -template -bool greater_than_impl( - typename std::enable_if< - (rhs < std::numeric_limits::min()), - LHS - >::type const -) { - return true; -} +#pragma GCC diagnostic pop } // namespace detail { @@ -428,18 +483,124 @@ 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 \ + struct classname { \ + template \ + constexpr static bool test(typename C::type_name*) { return true; } \ + template \ + constexpr static bool test(...) { return false; } \ + constexpr static bool value = test(nullptr); \ + } #define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, cv_qual) \ template \ @@ -508,7 +669,49 @@ FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(boost::shared_ptr); template class classname; \ FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, ); \ FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, const); \ - FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, volatile); \ - FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL(classname, func_name, volatile const) + FOLLY_CREATE_HAS_MEMBER_FN_TRAITS_IMPL( \ + classname, func_name, /* nolint */ volatile); \ + 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