X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FUtility.h;h=1969a9644b20e63c9a0e92e5878c6b3df62de375;hp=f8f4f9bb07d5e5a94156f04f46f43637ed4b7098;hb=766b616c0d104cfb37a2ad13284d320f2a4db67a;hpb=2843ff12364e1159d99f2b96bcc4a5c428dad1fa diff --git a/folly/Utility.h b/folly/Utility.h index f8f4f9bb..1969a964 100644 --- a/folly/Utility.h +++ b/folly/Utility.h @@ -20,6 +20,8 @@ #include #include +#include + namespace folly { /** @@ -98,14 +100,59 @@ void as_const(T const&&) = delete; #endif +namespace utility_detail { +template +struct make_seq_cat; +template < + template class S, + typename T, + T... Ta, + T... Tb, + T... Tc> +struct make_seq_cat, S, S> { + using type = + S; +}; + +// Not parameterizing by `template class, typename` because +// clang precisely v4.0 fails to compile that. Note that clang v3.9 and v5.0 +// handle that code correctly. +// +// For this to work, `S0` is required to be `Sequence` and `S1` is required +// to be `Sequence`. + +template +struct make_seq { + template + using apply = typename make_seq_cat< + typename make_seq::template apply, + typename make_seq::template apply, + typename make_seq::template apply>::type; +}; +template <> +struct make_seq<1> { + template + using apply = S1; +}; +template <> +struct make_seq<0> { + template + using apply = S0; +}; +} // namespace utility_detail + #if __cpp_lib_integer_sequence || _MSC_VER /* using override */ using std::integer_sequence; /* using override */ using std::index_sequence; -/* using override */ using std::make_index_sequence; #else +// TODO: Remove after upgrading to C++14 baseline + template struct integer_sequence { using value_type = T; @@ -116,19 +163,158 @@ struct integer_sequence { }; template -using index_sequence = folly::integer_sequence; +using index_sequence = integer_sequence; -namespace detail { -template -struct make_index_sequence - : detail::make_index_sequence {}; +#endif -template -struct make_index_sequence<0, Ints...> : folly::index_sequence {}; -} +#if FOLLY_HAS_BUILTIN(__make_integer_seq) || _MSC_FULL_VER >= 190023918 -template -using make_index_sequence = detail::make_index_sequence; +template +using make_integer_sequence = __make_integer_seq; + +#else + +template +using make_integer_sequence = typename utility_detail::make_seq< + Size>::template apply, integer_sequence>; #endif + +template +using make_index_sequence = make_integer_sequence; + +/** + * Backports from C++17 of: + * std::in_place_t + * std::in_place_type_t + * std::in_place_index_t + * std::in_place + * std::in_place_type + * std::in_place_index + */ + +struct in_place_tag {}; +template +struct in_place_type_tag {}; +template +struct in_place_index_tag {}; + +using in_place_t = in_place_tag (&)(in_place_tag); +template +using in_place_type_t = in_place_type_tag (&)(in_place_type_tag); +template +using in_place_index_t = in_place_index_tag (&)(in_place_index_tag); + +inline in_place_tag in_place(in_place_tag = {}) { + return {}; } +template +inline in_place_type_tag in_place_type(in_place_type_tag = {}) { + return {}; +} +template +inline in_place_index_tag in_place_index(in_place_index_tag = {}) { + 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{}; + +/** + * A simple function object that passes its argument through unchanged. + * + * Example: + * + * int i = 42; + * int &j = Identity()(i); + * assert(&i == &j); + * + * Warning: passing a prvalue through Identity turns it into an xvalue, + * which can effect whether lifetime extension occurs or not. For instance: + * + * auto&& x = std::make_unique(42); + * cout << *x ; // OK, x refers to a valid unique_ptr. + * + * auto&& y = Identity()(std::make_unique(42)); + * cout << *y ; // ERROR: y did not lifetime-extend the unique_ptr. It + * // is no longer valid + */ +struct Identity { + using is_transparent = void; + template + constexpr T&& operator()(T&& x) const noexcept { + return static_cast(x); + } +}; + +namespace moveonly_ { // Protection from unintended ADL. + +/** + * Disallow copy but not move in derived types. This is essentially + * boost::noncopyable (the implementation is almost identical) but it + * doesn't delete move constructor and move assignment. + */ +class MoveOnly { + protected: + constexpr MoveOnly() = default; + ~MoveOnly() = default; + + MoveOnly(MoveOnly&&) = default; + MoveOnly& operator=(MoveOnly&&) = default; + MoveOnly(const MoveOnly&) = delete; + MoveOnly& operator=(const MoveOnly&) = delete; +}; + +} // namespace moveonly_ + +using MoveOnly = moveonly_::MoveOnly; + +/** + * A pithy alias for std::integral_constant. + */ +template +using Bool = std::integral_constant; + +} // namespace folly