1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 
6 #pragma once
7 
8 #include <utility>
9 #include <type_traits>
10 
11 namespace folly {
12 
13 /**
14  *  Backports from C++17 of:
15  *    std::in_place_t
16  *    std::in_place_type_t
17  *    std::in_place_index_t
18  *    std::in_place
19  *    std::in_place_type
20  *    std::in_place_index
21  */
22 
23 struct in_place_tag {};
24 template <class>
25 struct in_place_type_tag {};
26 template <std::size_t>
27 struct in_place_index_tag {};
28 
29 using in_place_t = in_place_tag (&)(in_place_tag);
30 template <class T>
31 using in_place_type_t = in_place_type_tag<T> (&)(in_place_type_tag<T>);
32 template <std::size_t I>
33 using in_place_index_t = in_place_index_tag<I> (&)(in_place_index_tag<I>);
34 
35 inline in_place_tag in_place(in_place_tag = {}) {
36   return {};
37 }
38 template <class T>
39 inline in_place_type_tag<T> in_place_type(in_place_type_tag<T> = {}) {
40   return {};
41 }
42 template <std::size_t I>
43 inline in_place_index_tag<I> in_place_index(in_place_index_tag<I> = {}) {
44   return {};
45 }
46 
47 template <class T, class U = T>
exchange(T & obj,U && new_value)48 T exchange(T& obj, U&& new_value) {
49   T old_value = std::move(obj);
50   obj = std::forward<U>(new_value);
51   return old_value;
52 }
53 
54 namespace utility_detail {
55 template <typename...>
56 struct make_seq_cat;
57 template <
58     template <typename T, T...> class S,
59     typename T,
60     T... Ta,
61     T... Tb,
62     T... Tc>
63 struct make_seq_cat<S<T, Ta...>, S<T, Tb...>, S<T, Tc...>> {
64   using type =
65       S<T,
66         Ta...,
67         (sizeof...(Ta) + Tb)...,
68         (sizeof...(Ta) + sizeof...(Tb) + Tc)...>;
69 };
70 
71 // Not parameterizing by `template <typename T, T...> class, typename` because
72 // clang precisely v4.0 fails to compile that. Note that clang v3.9 and v5.0
73 // handle that code correctly.
74 //
75 // For this to work, `S0` is required to be `Sequence<T>` and `S1` is required
76 // to be `Sequence<T, 0>`.
77 
78 template <std::size_t Size>
79 struct make_seq {
80   template <typename S0, typename S1>
81   using apply = typename make_seq_cat<
82       typename make_seq<Size / 2>::template apply<S0, S1>,
83       typename make_seq<Size / 2>::template apply<S0, S1>,
84       typename make_seq<Size % 2>::template apply<S0, S1>>::type;
85 };
86 template <>
87 struct make_seq<1> {
88   template <typename S0, typename S1>
89   using apply = S1;
90 };
91 template <>
92 struct make_seq<0> {
93   template <typename S0, typename S1>
94   using apply = S0;
95 };
96 } // namespace utility_detail
97 
98 // TODO: Remove after upgrading to C++14 baseline
99 
100 template <class T, T... Ints>
101 struct integer_sequence {
102   using value_type = T;
103 
104   static constexpr std::size_t size() noexcept {
105     return sizeof...(Ints);
106   }
107 };
108 
109 template <std::size_t... Ints>
110 using index_sequence = integer_sequence<std::size_t, Ints...>;
111 
112 template <typename T, std::size_t Size>
113 using make_integer_sequence = typename utility_detail::make_seq<
114     Size>::template apply<integer_sequence<T>, integer_sequence<T, 0>>;
115 
116 template <std::size_t Size>
117 using make_index_sequence = make_integer_sequence<std::size_t, Size>;
118 template <class... T>
119 using index_sequence_for = make_index_sequence<sizeof...(T)>;
120 
121 /**
122  * A simple helper for getting a constant reference to an object.
123  *
124  * Example:
125  *
126  *   std::vector<int> v{1,2,3};
127  *   // The following two lines are equivalent:
128  *   auto a = const_cast<const std::vector<int>&>(v).begin();
129  *   auto b = folly::as_const(v).begin();
130  *
131  * Like C++17's std::as_const. See http://wg21.link/p0007
132  */
133 template <class T>
134 T const& as_const(T& t) noexcept {
135   return t;
136 }
137 
138 template <class T>
139 void as_const(T const&&) = delete;
140 
141 } // namespace folly
142