X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FUtility.h;h=1969a9644b20e63c9a0e92e5878c6b3df62de375;hp=1d3786181458768f1f8efcb04030b0a6ac963dc8;hb=90ce64f987677e11200729afa6bb9c4b64caf01e;hpb=efcacd1c99bbea5411507e39ce74051a279be5e7 diff --git a/folly/Utility.h b/folly/Utility.h index 1d378618..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,22 +163,105 @@ 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_integer_sequence = __make_integer_seq; + +#else -template -using make_index_sequence = detail::make_index_sequence; +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. * @@ -181,4 +311,10 @@ class MoveOnly { using MoveOnly = moveonly_::MoveOnly; +/** + * A pithy alias for std::integral_constant. + */ +template +using Bool = std::integral_constant; + } // namespace folly