logging: add more documentation
[folly.git] / folly / Utility.h
index 4d6725d7070ec70e9684d19db915100c6fc5e9cc..1969a9644b20e63c9a0e92e5878c6b3df62de375 100644 (file)
@@ -20,6 +20,8 @@
 #include <type_traits>
 #include <utility>
 
+#include <folly/CPortability.h>
+
 namespace folly {
 
 /**
@@ -98,14 +100,59 @@ void as_const(T const&&) = delete;
 
 #endif
 
+namespace utility_detail {
+template <typename...>
+struct make_seq_cat;
+template <
+    template <typename T, T...> class S,
+    typename T,
+    T... Ta,
+    T... Tb,
+    T... Tc>
+struct make_seq_cat<S<T, Ta...>, S<T, Tb...>, S<T, Tc...>> {
+  using type =
+      S<T,
+        Ta...,
+        (sizeof...(Ta) + Tb)...,
+        (sizeof...(Ta) + sizeof...(Tb) + Tc)...>;
+};
+
+// Not parameterizing by `template <typename T, T...> 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<T>` and `S1` is required
+// to be `Sequence<T, 0>`.
+
+template <std::size_t Size>
+struct make_seq {
+  template <typename S0, typename S1>
+  using apply = typename make_seq_cat<
+      typename make_seq<Size / 2>::template apply<S0, S1>,
+      typename make_seq<Size / 2>::template apply<S0, S1>,
+      typename make_seq<Size % 2>::template apply<S0, S1>>::type;
+};
+template <>
+struct make_seq<1> {
+  template <typename S0, typename S1>
+  using apply = S1;
+};
+template <>
+struct make_seq<0> {
+  template <typename S0, typename S1>
+  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 <class T, T... Ints>
 struct integer_sequence {
   using value_type = T;
@@ -116,22 +163,105 @@ struct integer_sequence {
 };
 
 template <std::size_t... Ints>
-using index_sequence = folly::integer_sequence<std::size_t, Ints...>;
+using index_sequence = integer_sequence<std::size_t, Ints...>;
 
-namespace detail {
-template <std::size_t N, std::size_t... Ints>
-struct make_index_sequence
-    : detail::make_index_sequence<N - 1, N - 1, Ints...> {};
+#endif
 
-template <std::size_t... Ints>
-struct make_index_sequence<0, Ints...> : folly::index_sequence<Ints...> {};
-}
+#if FOLLY_HAS_BUILTIN(__make_integer_seq) || _MSC_FULL_VER >= 190023918
+
+template <typename T, std::size_t Size>
+using make_integer_sequence = __make_integer_seq<integer_sequence, T, Size>;
 
-template <std::size_t N>
-using make_index_sequence = detail::make_index_sequence<N>;
+#else
+
+template <typename T, std::size_t Size>
+using make_integer_sequence = typename utility_detail::make_seq<
+    Size>::template apply<integer_sequence<T>, integer_sequence<T, 0>>;
 
 #endif
 
+template <std::size_t Size>
+using make_index_sequence = make_integer_sequence<std::size_t, Size>;
+
+/**
+ *  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 <class>
+struct in_place_type_tag {};
+template <std::size_t>
+struct in_place_index_tag {};
+
+using in_place_t = in_place_tag (&)(in_place_tag);
+template <class T>
+using in_place_type_t = in_place_type_tag<T> (&)(in_place_type_tag<T>);
+template <std::size_t I>
+using in_place_index_t = in_place_index_tag<I> (&)(in_place_index_tag<I>);
+
+inline in_place_tag in_place(in_place_tag = {}) {
+  return {};
+}
+template <class T>
+inline in_place_type_tag<T> in_place_type(in_place_type_tag<T> = {}) {
+  return {};
+}
+template <std::size_t I>
+inline in_place_index_tag<I> in_place_index(in_place_index_tag<I> = {}) {
+  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<int>);
+ *
+ *    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<int>);
+ *
+ *    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.
  *
@@ -158,4 +288,33 @@ struct Identity {
     return static_cast<T&&>(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<bool, B>.
+ */
+template <bool B>
+using Bool = std::integral_constant<bool, B>;
+
+} // namespace folly