X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FTraits.h;h=ece58c30b60c0e0b9de212479cf4702796f5451e;hb=74b5413059e7be72dbc52ba815160bd6fe825835;hp=566036bb77774b8d7a8f62b3f1ed95eb34ac406d;hpb=27494a20393fa45072e7d526d358835f3abe312a;p=folly.git diff --git a/folly/Traits.h b/folly/Traits.h index 566036bb..ece58c30 100644 --- a/folly/Traits.h +++ b/folly/Traits.h @@ -1,5 +1,5 @@ /* - * Copyright 2012 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,14 +16,28 @@ // @author: Andrei Alexandrescu -#ifndef FOLLY_BASE_TRAITS_H_ -#define FOLLY_BASE_TRAITS_H_ +#pragma once -#include -#include -#include #include +#include +#include +#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 namespace folly { @@ -41,7 +55,7 @@ namespace folly { * } * * void move2(T * from, T * to) { - * memcpy(from, to, sizeof(T)); + * memcpy(to, from, sizeof(T)); * } * * Most C++ types are relocatable; the ones that aren't would include @@ -57,9 +71,167 @@ namespace folly { * types. You may want to add your own specializations. Do so in * namespace folly and make sure you keep the specialization of * IsRelocatable in the same header as SomeStruct. + * + * You may also declare a type to be relocatable by including + * `typedef std::true_type IsRelocatable;` + * in the class header. + * + * 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)). */ -template struct IsRelocatable : boost::mpl::not_ > -{}; + +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 {}; + +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::conditional< + traits_detail::has_IsTriviallyCopyable::value, + traits_detail::has_true_IsTriviallyCopyable, + traits_detail::is_trivially_copyable + >::type {}; + +template struct IsRelocatable + : 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 + >::type {}; + +template struct IsZeroInitializable + : 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 @@ -73,11 +245,11 @@ template struct IsRelocatable : boost::mpl::not_ > * When using it with a template type, use it like this: * * // Make sure you're at namespace ::folly scope - * template + * template * FOLLY_ASSUME_RELOCATABLE(MyType) */ #define FOLLY_ASSUME_RELOCATABLE(...) \ - struct IsRelocatable< __VA_ARGS__ > : ::boost::true_type {}; + struct IsRelocatable< __VA_ARGS__ > : std::true_type {}; /** * Use this macro ONLY inside namespace boost. When using it with a @@ -89,7 +261,7 @@ template struct IsRelocatable : boost::mpl::not_ > * When using it with a template type, use it like this: * * // Make sure you're at namespace ::boost scope - * template + * template * FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(MyType) */ #define FOLLY_ASSUME_HAS_NOTHROW_CONSTRUCTOR(...) \ @@ -163,13 +335,15 @@ template struct IsRelocatable : boost::mpl::not_ > * although that is not guaranteed by the standard. */ -namespace std { +FOLLY_NAMESPACE_STD_BEGIN template - class pair; + 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; @@ -178,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 @@ -187,7 +363,7 @@ template template class shared_ptr; -} +FOLLY_NAMESPACE_STD_END namespace boost { @@ -195,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 @@ -204,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 @@ -218,19 +397,321 @@ struct IsOneOf { enum { value = std::is_same::value || IsOneOf::value }; }; +/* + * Complementary type traits for integral comparisons. + * + * For instance, `if(x < 0)` yields an error in clang for unsigned types + * when -Werror is used due to -Wtautological-compare + * + * + * @author: Marcelo Juchem + */ + +namespace detail { + +template +struct is_negative_impl { + constexpr static bool check(T x) { return x < 0; } +}; + +template +struct is_negative_impl { + constexpr static bool check(T) { 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 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(LHS const lhs) { + return + rhs > std::numeric_limits::max() ? false : + rhs < std::numeric_limits::min() ? true : + lhs > rhs; +} + +#pragma GCC diagnostic pop + +} // namespace detail { + +// same as `x < 0` +template +constexpr bool is_negative(T x) { + return folly::detail::is_negative_impl::value>::check(x); +} + +// same as `x <= 0` +template +constexpr bool is_non_positive(T x) { return !x || folly::is_negative(x); } + +// same as `x > 0` +template +constexpr bool is_positive(T x) { return !is_non_positive(x); } + +// same as `x >= 0` +template +constexpr bool is_non_negative(T x) { + return !x || is_positive(x); +} + +template +bool less_than(LHS const lhs) { + return detail::less_than_impl< + RHS, rhs, typename std::remove_reference::type + >(lhs); +} + +template +bool greater_than(LHS const lhs) { + return detail::greater_than_impl< + RHS, rhs, typename std::remove_reference::type + >(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_4(std::map); -FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(std::set); -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 \ + class classname { \ + template < \ + typename UTheClass_, RTheReturn_ (UTheClass_::*)(TTheArgs_...) cv_qual \ + > struct sfinae {}; \ + template \ + constexpr static bool test(sfinae*) \ + { return true; } \ + template \ + constexpr static bool test(...) { return false; } \ + public: \ + constexpr static bool value = test(nullptr); \ + } + +/* + * The FOLLY_CREATE_HAS_MEMBER_FN_TRAITS is used to create traits + * classes that check for the existence of a member function with + * a given name and signature. It currently does not support + * checking for inherited members. + * + * Such classes receive two template parameters: the class to be checked + * and the signature of the member function. A static boolean field + * named `value` (which is also constexpr) tells whether such member + * function exists. + * + * Each traits class created is bound only to the member name, not to + * its signature nor to the type of the class containing it. + * + * Say you need to know if a given class has a member function named + * `test` with the following signature: + * + * int test() const; + * + * You'd need this macro to create a traits class to check for a member + * named `test`, and then use this traits class to check for the signature: + * + * namespace { + * + * FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_test_traits, test); + * + * } // unnamed-namespace + * + * void some_func() { + * cout << "Does class Foo have a member int test() const? " + * << boolalpha << has_test_traits::value; + * } + * + * You can use the same traits class to test for a completely different + * signature, on a completely different class, as long as the member name + * is the same: + * + * void some_func() { + * cout << "Does class Foo have a member int test()? " + * << boolalpha << has_test_traits::value; + * cout << "Does class Foo have a member int test() const? " + * << boolalpha << has_test_traits::value; + * cout << "Does class Bar have a member double test(const string&, long)? " + * << boolalpha << has_test_traits::value; + * } + * + * @author: Marcelo Juchem + */ +#define FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(classname, func_name) \ + 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, /* 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