X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FTraits.h;h=16aab8d6ef1e9011b195e44f35d04e69b00144cc;hb=49e4875c1e7d55df5913410539d299b7aa3c62bc;hp=566036bb77774b8d7a8f62b3f1ed95eb34ac406d;hpb=27494a20393fa45072e7d526d358835f3abe312a;p=folly.git diff --git a/folly/Traits.h b/folly/Traits.h index 566036bb..16aab8d6 100644 --- a/folly/Traits.h +++ b/folly/Traits.h @@ -1,5 +1,5 @@ /* - * Copyright 2012 Facebook, Inc. + * Copyright 2015 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,28 @@ #ifndef FOLLY_BASE_TRAITS_H_ #define FOLLY_BASE_TRAITS_H_ +#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 +#include #include -#include -#include namespace folly { @@ -41,7 +58,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 +74,64 @@ 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. */ -template struct IsRelocatable : boost::mpl::not_ > -{}; +/* + * 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)). + */ + +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 +} + +template struct IsTriviallyCopyable + : std::integral_constant::value || + // TODO: add alternate clause is_trivially_copyable, when available + traits_detail::has_true_IsTriviallyCopyable::value + > {}; + +template struct IsRelocatable + : std::integral_constant::value || + // 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 + > {}; + +template struct IsZeroInitializable + : std::integral_constant::value || + traits_detail::has_true_IsZeroInitializable::value + > {}; } // namespace folly @@ -73,11 +145,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 +161,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 +235,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 +252,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 +263,7 @@ template template class shared_ptr; -} +FOLLY_NAMESPACE_STD_END namespace boost { @@ -218,14 +294,102 @@ 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 so suppress them in order to not prevent +// all calling code from using it. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" + +template +bool less_than_impl(LHS const lhs) { + return + rhs > std::numeric_limits::max() ? true : + rhs <= std::numeric_limits::min() ? false : + lhs < rhs; +} + +#pragma GCC diagnostic pop + +template +bool greater_than_impl(LHS const lhs) { + return + rhs > std::numeric_limits::max() ? false : + rhs < std::numeric_limits::min() ? true : + lhs > rhs; +} + +} // 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); +} + +/** + * Like std::piecewise_construct, a tag type & instance used for in-place + * construction of non-movable contained types, e.g. by Synchronized. + */ +struct construct_in_place_t {}; +constexpr construct_in_place_t construct_in_place{}; + } // 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); @@ -233,4 +397,86 @@ FOLLY_ASSUME_FBVECTOR_COMPATIBLE_1(std::function); // Boost 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_